Monday, 21 November 2022

School Fees Management System in PHP MySQL with Source Code

School Fees Management System in PHP MySQL with Source Code

Today, the education sector has become highly digitized. Students and parents expect seamless processes across all digital touchpoints, anytime, anywhere. In this scenario, schools need to come up with cost-effective solutions that not only keep their operating costs in check but also improve the experience of students and parents. Education institutes have multiple tuition fee collection channels such as offline cash payments, online payments through payment gateway, e-wallets and so on. However, this fragmented system creates a headache for school as well as parents whenever a student get fees details. On the other hand, an efficient school fees management system can help you collect monthly fees from students conveniently. Moreover, it will also save you time and money by automating fee collection and tracking procedures at every step. So In this blog post, we will discuss - PHP based School Management System.

Why Should You Use an Efficient School Fees Management System?


Schools find it difficult to manage fees across multiple channels, especially when students are attending courses from different institutes. Also, they lack a robust system that can help them track payments, understand cash flow, and manage fees across different channels. This can lead to inefficient fee management, which can affect your business in many ways. For instance, you may have difficulty in tracking and collecting school fees from students belonging to different channels. This can also lead to more manual errors and a lower level of customer satisfaction.

How Can an Efficient School Fees Management System Help?


A well-crafted school fees management system can help you collect fees from students at different channels. It can also help you manage fees and payments at all stages. You can use this system to collect payments from your existing students. You can also use the same platform to enroll new students and collect the fees on a monthly basis. Investing in a robust system will help you improve the overall experience of your fees collection and manage fees data. This will also help you in gathering valuable insight from the data that the system generates. You can also use this system to generate reports, and get insights about the number of students registered with your school, the total amount collected, and so on. This will help you understand your business performance, and take necessary steps for improvement.





PHP Based School Fee Management System


Fees management is yet another important role of the school management system. This is the one place where you can track the student or course fees details. If you are managing your fees data through a web application, you can connect it with your school management software to access the data. The Fees management will help you track the fees collection by different date filter. This will let you know where you need to focus on and how many fees collection has be increased. You can also generate reports based on the data gathered by the fees management module. This will let you know the total amount of fees.





Key Features of an Efficient School Fees Payment Platform


To ensure that your school or institution student get a seamless experience, you need to ensure that your school fees payment platform is efficient. Some of the key features of an efficient school fees payment platform include - An easy to use interface that allows users to collect fees in simple easy steps with few click. A robust system with safety and security features to protect your fees data from cyber attacks. A detailed user dashboard that allows users to manage their account and payment history.

  1. Multi User Fees Management System
  2. Single Login for Master and Sub User
  3. Fully Dynamic Fees Management System
  4. Admin can Add, Update, Disable and Enable Sub User
  5. Admin can Add, Update, Disable and Enable Academic Year Data
  6. Admin can Add, Update, Disable and Enable Course Data
  7. Admin can Add, Update Student Master Data
  8. Admin can define Student Standard and then after update, disable and enable that data
  9. Admin can Add, Update, Disable and Enable Fees Master Data
  10. Admin or Sub User can collect fees
  11. Fees Receipts can be open in PDF format also
  12. Admin or Sub User can filter fees collection data and get data of how many student has paid and how many student are still pending of fees

Web Technology used for Fees Management System


For Develop Web based Fees Management, we have use following open source web technology for build School Fees Management System.

Server Side


  • PHP
  • MySQL

Client Side


  • Vanill JavaScript
  • jQuery
  • Ajax
  • Bootstrap 5
  • jQuery DataTables




Database Structure of School Fees Management System


Below you can find database structure of PHP based School Management System.


Database Structure of School Fees Management System


Conclusion


The education sector is highly competitive, and businesses have to keep up with the latest technology to stay relevant. With growing use of internet and mobile devices, customers expect seamless experiences across all digital touchpoints. A school management system can help you come up with cost-effective solutions that not only keep your operating costs in check but also improve the experience of students and parents. If you are looking for an efficient school fees management system, you can consider PHP-based school fee management systems. These systems offer robust features, and you can use them to manage fees and payments at different stages.

Note - Source code will be added under this page after every publishing of video tutorial of this Fees Management System.





Rust vs. Go: Concurrency in Modern Programming Languages

Rust vs. Go: Concurrency in modern programming languages

The field of programming languages is a vast one. There are seemingly countless choices you could make when trying to write software. With that in mind, it might be interesting to look at two popular programming languages: Go and Rust. Both are relatively young, and they both aim to solve very different problems at the same time. Many say that programming languages were not invented when Go was developed, and vice versa for Rust.

Go and Rust has recently received much attention in the programming language community. Both languages are statically typed and compiled, but several other differences make them unique. This article explores the concurrency features of both Go and Rust, comparing their approaches to handling concurrent tasks with shared data.

What is concurrency?


Concurrency is the use of multiple processes or threads to perform a task. It is sometimes used interchangeably with parallel processing, but it refers to the simultaneous execution of various processes or tasks.

Concurrency in current programming languages can increase performance by allowing multiple threads to run simultaneously to achieve more work in a shorter time. Concurrency also allows for better scalability by allowing multiple processes or threads to run simultaneously on different computers.

Concurrency is a huge part of modern programming languages. It allows you to perform multiple tasks simultaneously, create data processing pipelines and even solve problems that would be impossible to solve on single-threaded systems. Like CPU architecture, programs written in concurrent languages are often highly optimized for parallelism and perform better than those written in single-threaded languages.

Rust and Go in concurrency

Rust and Go are two programming languages comparable in many ways. However, Rust has a few features that make it unique from Go.

The first feature is Rust's ability to nest functions. Nesting functions allow for easier code organization and readability because it allows you to specify how a function should be called within another function.

The second feature that makes Rust different from Go is its support for concurrency. Concurrency allows multiple processes to execute simultaneously on the same computer or network connection, which can significantly increase the speed of your programs by avoiding waiting periods between operations.

A key difference between Rust and other languages is that Rust does not allow exceptions but instead uses unchecked accesses for all code paths. This means there are no "try" statements; instead, you should always assume that your program will crash at any moment during execution.

Rust also has a swift compiler known as LLVM, which allows for extremely fast compilation times (currently around 10x faster than C).

Benchmarking & Comparison


Go is a server-side programming language that Google developed. It's often compared to Rust, a systems programming language used to build low-level applications and libraries. This article compares the two languages and identifies some of their similarities as well as differences.

Go is similar to Rust in that they both are statically typed languages with a strong emphasis on correctness. When we compare concurrency performance, we realize that they both provide garbage collection, which means they don't have to worry about memory management during runtime as many other languages do.





However, with the benchmarking conditions, several differences between these two languages should be considered before deciding which one to use for your project. Go is much more lightweight than Rust—designed for single-core CPUs—and its concurrency model allows it to scale up easily as needed.

Comparing go vs. Rust for web development, Rust can handle concurrent operations without any issues or overhead (as long as all threads involved in an operation use the same data structures). But this type of concurrency is optional for most web applications.

Benchmark observations


Go has garbage collection, which Rust does not. This means there is no need to worry about freeing up unused memory -- the garbage collector will automatically do so when it runs out of space. But it also means that you can't use pointers in Go, so each variable must be declared separately (which can make programs more difficult to read).

Rust supports both static and dynamic polymorphism through type inference. In Go, you have to declare types for your variables explicitly. The difference between these two approaches can lead to subtle bugs when working with third-party libraries written in other languages and using similar names for their functions and variables through benchmark web server frameworks.

Conclusion


Rust and Go are two high-quality, modern languages designed to make concurrent programming easier to manage and more reliable. Rust and Go are both excellent languages with an enormous number of developer-friendly features. They're also built by communities with a strong sense of value, and they prioritize the needs of their users.

However, Rust has a particular focus on safety, whereas Go has a certain focus on simplicity. The former may be more appropriate for serious software development efforts where expertise and input from expert clients are expected. In contrast, the latter may be better suited for quick, simple development projects or where strict adherence to the convention is necessary.

However, their key advantages differ depending on what application you want to write. Suppose your primary focus is writing a server implementing services (with a heavy emphasis on performance). In that case, Go is your language of choice due to its lightweight concurrency paradigms and ability to quickly build a modular foundation for your application. Rust may be a better option if reliability is your primary goal; it has some particularly fascinating guarantees about memory safety that greatly reduce the risk of program errors in production environments.

Identify Deadlocks Using Graphical Deadlock Chain Event in SQL Server Profiler

Identify Deadlocks Using Graphical Deadlock Chain Event in SQL Server Profiler

In SQL Server, a deadlock occurs when two or more processes attempt to acquire exclusive locks on resources in such a way that a circular chain is formed, where each process is waiting for another process to release the lock it holds. Deadlocks can be resolved by having one of the processes involved in the deadlock abort, so that its locks are released and the other process can continue.

When a deadlock occurs, SQL Server automatically detects it and ends one of the user processes (the "victim"), allowing the other process to complete. This event is then recorded in the SQL Server error log.

To identify which process was aborted during a deadlock, you can use the Graphical Deadlock Chain Event in SQL Server Profiler. This event will show you the processes involved in the deadlock, as well as which process was aborted.

To use the Graphical Deadlock Chain Event in SQL Server Profiler:


1. Start SQL Server Profiler and connect to the instance of SQL Server where the deadlock occurred.

2. Create a new trace or use an existing trace that includes the events you want to capture. For more information, see designing a Trace (SQL Server Profiler).

3. In the Events Selection tab, select the checkbox for the Graphical Deadlock Chain event under the Locks category.

4. Run the trace.

When a deadlock occurs, the Graphical Deadlock Chain event will be recorded in the trace. This event will show you the processes involved in the deadlock, as well as which process was aborted.

5. To view the details of the event, double-click it in the trace results.

6. In the Event Properties dialog box, click the Deadlock tab.

7. The details of the deadlock will be displayed in a graphical format, showing which processes were involved and which process was aborted.

8. To save the deadlock information to a file, click Save As and choose a location for the file.

When troubleshooting deadlocks, it is important to remember that SQL Server automatically detects and resolves them. In most cases, there is no need to take any further action. However, if you are seeing frequent deadlocks, or if they are causing performance problems, you may need to investigate further and take steps to prevent them from occurring.





For more information, see Deadlocks (SQL Server).

When a deadlock occurs, SQL Server automatically detects it and ends one of the user processes (the "victim"), allowing the other process to complete. This event is then recorded in the SQL Server error log.

To identify which process was aborted during a deadlock, you can use the Graphical Deadlock Chain Event in SQL Server Profiler. This event will show you the processes involved in the deadlock, as well as which process was aborted.

To use the Graphical Deadlock Chain Event in SQL Server Profiler:


1. Start SQL Server Profiler and connect to the instance of SQL Server where the deadlock occurred.

2. Create a new trace or use an existing trace that includes the events you want to capture. For more information, see designing a Trace (SQL Server Profiler).

3. In the Events Selection tab, select the checkbox for the Graphical Deadlock Chain event under the Locks category.

4. Run the trace.

When a deadlock occurs, the Graphical Deadlock Chain event will be recorded in the trace. This event will show you the processes involved in the deadlock, as well as which process was aborted.

5. To view the details of the event, double-click it in the trace results.

6. In the Event Properties dialog box, click the Deadlock tab.

7. The details of the deadlock will be displayed in a graphical format, showing which processes were involved and which process was aborted.

8. To save the deadlock information to a file, click Save As and choose a location for the file.

Conclusion:


When troubleshooting deadlocks, it is important to remember that SQL Server automatically detects and resolves them. In most cases, there is no need to take any further action. However, if you are seeing frequent deadlocks, or if they are causing performance problems, you may need to investigate further and take steps to prevent them from occurring.

Wildcard SSL Certificate: How Does it Work?

Wildcard SSL Certificate: How Does it Work?

In 2020, a report said that one million Secure Sockets Layer (SSL) certificates were being issued every day. This reflects the increasing preference of Internet users and search engines for websites that encrypt and protect the communication between a website and a visitor's browser.

Having an SSL certificate for your website is not merely an option. It has become one of the important components of protecting your site and ensuring all the confidential information during data transmission between the client, and central server stays encrypted and served through an HTTPS connection.

That being said, figuring out which SSL certificate to install on your website can be tricky, given that there are different types of certificates available at your convenience. If you have multiple subdomains, using a 'Wildcard' SSL certificate is the most obvious choice to make, as it secures all the subdomains with one single certificate. So, instead of buying one for each, you just have to buy one.

Let us explain what Wildcard SSL certificates are.

What are Wildcard SSL Certificates?


A Wildcard SSL certificate can be defined as an SSL certificate that has the power to secure your main domain along with all its subdomains. It means that instead of using individual SSL certificates for securing the associated subdomains, with one certificate, you can secure your primary domain and all the subdomains under that domain.

As the certificate offers to secure an unlimited number of subdomains with just a single certificate, it works with any subdomain of the base domain name it is made for. Let us give you an example:

The name of your domain is 'yourwebsite.com.' With a Wildcard SSL certificate, you can also protect 'subsite.yourwebsite.com' and 'subsite2.yourwebsite.com.' So, the certificate for your domain www.yourwebsite.com will also secure the following subdomains:

  • yourwebsite.com
  • news.yourwebsite.com
  • blog.yourwebsite.com
  • shop.yourwebsite.com

The domain name field of the wildcard SSL certificate is placed with a Wildcard character called asterisk (*) as a placeholder. It is responsible for securing multiple subdomains, the base domain, and the primary domain itself. For instance, with a Wildcard SSL certificate, you can secure your primary domain *.yourwebsite.com and accompanying subdomains like mail.yourwebsite.com, blog.yourwebsite.com, www.yourwebsite.com, and many more.





Some of the key features of this certificate are:

  • No set limit on the number of subdomains to cover. All the primary domain's first-level subdomains are covered. Website owners can also add more subdomains during the certificate's validity period.
  • Offers NIST and CAB Forum standard 256-bit data encryption.
  • Exhibits compatibility with all modern web browsers and devices.

So, when can one get these certificates? Let us talk about that:

When can you Use a Wildcard SSL Certificate?


Some common scenarios where you can use a wildcard SSL certificate are:

  • A web developer using subdomains for testing environments.
  • A business using separate subdomains for various aspects and entities of the organization, such as blog, shop, etc.
  • A user who needs a single top-level domain but plans to use multiple subdomains later.

Now the question is how the certificate operates. So, let us answer that for you:

How do the Wildcard SSL Certificates Secure all Subdomains?


Just like single-name SSL certificates, Wildcard certificates encrypt the data with the help of a set of keys. It consists of a public key stored on the digital certificate and a private key stored on your website's server. However, with a Wildcard cert, you can copy the private key and upload it to an unlimited number of servers to host the primary domain and all its subdomains.

After the installation of the certificate, all the traffic between your end user's browser and all the connecting web servers will be subjected to encryption. It means when a hacker makes an attempt to intercept data between a visitor's browser and your site's server, it will be unreadable to them. All they will see is a series of vague characters, which is an encrypted code. It is because only the server with the private key can decrypt the message.

One of the primary advantages of using Wildcard SSL is that there is a good scope of saving money and time. Moreover, it offers more flexibility to the users. Purchasing Wildcard SSL certificates if you own a single domain with numerous first-level subdomains (or are planning to add them in the future will help you secure all of them at once.

One of the best benefits of purchasing a Wildcard SSL certificate is to protect each chosen domain name subdomain without needing any extra setup or purchases when another subdomain is created.

Closing Thoughts


Almost all types of devices and web browsers, including desktop computers and mobiles, support Wildcard SSL certificates. Apart from this, the Wildcard SSL certificate comes with an unlimited re-issuance and an unlimited server license policy. It means you can re-issue it as often as possible and protect your site on as many servers as you deem necessary.

When you use a Wildcard SSL certificate, you can secure the data of your visitors on not just your primary domain but also on related subdomains. This will make sure you can keep your business running safe online while keeping your certificate management and expenses low.

While many reputable Certificate Authorities (CA) offer these certificates, they are expensive. That being said, there are various pocket-friendly options from where you can avail of cheap Wildcard SSL certificates. These certificates are structurally similar to other certificates, as they provide the same level of security but are designated by a CA policy identifier. It helps in featuring the company's domain name in the certificate. So get one for your site today!

Saturday, 3 September 2022

Real-time Laravel Ratchet Websocket Chat Application


In this tutorial, we will discuss How to make Real Time Chat Application in Laravel 9 Framework by using Ratchet Web Socket Library. In this tutorial, we will build Real-time Chat Application in which we users can do real time conversation via this Chat Application. So if you are searching tutorial on Real-time Laravel Chat Application with Web Socket, then you have land on the right place because here, we will build Real-time Chat Application using Laravel and Ratchet Web Socket.

Under this tutorial, we will not use any paid messaging service but for send and receive chat message in real-time here we will use Ratchet Web Socket Library with Laravel 9 framework. So at backend we will use Laravel 9 framework, Ratchet Websocket Library and MySQL database and at front-end we will use Vanilla JavaScript and Bootstrap 5 Library. So this web technology we will use for build real time chat application in Laravel framework by using Ratchet Websocket Library. In the current time, in every web application that requires real time communication so for implement real time communication, here we have use Ratchet Websocket Library with Laravel framework and by using this Library we can implement real time communication of data and build chat application.

What is Ratchet WebSocket?


Ratchet WebSocket is PHP Library which will provides tools to developer for create real-time web application in which client and server are connected in bi-directional, so client directly send message to other client via this Web Socket. It will create tunnel between two or multiple client and they can sed and receive message in real-time. This Ratchet WebSocket will make persistent connection from browser to the server and once the connection has been established then that connection will be open until client or server decide to close it. So in open connection mode, the client send message to other client.

 

Web Technology used for Build Laravel Chat Application


Server Side


  • Laravel 9 Framework
  • MySQL Database
  • Ratchet WebSocket
  • Composer

Client Side


  • Vanilla JavaScript
  • Bootstrap 5 Library

Real-time Laravel Ratchet Websocket Chat Application

Architecture of Laravel Ratchet Web Socket Chat Application


In Below image you can find the basic architecture of Laravel Ratchet Web Socket Chat Application.


Real-time Laravel Ratchet Websocket Chat Application


Features of Laravel Ratchet WebSocket Chat Application


Below you can find different feature of Real-time Laravel Ratchet WebSocket Chat Application.

  1. Chat Application Registration
  2. Chat Application Login
  3. Manage Profile
  4. List Unconnected User with Send Chat Request Button
  5. Search User and List with Send Chat Request Button
  6. Send Chat Request to User
  7. Display User Chat Request in Notification Area
  8. Approve or Reject User Chat Request in Notification Area
  9. Display Approve Chat Request User in Connected User Area
  10. List Approve Chat Request User in Connected User Area
  11. Make Chat Area with Send Chat Button
  12. Reset Chat Area
  13. Load Chat history when User has select another user to Chat
  14. Send Chat Message to One to One User
  15. Whatsup like Message Send Read status using icon
  16. Display number of unread message notification
  17. Display User is Online or Not using icon
  18. Display Whatsup like User Last Seen Detail

Below you can find step by step process for build Laravel Ratchet WebSocket Chat Application.

  1. Install Laravel 9 Application
  2. Make Database Connection
  3. Create Model Class
  4. Download & Install Ratchet WebSocket Library
  5. Create Controller
  6. Create View Blades Files
  7. Set Route of Controller Method
  8. Run Laravel 9 Application

Step 1 - Install Laravel 9 Application


In first step, we want to download fresh copy of Laravel 9 framework. So we have goes to command prompt and goes to directory where we can run our PHP code. So after goes into that directory, we have to run following command which will make custom_login directory and under that directory it will download and install Laravel 9 Application.


composer create-project laravel/laravel custom_demo


Step 2 - Make Database Connection


Once we have download and install Laravel 9 Application, now we first we want to make MySQL database connection. So for this, we have to open .env file and under this file, we have to define MySQL database configuration. So after define this configuration details it will make MySQL database connection with Laravel 9 Application.

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=testing
DB_USERNAME=root
DB_PASSWORD=


So after make MySQL Database connection, now we want to make user table under mysql database. So here we will use default user table of Laravel 9 Application. So here user table defination has been stored under database/migrations directory. So for create table in MySQL database from Laravel Application, we have to run following command. So this command will create users table under MySQL database from this Laravel 9 Application.


php artisan migrate


Now we want to add four table column in users table, so for this, in command prompt we have to following command.


php artisan make:migration update_users_table --table=users

So this command has been create alter user table migration file and under this file we have to define column details which you can seen below.

database/migrations/2022_09_06_111722_update_users_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('token');
            $table->integer('connection_id');
            $table->enum('user_status', ['Offline', 'Online']);
            $table->string('user_image');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('token');
            $table->dropColumn('connection_id');
            $table->dropColumn('user_status');
            $table->dropColumn('user_image');
        });
    }
};



Next We need to create chats table, so for this, we have to goest to command prompt and run following command.


php artisan make:model Chat -m


So this command will create migration file and Chat Model Class file. First we have to open Chats table migration file and under this file, we have to define table column defination.

database/migrations/2022_09_06_112831_create_chats_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('chats', function (Blueprint $table) {
            $table->id();
            $table->integer('from_user_id');
            $table->integer('to_user_id');
            $table->string('chat_message');
            $table->string('message_status');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('chats');
    }
};



And in MySQL database part, we have to create chat_requests table. So for this, we have goes to command prompt and run following command.


php artisan make:model Chat_request -m


This command will make create chat_requests table migration file and Chat_request.php Model class file. Here first we have to open create chat_requests table migration file and under this file, we have to define table column details which you can seen below.


<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('chat_requests', function (Blueprint $table) {
            $table->id();
            $table->integer('from_user_id');
            $table->integer('to_user_id');
            $table->enum('status', ['Pending', 'Approve', 'Reject']);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('chat_requests');
    }
};



Now we want to create two new table and alter existing table, so for this we have goes to command prompt and run following command.


php artisan migrate


So this command will create chats table and chat_requests table and add four table column in users table from this laravel application.

Step 3 - Create Model Class


Under this Laravel Chat Application we will use Model class for database operation. Model class file will be created when we have create MySQL table migration file. Under this tutorial, we have create User.php, Chat.php and Chat_request.php model class file. So under this file, we have to define MySQL table column details, which you can seen below.

app/Models/User.php

<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'token',
        'connection_id',
        'user_status',
        'user_image'
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}



app/Models/Chat.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Chat extends Model
{
    use HasFactory;

    protected $fillable = ['from_user_id', 'to_user_id', 'chat_message', 'message_status'];
}



app/Models/Chat_request.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Chat_request extends Model
{
    use HasFactory;

    protected $fillable = ['from_user_id', 'to_user_id', 'status'];
}



Step 4 - Download & Install Ratchet WebSocket Library


In this Laravel Chat Application, we have use Ratchet WebSocket Library for make Real-time Chat Application. So in this part, we will download and install Ratchet WebSocket Library. So for download Ratchet WebSocket Library. We have goes to command prompt and run following command.


composer require cboden/ratchet


This command will download and install Ratchet Websocket Library under vendor. After this we want to create WebSocket Server file. So for this, we have to goes to command prompt and run following file.


php artisan make:command WebSocketServer --command=websocket:init


After run above command, so it will create Websocket Server file in app/Console/Commands/WebSocketServer.php under this directory. So we have to open this file, and under this file we have to define following code for make Ratchet WebSocket server.

app/Console/Commands/WebSocketServer.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

use Ratchet\Server\IoServer;

use Ratchet\Http\HttpServer;

use Ratchet\WebSocket\WsServer;

use React\EventLoop\Factory;

use App\Http\Controllers\SocketController;

class WebSocketServer extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'websocket:init';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        //return 0;

        $server = IoServer::factory(
            new HttpServer(
                new WsServer(
                    new SocketController()
                )
            ),
            8090
        );

        $server->run();
    }
}



So this WebSocket Server will be run on the 8090 port number. Next we have to create Socket Controller file. So for this, we have goes to command prompt and run following command.


php artisan make:controller SocketController


So this command will make SocketController.php controller file under app/Http/Controllers directory, and you can find source code of this controller file under this Create Controller Steps.





Step 5 - Create Controller


Under this Laravel Ratchet Chat Application, first we want to make controller for Login and Registration page. So for create Controller for Chat Application Login and Registration page, we have goes to command prompt and run following command.


php artisan make:controller SampleController


This command will make SampleController.php file under app/Http/Controllers directory. So we have to open this directory and write following code for make Login Registration and Logout feature for this Real-time Laravel Ratchet WebSocket Chat Application.

app/Http/Controllers/SampleController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Hash;
use Session;
use App\Models\User;
use Illuminate\Support\Facades\Auth;

class SampleController extends Controller
{
    function index()
    {
        return view('login');
    }

    function registration()
    {
        return view('registration');
    }

    function validate_registration(Request $request)
    {
        $request->validate([
            'name'         =>   'required',
            'email'        =>   'required|email|unique:users',
            'password'     =>   'required|min:6'
        ]);

        $data = $request->all();

        User::create([
            'name'  =>  $data['name'],
            'email' =>  $data['email'],
            'password' => Hash::make($data['password'])
        ]);

        return redirect('login')->with('success', 'Registration Completed, now you can login');
    }

    function validate_login(Request $request)
    {
        $request->validate([
            'email' =>  'required',
            'password'  =>  'required'
        ]);

        $credentials = $request->only('email', 'password');

        if(Auth::attempt($credentials))
        {
            $token = md5(uniqid());

            User::where('id', Auth::id())->update([ 'token' => $token ]);

            return redirect('dashboard');
        }

        return redirect('login')->with('success', 'Login details are not valid');
    }

    function dashboard()
    {
        if(Auth::check())
        {
            return view('dashboard');
        }

        return redirect('login')->with('success', 'you are not allowed to access');
    }

    function logout()
    {
        Session::flush();

        Auth::logout();

        return Redirect('login');
    }

    public function profile()
    {
        if(Auth::check())
        {
            $data = User::where('id', Auth::id())->get();

            return view('profile', compact('data'));
        }

        return redirect("login")->with('success', 'you are not allowed to access');
    }

    public function profile_validation(Request $request)
    {
        $request->validate([
            'name'      =>  'required',
            'email'     =>  'required|email',
            'user_image'   =>   'image|mimes:jpg,png,jpeg|max:2048|dimensions:min_width=100,min_height=100,max_width=1000,max_height=1000'
        ]);

        $user_image = $request->hidden_user_image;

        if($request->user_image != '')
        {
            $user_image = time() . '.' . $request->user_image->getClientOriginalExtension();

            $request->user_image->move(public_path('images'), $user_image);
        }

        $user = User::find(Auth::id());

        $user->name = $request->name;

        $user->email = $request->email;

        if($request->password != '')
        {
            $user->password = Hash::make($request->password);
        }

        $user->user_image = $user_image;

        $user->save();

        return redirect('profile')->with('success', 'Profile Details Updated');
    }
}



app/Http/Controllers/SocketController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Ratchet\MessageComponentInterface;

use Ratchet\ConnectionInterface;

use App\Models\User;

use App\Models\Chat;

use App\Models\Chat_request;

use Auth;

class SocketController extends Controller implements MessageComponentInterface
{
    protected $clients;

    public function __construct()
    {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn)
    {
        $this->clients->attach($conn);

        $querystring = $conn->httpRequest->getUri()->getQuery();

        parse_str($querystring, $queryarray);

        if(isset($queryarray['token']))
        {
            User::where('token', $queryarray['token'])->update([ 'connection_id' => $conn->resourceId, 'user_status' => 'Online' ]);

            $user_id = User::select('id')->where('token', $queryarray['token'])->get();

            $data['id'] = $user_id[0]->id;

            $data['status'] = 'Online';

            foreach($this->clients as $client)
            {
                if($client->resourceId != $conn->resourceId)
                {
                    $client->send(json_encode($data));
                }
            }

        }


    }

    public function onMessage(ConnectionInterface $conn, $msg)
    {
        if(preg_match('~[^\x20-\x7E\t\r\n]~', $msg) > 0)
        {
            //receiver image in binary string message

            $image_name = time() . '.jpg';

            file_put_contents(public_path('images/') . $image_name, $msg);

            $send_data['image_link'] = $image_name;

            foreach($this->clients as $client)
            {
                if($client->resourceId == $conn->resourceId)
                {
                    $client->send(json_encode($send_data));
                }
            }
        }


        $data = json_decode($msg);

        if(isset($data->type))
        {
            if($data->type == 'request_load_unconnected_user')
            {
                $user_data = User::select('id', 'name', 'user_status', 'user_image')
                                    ->where('id', '!=', $data->from_user_id)
                                    ->orderBy('name', 'ASC')
                                    ->get();

                $sub_data = array();

                foreach($user_data as $row)
                {
                    $sub_data[] = array(
                        'name'      =>  $row['name'],
                        'id'        =>   $row['id'],
                        'status'    =>  $row['user_status'],
                        'user_image'=>  $row['user_image']
                    );
                }

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                $send_data['data'] = $sub_data;

                $send_data['response_load_unconnected_user'] = true;

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $client->send(json_encode($send_data));
                    }
                }
            }

            if($data->type == 'request_search_user')
            {
                $user_data = User::select('id', 'name', 'user_status', 'user_image')
                                    ->where('id', '!=', $data->from_user_id)
                                    ->where('name', 'like', '%'.$data->search_query.'%')
                                    ->orderBy('name', 'ASC')
                                    ->get();

                $sub_data = array();

                foreach($user_data as $row)
                {

                    $chat_request = Chat_request::select('id')
                                    ->where(function($query) use ($data, $row){
                                        $query->where('from_user_id', $data->from_user_id)->where('to_user_id', $row->id);
                                    })
                                    ->orWhere(function($query) use ($data, $row){
                                        $query->where('from_user_id', $row->id)->where('to_user_id', $data->from_user_id);
                                    })->get();

                    /*
                    SELECT id FROM chat_request 
                    WHERE (from_user_id = $data->from_user_id AND to_user_id = $row->id) 
                    OR (from_user_id = $row->id AND to_user_id = $data->from_user_id)
                    */

                    if($chat_request->count() == 0)
                    {
                        $sub_data[] = array(
                            'name'  =>  $row['name'],
                            'id'    =>  $row['id'],
                            'status'=>  $row['user_status'],
                            'user_image' => $row['user_image']
                        );
                    }

                    
                }

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                $send_data['data'] = $sub_data;

                $send_data['response_search_user'] = true;

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $client->send(json_encode($send_data));
                    }
                }
            }

            if($data->type == 'request_chat_user')
            {
                $chat_request = new Chat_request;

                $chat_request->from_user_id = $data->from_user_id;

                $chat_request->to_user_id = $data->to_user_id;

                $chat_request->status = 'Pending';

                $chat_request->save();

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                $receiver_connection_id = User::select('connection_id')->where('id', $data->to_user_id)->get();

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $send_data['response_from_user_chat_request'] = true;

                        $client->send(json_encode($send_data));
                    }

                    if($client->resourceId == $receiver_connection_id[0]->connection_id)
                    {
                        $send_data['user_id'] = $data->to_user_id;

                        $send_data['response_to_user_chat_request'] = true;

                        $client->send(json_encode($send_data));
                    }
                }
            }

            if($data->type == 'request_load_unread_notification')
            {
                $notification_data = Chat_request::select('id', 'from_user_id', 'to_user_id', 'status')
                                        ->where('status', '!=', 'Approve')
                                        ->where(function($query) use ($data){
                                            $query->where('from_user_id', $data->user_id)->orWhere('to_user_id', $data->user_id);
                                        })->orderBy('id', 'ASC')->get();

                /*
                SELECT id, from_user_id, to_user_id, status FROM chat_requests
                WHERE status != 'Approve'
                AND (from_user_id = $data->user_id OR to_user_id = $data->user_id)
                ORDER BY id ASC
                */

                $sub_data = array();

                foreach($notification_data as $row)
                {
                    $user_id = '';

                    $notification_type = '';

                    if($row->from_user_id == $data->user_id)
                    {
                        $user_id = $row->to_user_id;

                        $notification_type = 'Send Request';
                    }
                    else
                    {
                        $user_id = $row->from_user_id;

                        $notification_type = 'Receive Request';
                    }

                    $user_data = User::select('name', 'user_image')->where('id', $user_id)->first();

                    $sub_data[] = array(
                        'id'            =>  $row->id,
                        'from_user_id'  =>  $row->from_user_id,
                        'to_user_id'    =>  $row->to_user_id,
                        'name'          =>  $user_data->name,
                        'notification_type' =>  $notification_type,
                        'status'           =>   $row->status,
                        'user_image'    =>  $user_data->user_image
                    );
                }

                $sender_connection_id = User::select('connection_id')->where('id', $data->user_id)->get();

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $send_data['response_load_notification'] = true;

                        $send_data['data'] = $sub_data;

                        $client->send(json_encode($send_data));
                    }
                }
            }

            if($data->type == 'request_process_chat_request')
            {
                Chat_request::where('id', $data->chat_request_id)->update(['status' => $data->action]);

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                $receiver_connection_id = User::select('connection_id')->where('id', $data->to_user_id)->get();

                foreach($this->clients as $client)
                {
                    $send_data['response_process_chat_request'] = true;

                    if($client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $send_data['user_id'] = $data->from_user_id;
                    }

                    if($client->resourceId == $receiver_connection_id[0]->connection_id)
                    {
                        $send_data['user_id'] = $data->to_user_id;
                    }

                    $client->send(json_encode($send_data));
                }
            }

            if($data->type == 'request_connected_chat_user')
            {
                $condition_1 = ['from_user_id' => $data->from_user_id, 'to_user_id' => $data->from_user_id];

                $user_id_data = Chat_request::select('from_user_id', 'to_user_id')
                                            ->orWhere($condition_1)
                                            ->where('status', 'Approve')
                                            ->get();

                /*
                SELECT from_user id, to_user_id FROM chat_requests 
                WHERE (from_user_id = $data->from_user_id OR to_user_id = $data->from_user_id) 
                AND status = 'Approve'
                */

                $sub_data = array();

                foreach($user_id_data as $user_id_row)
                {
                    $user_id = '';

                    if($user_id_row->from_user_id != $data->from_user_id)
                    {
                        $user_id = $user_id_row->from_user_id;
                    }
                    else
                    {
                        $user_id = $user_id_row->to_user_id;
                    }

                    $user_data = User::select('id', 'name', 'user_image', 'user_status', 'updated_at')->where('id', $user_id)->first();

                    if(date('Y-m-d') == date('Y-m-d', strtotime($user_data->updated_at)))
                    {
                        $last_seen = 'Last Seen At ' . date('H:i', strtotime($user_data->updated_at));
                    }
                    else
                    {
                        $last_seen = 'Last Seen At ' . date('d/m/Y H:i', strtotime($user_data->updated_at));
                    }

                    $sub_data[] = array(
                        'id'    =>  $user_data->id,
                        'name'  =>  $user_data->name,
                        'user_image'    =>  $user_data->user_image,
                        'user_status'   =>  $user_data->user_status,
                        'last_seen'     =>  $last_seen
                    );


                }

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $send_data['response_connected_chat_user'] = true;

                        $send_data['data'] = $sub_data;

                        $client->send(json_encode($send_data));
                    }
                }
            }

            if($data->type == 'request_send_message')
            {
                //save chat message in mysql

                $chat = new Chat;

                $chat->from_user_id = $data->from_user_id;

                $chat->to_user_id = $data->to_user_id;

                $chat->chat_message = $data->message;

                $chat->message_status = 'Not Send';

                $chat->save();

                $chat_message_id = $chat->id;

                $receiver_connection_id = User::select('connection_id')->where('id', $data->to_user_id)->get();

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $receiver_connection_id[0]->connection_id || $client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $send_data['chat_message_id'] = $chat_message_id;
                        
                        $send_data['message'] = $data->message;

                        $send_data['from_user_id'] = $data->from_user_id;

                        $send_data['to_user_id'] = $data->to_user_id;

                        if($client->resourceId == $receiver_connection_id[0]->connection_id)
                        {
                            Chat::where('id', $chat_message_id)->update(['message_status' =>'Send']);

                            $send_data['message_status'] = 'Send';
                        }
                        else
                        {
                            $send_data['message_status'] = 'Not Send';
                        }

                        $client->send(json_encode($send_data));
                    }
                }
            }

            if($data->type == 'request_chat_history')
            {
                $chat_data = Chat::select('id', 'from_user_id', 'to_user_id', 'chat_message', 'message_status')
                                    ->where(function($query) use ($data){
                                        $query->where('from_user_id', $data->from_user_id)->where('to_user_id', $data->to_user_id);
                                    })
                                    ->orWhere(function($query) use ($data){
                                        $query->where('from_user_id', $data->to_user_id)->where('to_user_id', $data->from_user_id);
                                    })->orderBy('id', 'ASC')->get();
                /*
                SELECT id, from_user_id, to_user_id, chat_message, message status 
                FROM chats 
                WHERE (from_user_id = $data->from_user_id AND to_user_id = $data->to_user_id) 
                OR (from_user_id = $data->to_user_id AND to_user_id = $data->from_user_id)
                ORDER BY id ASC
                */

                $send_data['chat_history'] = $chat_data;

                $receiver_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $receiver_connection_id[0]->connection_id)
                    {
                        $client->send(json_encode($send_data));
                    }
                }

            }

            if($data->type == 'update_chat_status')
            {
                //update chat status

                Chat::where('id', $data->chat_message_id)->update(['message_status' => $data->chat_message_status]);

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get();

                foreach($this->clients as $client)
                {
                    if($client->resourceId == $sender_connection_id[0]->connection_id)
                    {
                        $send_data['update_message_status'] = $data->chat_message_status;

                        $send_data['chat_message_id'] = $data->chat_message_id;

                        $client->send(json_encode($send_data));
                    }
                }
            }

            if($data->type == 'check_unread_message')
            {
                $chat_data = Chat::select('id', 'from_user_id', 'to_user_id')->where('message_status', '!=', 'Read')->where('from_user_id', $data->to_user_id)->get();

                /*
                SELECT id, from_user_id, to_user_id FROM chats 
                WHERE message_status != 'Read'
                AND from_user_id = $data->to_user_id
                */

                $sender_connection_id = User::select('connection_id')->where('id', $data->from_user_id)->get(); //send number of unread message

                $receiver_connection_id = User::select('connection_id')->where('id', $data->to_user_id)->get(); //send message read status

                foreach($chat_data as $row)
                {
                    Chat::where('id', $row->id)->update(['message_status' => 'Send']);

                    foreach($this->clients as $client)
                    {
                        if($client->resourceId == $sender_connection_id[0]->connection_id)
                        {
                            $send_data['count_unread_message'] = 1;

                            $send_data['chat_message_id'] = $row->id;

                            $send_data['from_user_id'] = $row->from_user_id;
                        }

                        if($client->resourceId == $receiver_connection_id[0]->connection_id)
                        {
                            $send_data['update_message_status'] = 'Send';

                            $send_data['chat_message_id'] = $row->id;

                            $send_data['unread_msg'] = 1;

                            $send_data['from_user_id'] = $row->from_user_id;
                        }

                        $client->send(json_encode($send_data));
                    }
                }
            }
        }
    }

    public function onClose(ConnectionInterface $conn)
    {
        $this->clients->detach($conn);

        $querystring = $conn->httpRequest->getUri()->getQuery();

        parse_str($querystring, $queryarray);

        if(isset($queryarray['token']))
        {
            User::where('token', $queryarray['token'])->update([ 'connection_id' => 0, 'user_status' => 'Offline' ]);

            $user_id = User::select('id', 'updated_at')->where('token', $queryarray['token'])->get();

            $data['id'] = $user_id[0]->id;

            $data['status'] = 'Offline';

            $updated_at = $user_id[0]->updated_at;

            if(date('Y-m-d') == date('Y-m-d', strtotime($updated_at))) //Same Date, so display only Time
            {
                $data['last_seen'] = 'Last Seen at ' . date('H:i');
            }
            else
            {
                $data['last_seen'] = 'Last Seen at ' . date('d/m/Y H:i');
            }

            foreach($this->clients as $client)
            {
                if($client->resourceId != $conn->resourceId)
                {
                    $client->send(json_encode($data));
                }
            }
        }
    }

    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        echo "An error has occurred: {$e->getMessage()} \n";

        $conn->close();
    }
}



Step 6 - Create View Blades Files


In this steps, we have to make Blade views file for display HTML output in the browser. So first we have to make Login, Registration and Master template for this Laravel Chat Application. So we have goes to resources/views directory and under this directory, we have to make following views blade file.

resources/views/main.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Laravel 9 Custom Login Registration</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
<body>

    <nav class="navbar navbar-light navbar-expand-lg mb-5" style="background-color: #e3f2fd;">
        <div class="container">
            <a class="navbar-brand mr-auto" href="#">Chat Application</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                    
                <ul class="navbar-nav">
                    @guest

                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('login') }}">Login</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('registration') }}">Register</a>
                    </li>

                    @else

                    <li class="nav-item">
                        @if(Auth::user()->user_image != '')
                        <a class="nav-link" href="#"><b>Welcome <img src="{{ asset('images/' . Auth::user()->user_image ) }}" width="35" class="rounded-circle" />&nbsp; {{ Auth::user()->name }}</b></a>
                        @else
                        <a class="nav-link" href="#"><b>Welcome <img src="{{ asset('images/no-image.jpg') }}" width="35" class="rounded-circle" />&nbsp;{{ Auth::user()->name }}</b></a>
                        @endif
                    </li>

                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('profile') }}">Profile</a>
                    </li>

                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('logout') }}">Logout</a>
                    </li>

                    @endguest
                </ul>
                
            </div>
        </div>
    </nav>
    <div class="container-fluid mt-5">

        @yield('content')
        
    </div>
    
</body>
</html>


resources/views/login.blade.php

@extends('main')

@section('content')

@if($message = Session::get('success'))

<div class="alert alert-info">
{{ $message }}
</div>

@endif

<div class="row justify-content-center">
	<div class="col-md-4">
		<div class="card">
			<div class="card-header">Login</div>
			<div class="card-body">
				<form action="{{ route('sample.validate_login') }}" method="post">
					@csrf
					<div class="form-group mb-3">
						<input type="text" name="email" class="form-control" placeholder="Email" />
						@if($errors->has('email'))
							<span class="text-danger">{{ $errors->first('email') }}</span>
						@endif
					</div>
					<div class="form-group mb-3">
						<input type="password" name="password" class="form-control" placeholder="Password" />
						@if($errors->has('password'))
							<span class="text-danger">{{ $errors->first('password') }}</span>
						@endif
					</div>
					<div class="d-grid mx-auto">
						<button type="subit" class="btn btn-dark btn-block">Login</button>
					</div>
				</form>
			</div>
		</div>
	</div>
</div>

@endsection('content')


resources/views/registration.blade.php

@extends('main')

@section('content')

<div class="row justify-content-center">
	<div class="col-md-4">
		<div class="card">
		<div class="card-header">Registration</div>
		<div class="card-body">
			<form action="{{ route('sample.validate_registration') }}" method="POST">
				@csrf
				<div class="form-group mb-3">
					<input type="text" name="name" class="form-control" placeholder="Name" />
					@if($errors->has('name'))
						<span class="text-danger">{{ $errors->first('name') }}</span>
					@endif
				</div>
				<div class="form-group mb-3">
					<input type="text" name="email" class="form-control" placeholder="Email Address" />
					@if($errors->has('email'))
						<span class="text-danger">{{ $errors->first('email') }}</span>
					@endif
				</div>
				<div class="form-group mb-3">
					<input type="password" name="password" class="form-control" placeholder="Password" />
					@if($errors->has('password'))
						<span class="text-danger">{{ $errors->first('password') }}</span>
					@endif
				</div>
				<div class="d-grid mx-auto">
					<button type="submit" class="btn btn-dark btn-block">Register</button>
				</div>
			</form>
		</div>
	</div>
</div>

@endsection('content')


resources/views/dashboard.php

@extends('main')

@section('content')

<div class="row">
	<div class="col-sm-4 col-lg-3">
		<div class="card">
			<div class="card-header"><b>Connected User</b></div>
			<div class="card-body" id="user_list">
				
			</div>
		</div>
	</div>
	<div class="col-sm-4 col-lg-6">
		<div class="card">
			<div class="card-header">
				<div class="row">
					<div class="col col-md-6" id="chat_header"><b>Chat Area</b></div>
					<div class="col col-md-6" id="close_chat_area"></div>
				</div>
			</div>
			<div class="card-body" id="chat_area">
				
			</div>
		</div>
	</div>
	<div class="col-sm-4 col-lg-3">
		<div class="card" style="height:255px; overflow-y: scroll;">
			<div class="card-header">
				<input type="text" class="form-control" placeholder="Search User..." autocomplete="off" id="search_people" onkeyup="search_user('{{ Auth::id() }}', this.value);" />
			</div>
			<div class="card-body">
				<div id="search_people_area" class="mt-3"></div>
			</div>
		</div>
		<br />
		<div class="card" style="height:255px; overflow-y: scroll;">
			<div class="card-header"><b>Notification</b></div>
			<div class="card-body">
				<ul class="list-group" id="notification_area">
					
				</ul>
			</div>
		</div>
	</div>
</div>

<style>

#chat_area
{
	min-height: 500px;
	/*overflow-y: scroll*/;
}

#chat_history
{
	min-height: 500px; 
	max-height: 500px; 
	overflow-y: scroll; 
	margin-bottom:16px; 
	background-color: #ece5dd;
	padding: 16px;
}

#user_list
{
	min-height: 500px; 
	max-height: 500px; 
	overflow-y: scroll;
}
</style>

@endsection('content')

<script>

var conn = new WebSocket('ws://127.0.0.1:8090/?token={{ auth()->user()->token }}');

var from_user_id = "{{ Auth::user()->id }}";

var to_user_id = "";

conn.onopen = function(e){

	console.log("Connection established!");

	load_unconnected_user(from_user_id);

	load_unread_notification(from_user_id);

	load_connected_chat_user(from_user_id);

};

conn.onmessage = function(e){

	var data = JSON.parse(e.data);

	if(data.image_link)
	{
		//Display Code for uploaded Image

		document.getElementById('message_area').innerHTML = `<img src="{{ asset('images/`+data.image_link+`') }}" class="img-thumbnail img-fluid" />`;
	}

	if(data.status)
	{
		var online_status_icon = document.getElementsByClassName('online_status_icon');

		for(var count = 0; count < online_status_icon.length; count++)
		{
			if(online_status_icon[count].id == 'status_'+data.id)
			{
				if(data.status == 'Online')
				{
					online_status_icon[count].classList.add('text-success');

					online_status_icon[count].classList.remove('text-danger');

					document.getElementById('last_seen_'+data.id+'').innerHTML = 'Online';
				}
				else
				{
					online_status_icon[count].classList.add('text-danger');

					online_status_icon[count].classList.remove('text-success');

					document.getElementById('last_seen_'+data.id+'').innerHTML = data.last_seen;
				}
			}
		}
	}

	if(data.response_load_unconnected_user || data.response_search_user)
	{
		var html = '';

		if(data.data.length > 0)
		{
			html += '<ul class="list-group">';

			for(var count = 0; count < data.data.length; count++)
			{
				var user_image = '';

				if(data.data[count].user_image != '')
				{
					user_image = `<img src="{{ asset('images/') }}/`+data.data[count].user_image+`" width="40" class="rounded-circle" />`;
				}
				else
				{
					user_image = `<img src="{{ asset('images/no-image.jpg') }}" width="40" class="rounded-circle" />`
				}

				html += `
				<li class="list-group-item">
					<div class="row">
						<div class="col col-9">`+user_image+`&nbsp;`+data.data[count].name+`</div>
						<div class="col col-3">
							<button type="button" name="send_request" class="btn btn-primary btn-sm float-end" onclick="send_request(this, `+from_user_id+`, `+data.data[count].id+`)"><i class="fas fa-paper-plane"></i></button>
						</div>
					</div>
				</li>
				`;
			}

			html += '</ul>';
		}
		else
		{
			html = 'No User Found';
		}

		document.getElementById('search_people_area').innerHTML = html;
	}

	if(data.response_from_user_chat_request)
	{
		search_user(from_user_id, document.getElementById('search_people').value);

		load_unread_notification(from_user_id);
	}

	if(data.response_to_user_chat_request)
	{
		load_unread_notification(data.user_id);
	}

	if(data.response_load_notification)
	{
		var html = '';

		for(var count = 0; count < data.data.length; count++)
		{
			var user_image = '';

			if(data.data[count].user_image != '')
			{
				user_image = `<img src="{{ asset('images/') }}/`+data.data[count].user_image+`" width="40" class="rounded-circle" />`;
			}
			else
			{
				user_image = `<img src="{{ asset('images/no-image.jpg') }}" width="40" class="rounded-circle" />`;
			}

			html += `
			<li class="list-group-item">
				<div class="row">
					<div class="col col-8">`+user_image+`&nbsp;`+data.data[count].name+`</div>
					<div class="col col-4">
			`;
			if(data.data[count].notification_type == 'Send Request')
			{
				if(data.data[count].status == 'Pending')
				{
					html += '<button type="button" name="send_request" class="btn btn-warning btn-sm float-end">Request Send</button>';
				}
				else
				{
					html += '<button type="button" name="send_request" class="btn btn-danger btn-sm float-end">Request Rejected</button>';
				}
			}
			else
			{
				if(data.data[count].status == 'Pending')
				{
					html += '<button type="button" class="btn btn-danger btn-sm float-end" onclick="process_chat_request('+data.data[count].id+', '+data.data[count].from_user_id+', '+data.data[count].to_user_id+', `Reject`)"><i class="fas fa-times"></i></button>&nbsp;';
					html += '<button type="button" class="btn btn-success btn-sm float-end" onclick="process_chat_request('+data.data[count].id+', '+data.data[count].from_user_id+', '+data.data[count].to_user_id+', `Approve`)"><i class="fas fa-check"></i></button>';
				}
				else
				{
					html += '<button type="button" name="send_request" class="btn btn-danger btn-sm float-end">Request Rejected</button>';
				}
			}

			html += `
					</div>
				</div>
			</li>
			`;
		}

		document.getElementById('notification_area').innerHTML = html;
	}

	if(data.response_process_chat_request)
	{
		load_unread_notification(data.user_id);

		load_connected_chat_user(data.user_id);
	}

	if(data.response_connected_chat_user)
	{
		var html = '<div class="list-group">';

		if(data.data.length > 0)
		{
			for(var count = 0; count < data.data.length; count++)
			{
				html += `
				<a href="#" class="list-group-item d-flex justify-content-between align-items-start" onclick="make_chat_area(`+data.data[count].id+`, '`+data.data[count].name+`'); load_chat_data(`+from_user_id+`, `+data.data[count].id+`); ">
					<div class="ms-2 me-auto">
				`;

				var last_seen = '';

				if(data.data[count].user_status == 'Online')
				{
					html += '<span class="text-success online_status_icon" id="status_'+data.data[count].id+'"><i class="fas fa-circle"></i></span>';

					last_seen = 'Online';
				}
				else
				{
					html += '<span class="text-danger online_status_icon" id="status_'+data.data[count].id+'"><i class="fas fa-circle"></i></span>';

					last_seen = data.data[count].last_seen;
				}

				var user_image = '';

				if(data.data[count].user_image != '')
				{
					user_image = `<img src="{{ asset('images/') }}/`+data.data[count].user_image+`" width="35" class="rounded-circle" />`;
				}
				else
				{
					user_image = `<img src="{{ asset('images/no-image.jpg') }}" width="35" class="rounded-circle" />`;
				}



				html += `
						&nbsp; `+user_image+`&nbsp;<b>`+data.data[count].name+`</b>
						<div class="text-right"><small class="text-muted last_seen" id="last_seen_`+data.data[count].id+`">`+last_seen+`</small></div>
					</div>
					<span class="user_unread_message" data-id="`+data.data[count].id+`" id="user_unread_message_`+data.data[count].id+`"></span>
				</a>
				`;
			}
		}
		else
		{
			html += 'No User Found';
		}

		html += '</div>';

		document.getElementById('user_list').innerHTML = html;

		check_unread_message();
	}

	if(data.message)
	{
		var html = '';

		if(data.from_user_id == from_user_id)
		{

			var icon_style = '';

			if(data.message_status == 'Not Send')
			{
				icon_style = '<span id="chat_status_'+data.chat_message_id+'" class="float-end"><i class="fas fa-check text-muted"></i></span>';
			}
			if(data.message_status == 'Send')
			{
				icon_style = '<span id="chat_status_'+data.chat_message_id+'" class="float-end"><i class="fas fa-check-double text-muted"></i></span>';
			}

			if(data.message_status == 'Read')
			{
				icon_style = '<span class="text-primary float-end" id="chat_status_'+data.chat_message_id+'"><i class="fas fa-check-double"></i></span>';
			}

			html += `
			<div class="row">
				<div class="col col-3">&nbsp;</div>
				<div class="col col-9 alert alert-success text-dark shadow-sm">
					`+data.message+ icon_style +`
				</div>
			</div>
			`;
		}
		else
		{
			if(to_user_id != '')
			{
				html += `
				<div class="row">
					<div class="col col-9 alert alert-light text-dark shadow-sm">
					`+data.message+`
					</div>
				</div>
				`;

				update_message_status(data.chat_message_id, from_user_id, to_user_id, 'Read');
			}
			else
			{
				var count_unread_message_element = document.getElementById('user_unread_message_'+data.from_user_id+'');
            	if(count_unread_message_element)
            	{
	            	var count_unread_message = count_unread_message_element.textContent;
	            	if(count_unread_message == '')
	            	{
	            		count_unread_message = parseInt(0) + 1;
	            	}
	            	else
	            	{
	            		count_unread_message = parseInt(count_unread_message) + 1;
	            	}
	            	count_unread_message_element.innerHTML = '<span class="badge bg-primary rounded-pill">'+count_unread_message+'</span>';

	            	update_message_status(data.chat_message_id, data.from_user_id, data.to_user_id, 'Send');
	            }
			}
			
		}

		if(html != '')
		{
			var previous_chat_element = document.querySelector('#chat_history');

			var chat_history_element = document.querySelector('#chat_history');

			chat_history_element.innerHTML = previous_chat_element.innerHTML + html;
			scroll_top();
		}
		
	}

	if(data.chat_history)
	{
		var html = '';

		for(var count = 0; count < data.chat_history.length; count++)
		{
			if(data.chat_history[count].from_user_id == from_user_id)
			{
				var icon_style = '';

				if(data.chat_history[count].message_status == 'Not Send')
				{
					icon_style = '<span id="chat_status_'+data.chat_history[count].id+'" class="float-end"><i class="fas fa-check text-muted"></i></span>';
				}

				if(data.chat_history[count].message_status == 'Send')
				{
					icon_style = '<span id="chat_status_'+data.chat_history[count].id+'" class="float-end"><i class="fas fa-check-double text-muted"></i></span>';
				}

				if(data.chat_history[count].message_status == 'Read')
				{
					icon_style = '<span class="text-primary float-end" id="chat_status_'+data.chat_history[count].id+'"><i class="fas fa-check-double"></i></span>';
				}

				html +=`
				<div class="row">
					<div class="col col-3">&nbsp;</div>
					<div class="col col-9 alert alert-success text-dark shadow-sm">
					`+data.chat_history[count].chat_message+ icon_style + `
					</div>
				</div>
				`;

				
			}
			else
			{
				if(data.chat_history[count].message_status != 'Read')
				{
					update_message_status(data.chat_history[count].id, data.chat_history[count].from_user_id, data.chat_history[count].to_user_id, 'Read');
				}

				html += `
				<div class="row">
					<div class="col col-9 alert alert-light text-dark shadow-sm">
					`+data.chat_history[count].chat_message+`
					</div>
				</div>
				`;

				var count_unread_message_element = document.getElementById('user_unread_message_'+data.chat_history[count].from_user_id+'');

                if(count_unread_message_element)
                {
                	count_unread_message_element.innerHTML = '';
                }
			}
		}

		document.querySelector('#chat_history').innerHTML = html;

		scroll_top();
	}

	if(data.update_message_status)
	{
		var chat_status_element = document.querySelector('#chat_status_'+data.chat_message_id+'');

		if(chat_status_element)
		{
			if(data.update_message_status == 'Read')
			{
				chat_status_element.innerHTML = '<i class="fas fa-check-double text-primary"></i>';
			}
			if(data.update_message_status == 'Send')
			{
				chat_status_element.innerHTML = '<i class="fas fa-check-double text-muted"></i>';
			}
		}

		if(data.unread_msg)
		{
			var count_unread_message_element = document.getElementById('user_unread_message_'+data.from_user_id+'');

			if(count_unread_message_element)
			{
				var count_unread_message = count_unread_message_element.textContent;
				
				if(count_unread_message == '')	
				{
					count_unread_message = parseInt(0) + 1;
				}
				else
				{
					count_unread_message = parseInt(count_unread_message) + 1;
				}

				count_unread_message_element.innerHTML = '<span class="badge bg-danger rounded-pill">'+count_unread_message+'</span>';
			}
		}
	}
};

function scroll_top()
{
    document.querySelector('#chat_history').scrollTop = document.querySelector('#chat_history').scrollHeight;
}

function load_unconnected_user(from_user_id)
{
	var data = {
		from_user_id : from_user_id,
		type : 'request_load_unconnected_user'
	};

	conn.send(JSON.stringify(data));
}

function search_user(from_user_id, search_query)
{
	if(search_query.length > 0)
	{
		var data = {
			from_user_id : from_user_id,
			search_query : search_query,
			type : 'request_search_user'
		};

		conn.send(JSON.stringify(data));
	}
	else
	{
		load_unconnected_user(from_user_id);
	}
}

function send_request(element, from_user_id, to_user_id)
{
	var data = {
		from_user_id : from_user_id,
		to_user_id : to_user_id,
		type : 'request_chat_user'
	};

	element.disabled = true;

	conn.send(JSON.stringify(data));
}

function load_unread_notification(user_id)
{
	var data = {
		user_id : user_id,
		type : 'request_load_unread_notification'
	};

	conn.send(JSON.stringify(data));

}

function process_chat_request(chat_request_id, from_user_id, to_user_id, action)
{
	var data = {
		chat_request_id : chat_request_id,
		from_user_id : from_user_id,
		to_user_id : to_user_id,
		action : action,
		type : 'request_process_chat_request'
	};

	conn.send(JSON.stringify(data));
}

function load_connected_chat_user(from_user_id)
{
	var data = {
		from_user_id : from_user_id,
		type : 'request_connected_chat_user'
	};

	conn.send(JSON.stringify(data));
}

function make_chat_area(user_id, to_user_name)
{
	var html = `
	<div id="chat_history"></div>
	<div class="input-group mb-3">
		<div id="message_area" class="form-control" contenteditable style="min-height:125px; border:1px solid #ccc; border-radius:5px;"></div>
		<label class="btn btn-warning" style="line-height:125px;">
			<i class="fas fa-upload"></i> <input type="file" id="browse_image" onchange="upload_image()" hidden />
		</label>
		<button type="button" class="btn btn-success" id="send_button" onclick="send_chat_message()"><i class="fas fa-paper-plane"></i></button>
	</div>
	`;

	document.getElementById('chat_area').innerHTML = html;

	document.getElementById('chat_header').innerHTML = 'Chat with <b>'+to_user_name+'</b>';

	document.getElementById('close_chat_area').innerHTML = '<button type="button" id="close_chat" class="btn btn-danger btn-sm float-end" onclick="close_chat();"><i class="fas fa-times"></i></button>';

	to_user_id = user_id;
}

function close_chat()
{
	document.getElementById('chat_header').innerHTML = 'Chat Area';

	document.getElementById('close_chat_area').innerHTML = '';

	document.getElementById('chat_area').innerHTML = '';

	to_user_id = '';
}

function send_chat_message()
{
	document.querySelector('#send_button').disabled = true;

	var message = document.getElementById('message_area').innerHTML.trim();

	var data = {
		message : message,
		from_user_id : from_user_id,
		to_user_id : to_user_id,
		type : 'request_send_message'
	};

	conn.send(JSON.stringify(data));

	document.querySelector('#message_area').innerHTML = '';

	document.querySelector('#send_button').disabled = false;
}

function load_chat_data(from_user_id, to_user_id)
{
	var data = {
		from_user_id : from_user_id,
		to_user_id : to_user_id,
		type : 'request_chat_history'
	};

	conn.send(JSON.stringify(data));
}

function update_message_status(chat_message_id, from_user_id, to_user_id, chat_message_status)
{
	var data = {
		chat_message_id : chat_message_id,
		from_user_id : from_user_id,
		to_user_id : to_user_id,
		chat_message_status : chat_message_status,
		type : 'update_chat_status'
	};

	conn.send(JSON.stringify(data));
}

function check_unread_message()
{
	var unread_element = document.getElementsByClassName('user_unread_message');

	for(var count = 0; count < unread_element.length; count++)
	{
		var temp_user_id = unread_element[count].dataset.id;

		var data = {
			from_user_id : from_user_id,
			to_user_id : to_user_id,
			type : 'check_unread_message'
		};

		conn.send(JSON.stringify(data));
	}
}

function upload_image()
{
	var file_element = document.getElementById('browse_image').files[0];

	var file_name = file_element.name;

	var file_extension = file_name.split('.').pop().toLowerCase();

	var allowed_extension = ['png', 'jpg'];

	if(allowed_extension.indexOf(file_extension) == -1)
	{
		alert("Invalid Image File");

		return false;
	}

	var file_reader = new FileReader();

	var file_raw_data = new ArrayBuffer();

	file_reader.loadend = function()
	{

	}

	file_reader.onload = function(event){

		file_raw_data = event.target.result;

		conn.send(file_raw_data);
	}

	file_reader.readAsArrayBuffer(file_element);
}

</script>


Step 7 - Set Route of Controller Method


Next we have to set route of Controllers class method. So for this, we have to open routes/web.php and under this file, we have to write following code for set route for Controllers Class method.

routes/web.php

<?php

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\SampleController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::controller(SampleController::class)->group(function(){

    Route::get('login', 'index')->name('login');

    Route::get('registration', 'registration')->name('registration');

    Route::get('logout', 'logout')->name('logout');

    Route::post('validate_registration', 'validate_registration')->name('sample.validate_registration');

    Route::post('validate_login', 'validate_login')->name('sample.validate_login');

    Route::get('dashboard', 'dashboard')->name('dashboard');

    Route::get('profile', 'profile')->name('profile');

    Route::post('profile_validation', 'profile_validation')->name('sample.profile_validation');

});



Step 8 - Run Laravel 9 Application


Now we have come to last step and under this step we have to check output in the browser. So before check output in the browser, first we need to start Laravel server. So we have goes to command prompt and run following command.


php artisan serve


This command will start Laravel server and it will provide use base url of our Laravel Ratchet WebScoket Chat Application, so we have goes to browser and paste following url in browser for check output in the browser.


http://127.0.0.1:8000/login


This is partial code and we will update remaining code on every publish of video tutorial. So check this tutorial, on every publish of new video tutorial of this Real-time Laravel Ratchet WebSocket Chat Application.