blog.codehunger.in Open in urlscan Pro
2a02:4780:11:884:0:14f3:47ce:3  Public Scan

URL: https://blog.codehunger.in/how-to-create-installer-in-laravel/
Submission: On December 18 via api from US — Scanned from DE

Form analysis 4 forms found in the DOM

GET https://blog.codehunger.in/

<form method="get" id="search" action="https://blog.codehunger.in/">
  <input id="search-input" class="is-ajax-search" inputmode="search" type="text" name="s" title="Search for" placeholder="Search for" autocomplete="off">
  <button id="search-submit" type="submit">
    <span class="tie-icon-search tie-search-icon" aria-hidden="true"></span>
    <span class="screen-reader-text">Search for</span>
  </button>
</form>

POST https://blog.codehunger.in/wp-comments-post.php

<form action="https://blog.codehunger.in/wp-comments-post.php" method="post" id="commentform" class="comment-form" novalidate="">
  <p class="comment-notes"><span id="email-notes">Your email address will not be published.</span> <span class="required-field-message">Required fields are marked <span class="required">*</span></span></p>
  <p class="comment-form-comment"><label for="comment">Comment <span class="required">*</span></label> <textarea id="comment" name="comment" cols="45" rows="8" maxlength="65525" required=""></textarea></p>
  <p class="comment-form-author"><label for="author">Name <span class="required">*</span></label> <input id="author" name="author" type="text" value="" size="30" maxlength="245" autocomplete="name" required=""></p>
  <p class="comment-form-email"><label for="email">Email <span class="required">*</span></label> <input id="email" name="email" type="email" value="" size="30" maxlength="100" aria-describedby="email-notes" autocomplete="email" required=""></p>
  <p class="comment-form-url"><label for="url">Website</label> <input id="url" name="url" type="url" value="" size="30" maxlength="200" autocomplete="url"></p>
  <p class="comment-form-cookies-consent"><input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"> <label for="wp-comment-cookies-consent">Save my name, email, and website in this browser for the next time
      I comment.</label></p>
  <p class="comment-subscription-form"><input type="checkbox" name="subscribe_comments" id="subscribe_comments" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"> <label class="subscribe-label"
      id="subscribe-label" for="subscribe_comments">Notify me of follow-up comments by email.</label></p>
  <p class="comment-subscription-form"><input type="checkbox" name="subscribe_blog" id="subscribe_blog" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"> <label class="subscribe-label"
      id="subscribe-blog-label" for="subscribe_blog">Notify me of new posts by email.</label></p>
  <p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Post Comment"> <input type="hidden" name="comment_post_ID" value="4763" id="comment_post_ID">
    <input type="hidden" name="comment_parent" id="comment_parent" value="0">
  </p>
  <p style="display: none;"><input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="0e00b01958"></p>
  <p style="display: none !important;"><label>Δ<textarea name="ak_hp_textarea" cols="45" rows="8" maxlength="100"></textarea></label><input type="hidden" id="ak_js_1" name="ak_js" value="1702904900599">
    <script>
      document.getElementById("ak_js_1").setAttribute("value", (new Date()).getTime());
    </script>
  </p>
</form>

GET https://blog.codehunger.in/

<form role="search" method="get" class="search-form" action="https://blog.codehunger.in/">
  <label>
    <span class="screen-reader-text">Search for:</span>
    <input type="search" class="search-field" placeholder="Search …" value="" name="s">
  </label>
  <input type="submit" class="search-submit" value="Search">
</form>

GET https://blog.codehunger.in/

<form method="get" class="tie-popup-search-form" action="https://blog.codehunger.in/">
  <input class="tie-popup-search-input " inputmode="search" type="text" name="s" title="Search for" autocomplete="off" placeholder="Search for">
  <button class="tie-popup-search-submit" type="submit">
    <span class="tie-icon-search tie-search-icon" aria-hidden="true"></span>
    <span class="screen-reader-text">Search for</span>
  </button>
</form>

Text Content

Monday, December 18 2023
Latest Post

As a React Native Developer, How can I Increase the Performance of an React
Native App


 * 
 * 

 * Switch skin
 * Sidebar
 * Random Article
 * Instagram
 * GitHub
 * YouTube
 * LinkedIn
 * Twitter
 * Facebook

 * Menu


 * Search for


 * Home
 * Programming
   * C PROGRAMMING
   * Python
   * Java
 * Quiz
   * Programming in C
 * Tutorials
   * React Native
   * C#
   * C++
 * Web Development
   * PHP
   * .Net
   * Laravel
   * Html
   * SQL
   * SEO
   * JavaScript
     * Vue js
     * Angular js
     * jQuery
     * React js
     * Node Js
     * Ajax
 * Other
   * Digital Marketing
   * LifeStyle
     * Healthy Tips
     * Human Behaviour & Mental Health
   * Tips & Tricks
   * Poems
 * Contact Us

 * 10
   PopularArticles
   
   
    * HOW TO BOOST WEBSITE SEO
      
      4 weeks ago
   
   
    * AS A REACT NATIVE DEVELOPER, HOW CAN I INCREASE THE PERFORMANCE OF AN
      REACT NATIVE APP
      
      4 weeks ago
   
   
    * UNLEASHING SUCCESS: THE POWER OF ECOMMERCE DEVELOPMENT COMPANIES
      
      November 16, 2023
   
   
    * WHAT DEVELOPER NEED TO DO TO MAKE THE WEBSITE RUN SMOOTHLY?
      
      November 14, 2023
   
   
    * HOW TO HIRE EXPERIENCED APP DEVELOPER AT LOW COST
      
      November 14, 2023
   
   
    * HOW TO HIRE EXPERIENCED WEB DEVELOPER AT LOW COST
      
      November 13, 2023
   
   
    * WEBSITE DEVELOPMENT ONLY AT $5 PER HOUR
      
      November 13, 2023
   
   
    * WHAT IS DOMAIN AND SUBDOMAIN IN WEBSITE DEVELOPMENT?
      
      November 12, 2023
   
   
    * WHY SHOULD WE HAVE A WEBSITE FOR OUR BUSINESS AND HOW IT WILL BE HELPFUL
      IN OUR SALES?
      
      November 10, 2023
   
   
    * WHAT IS THE EASIEST WAY TO BUILD AN E-COMMERCE WEBSITE?
      
      November 10, 2023

 * Search for

Home/Laravel/How to Create Installer In Laravel
Laravel


HOW TO CREATE INSTALLER IN LARAVEL

sachin bharmoria Send an email June 16, 2022Last Updated: June 16, 2022
0 70 13 minutes read


In this article, we will guide you through the step-by-step process of creating
your custom web installer for your web application. If you are building a
complex application that requires a lot of initial configuration, it’s
considered to develop a web installer.

A web installer is also helpful for the non-tech-savvy users to install your web
application on their server. There are many packages built for the same purpose.
But in this article, we will guide you through the process of making your own
web installer for Laravel.

We will be adding almost all the features in our web installer that are
generally needed when installing the Laravel software. Here’s the list of
features that we are going to add to our installer:

 * Check Minimum Requirements
 * Setup Database Details
 * Run The Database Migration
 * Create Admin User Account
 * Setup Website Configuration


STEPS TO CREATE INSTALLER IN LARAVEL

Here are the steps you need to go through to create your custom Laravel web
installer:


STEP 1: SETUP YOUR LARAVEL APPLICATION

Create your new Laravel web application if haven’t already using the following
command:

laravel new application-name-here


STEP 2: SETUP YOUR WEB INSTALLER ASSETS & VIEW FILES

 * In this example, we will be using bootstrap to build the setup user
   interface. So, we will create a folder inside the public folder named “setup”
   inside which all the bootstrap CSS and JS files will be present.
 * Inside public/setup folder, create two more folder named as css, img.
 * Inside css folder, place bootstrap.min.css file and inside img folder, place
   your application’s favicon.ico file.
 * Now, create a folder named “setup” inside resources->views. This folder
   contains all the view files needed for the setup.

After completing these steps, create the following files inside your views/setup
folder accordingly:


 * app.blade.php
 * index.blade.php
 * requirements.blade.php
 * database.blade.php
 * account.blade.php
 * config.blade.php
 * complete.blade.php

Paste the following code in those view files accordingly:

Inside app.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>{{ config('app.name', 'Custom Installer') }}</title>
    <link rel="icon" href="{{ asset('setup/img/favicon.ico') }}">
    <link href="{{ asset('setup/css/bootstrap.min.css') }}" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    @stack('styles')
  </head>

  <body>
    <main class="main container mt-5">
        <div class="mb-5 h1 text-center text-primary">
            Web Installer
        </div>

        @yield('content')
    </main>
  </body>
  @stack('scripts')
</html>


Inside index.blade.php



@extends('setup.app')
@section('content')
<div class="row justify-content-center">
    <div class="col-12 col-md-8">
        @if($errors->any())
        <div class="card mb-1">
            <div class="card-body text-danger">
                {{$errors->first()}}
            </div>
        </div>
        @endif
        <div class="card">
            <div class="card-header">
                Welcome To Web Installer
            </div>
            <div class="card-body">

                <p>Step By Step Installer</p>

                <ol>
                    <li>Check Minimum Requirements</li>
                    <li>Enter Database Details</li>
                    <li>Setup User Account</li>
                </ol>

                <a href="{{ route('setup.requirements') }}" class="btn btn-primary">
                    Check Minimum Requirements
                </a>
            </div>
        </div>

    </div>
</div>
@endsection

Inside requirements.blade.php

@extends('setup.app')
@section('content')
<div class="row justify-content-center">
    <div class="col-12 col-md-8">

        <div class="card">
            <div class="card-header">
                Minimum Requirements
            </div>
            <div class="card-body">

                <ul>
                    @foreach($checks as $key => $check)
                    <li>
                    @lang('setup.' . $key)
                    @if($check)
                    <i class="fa fa-check text-success"></i>
                    @else
                    <i class="fa fa-close text-danger"></i>
                    @endif
                    </li>
                    @endforeach
                </ul>

                @if($success)
                <a href="{{ route('setup.database') }}" class="btn btn-primary">
                    Setup Database
                </a>
                @endif
            </div>
        </div>

    </div>
</div>
@endsection

Inside database.blade.php

@extends('setup.app')
@section('content')
<div class="row justify-content-center">
    <div class="col-12 col-md-8">
        @if($errors->any())
        <div class="card mb-1">
            <div class="card-body text-danger">
                {{$errors->first()}}
            </div>
        </div>
        @endif
        <div class="card">
            <div class="card-header">
                Enter Database Details
            </div>
            <div class="card-body">
                <form method="POST" action="{{ route('setup.database.submit') }}" autocomplete="off">
                    @csrf
                    <div class="mb-3">
                        <label>Host <span class="text-danger">*</span></label>
                        <input type="text" name="host" class="form-control" value="{{ old('host') ?:'127.0.0.1' }}" placeholder="Enter Database Host">
                        <div class="form-text">Enter Server IP In Case Of Remote Database, 127.0.0.1 Is Default</div>
                    </div>
                    <div class="mb-3">
                        <label>Port <span class="text-danger">*</span></label>
                        <input type="text" name="port" class="form-control" value="{{ old('port') ?:'3306' }}" placeholder="Enter Database Port">
                        <div class="form-text">Enter Database Port. Default Is 3306</div>
                    </div>
                    <div class="mb-3">
                        <label>Database Name <span class="text-danger">*</span></label>
                        <input type="text" name="database" value="{{ old('database')}}" class="form-control" placeholder="Enter Database Name">
                        <div class="form-text">Enter Database Name Here, Create New Database If Haven't Already</div>
                    </div>
                    <div class="mb-3">
                        <label>Database User <span class="text-danger">*</span></label>
                        <input autocomplete="off" type="text" name="user" value="{{ old('user')}}" class="form-control" placeholder="Enter Database User Name Here">
                        <div class="form-text">Enter Database Username Here, Create New User If Haven't Already</div>
                    </div>
                    <div class="mb-3">
                        <label>Database User Password <span class="text-danger">*</span></label>
                        <input autocomplete="new-password" type="password" name="password" value="{{ old('password')}}" class="form-control" placeholder="Enter Database User Password">
                        <div class="form-text">Enter Database Password Here</div>
                    </div>
                    <button type="submit" class="btn btn-primary">Submit Details</button>
                </form>
            </div>
        </div>

    </div>
</div>
@endsection


Inside account.blade.php

@extends('setup.app')
@section('content')
<div class="row justify-content-center">
    <div class="col-12 col-md-8">
        @if($errors->any())
        <div class="card mb-1">
            <div class="card-body text-danger">
                {{$errors->first()}}
            </div>
        </div>
        @endif
        <div class="card">
            <div class="card-header">
                Setup Your User Account
            </div>
            <div class="card-body">
                <form method="POST" action="{{ route('setup.account.submit') }}" autocomplete="off" enctype="multipart/form-data">
                    @csrf
                    <div class="mb-3">
                        <label>Full Name <span class="text-danger">*</span></label>
                        <input type="text" name="name" class="form-control" value="{{ old('name') }}" placeholder="Enter Your Full Name">
                    </div>
                    <div class="mb-3">
                        <label>E-Mail <span class="text-danger">*</span></label>
                        <input type="text" name="email" class="form-control" value="{{ old('email') }}" placeholder="Enter Your E-Mail Address">
                    </div>
                    <div class="mb-3">
                        <label>Profile Pic <span class="text-danger">*</span></label>
                        <input type="file" name="profile_pic" class="form-control" value="{{ old('profile_pic') }}" placeholder="Select Profile Pic">
                    </div>
                    <div class="mb-3">
                        <label>Password <span class="text-danger">*</span></label>
                        <input autocomplete="new-password" type="password" name="password" value="{{ old('password')}}" class="form-control" placeholder="Enter Your Password">
                    </div>
                    <div class="mb-3">
                        <label>Re-Type Password <span class="text-danger">*</span></label>
                        <input autocomplete="new-password" type="password" name="confirm_password" value="{{ old('password')}}" class="form-control" placeholder="Confirm Your Address">
                    </div>
                    <button type="submit" class="btn btn-primary">Create Account</button>
                </form>
            </div>
        </div>

    </div>
</div>
@endsection


Inside: config.blade.php

@extends('setup.app')
@section('content')
<div class="row justify-content-center">
    <div class="col-12 col-md-8">
        @if($errors->any())
        <div class="card mb-1">
            <div class="card-body text-danger">
                {{$errors->first()}}
            </div>
        </div>
        @endif
        <div class="card">
            <div class="card-header">
                Configure Your Website
            </div>
            <div class="card-body">
                <form method="POST" action="{{ route('setup.configuration.submit') }}" autocomplete="off" enctype="multipart/form-data">
                    @csrf
                    <div class="mb-3">
                        <label>Company Name <span class="text-danger">*</span></label>
                        <input type="text" name="config_company_name" class="form-control" value="{{ old('config_company_name') }}" placeholder="Enter Your Company Name">
                    </div>
                    <div class="mb-3">
                        <label>Company Address <span class="text-danger">*</span></label>
                        <textarea name="config_company_address" class="form-control">{{ old('config_company_address') }}</textarea>
                    </div>
                    <div class="mb-3">
                        <label>App Name <span class="text-danger">*</span></label>
                        <input type="text" name="config_app_name" class="form-control" value="{{ old('config_app_name') }}" placeholder="Enter Your App Name">
                    </div>
                    <div class="mb-3">
                        <label>App Currency <span class="text-danger">*</span></label>
                        <select name="config_app_currency" class="form-control">
                            <option value="INR">INR</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>App Language <span class="text-danger">*</span></label>
                        <select name="config_app_lang" class="form-control">
                            <option value="en">EN</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>App Logo <span class="text-danger">*</span></label>
                        <input type="file" name="config_app_logo" class="form-control" placeholder="Select App Logo">
                    </div>
                    <div class="mb-3">
                        <label>App Favicon <span class="text-danger">*</span></label>
                        <input type="file" name="config_app_favicon_icon" class="form-control" placeholder="Select App Favicon">
                    </div>
                    <div class="mb-3">
                        <label>App Timestamp <span class="text-danger">*</span></label>
                        <select name="config_app_timestamp" class="form-control">
                            <option value="Asia/Kolkata">Asia/Kolkata</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>App Color Scheme <span class="text-danger">*</span></label>
                        <select name="config_color_scheme_class" class="form-control">
                            <option value="bg-primary">BG-Primary</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>Right Footer 1 Text <span class="text-danger">*</span></label>
                        <textarea name="config_right_footer_1" class="form-control">{{ old('config_right_footer_1') }}</textarea>
                    </div>
                    <div class="mb-3">
                        <label>Right Footer 2 Text <span class="text-danger">*</span></label>
                        <textarea name="config_right_footer_2" class="form-control">{{ old('config_right_footer_2') }}</textarea>
                    </div>
                    <div class="mb-3">
                        <label>Left Footer 1 Text <span class="text-danger">*</span></label>
                        <textarea name="config_left_footer_1" class="form-control">{{ old('config_left_footer_1') }}</textarea>
                    </div>
                    <div class="mb-3">
                        <label>Left Footer 2 Text <span class="text-danger">*</span></label>
                        <textarea name="config_left_footer_2" class="form-control">{{ old('config_left_footer_2') }}</textarea>
                    </div>
                    <div class="mb-3">
                        <label>If Footer Fixed <span class="text-danger">*</span></label>
                        <select name="config_is_footer_fixed" class="form-control">
                            <option value="fixed-footer">Fixed</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>If Header Fixed <span class="text-danger">*</span></label>
                        <select name="config_is_header_fixed" class="form-control">
                            <option value="fixed-header">Fixed</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>If Sidebar Fixed <span class="text-danger">*</span></label>
                        <select name="config_is_sidebar_fixed" class="form-control">
                            <option value="fixed-sidebar">Fixed</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>If Notification Fixed <span class="text-danger">*</span></label>
                        <select name="config_is_checked_notification" class="form-control">
                            <option value="fixed-notification">Fixed</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>Mailer Protocol <span class="text-danger">*</span></label>
                        <select name="config_mail_mailer" class="form-control">
                            <option value="smtp">SMTP</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>Mail Host <span class="text-danger">*</span></label>
                        <input type="text" name="config_mail_host" class="form-control" value="{{ old('config_mail_host') }}" placeholder="Enter Mail Host">
                    </div>
                    <div class="mb-3">
                        <label>Mail Port <span class="text-danger">*</span></label>
                        <input type="text" name="config_mail_port" class="form-control" value="{{ old('config_mail_port') }}" placeholder="Enter Mail Port">
                    </div>
                    <div class="mb-3">
                        <label>Mail Encryption <span class="text-danger">*</span></label>
                        <select name="config_mail_encryption" class="form-control">
                            <option value="tls">TLS</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label>Mail Username <span class="text-danger">*</span></label>
                        <input type="text" name="config_mail_username" class="form-control" value="{{ old('config_mail_username') }}" placeholder="Enter Mail Username">
                    </div>
                    <div class="mb-3">
                        <label>Mail Password <span class="text-danger">*</span></label>
                        <input type="text" name="config_mail_password" class="form-control" value="{{ old('config_mail_password') }}" placeholder="Enter Mail Password">
                    </div>
                    <div class="mb-3">
                        <label>Mail From <span class="text-danger">*</span></label>
                        <input type="text" name="config_mail_from" class="form-control" value="{{ old('config_mail_from') }}" placeholder="Enter Mail From Address">
                    </div>
                    <button type="submit" class="btn btn-primary">Save Config</button>
                </form>
            </div>
        </div>

    </div>
</div>
@endsection


Inside: complete.blade.php

@extends('setup.app')
@section('content')
<div class="row justify-content-center">
    <div class="col-12 col-md-8">
        @if($errors->any())
        <div class="card mb-1">
            <div class="card-body text-danger">
                {{$errors->first()}}
            </div>
        </div>
        @endif
        <div class="card">
            <div class="card-header">
                Setup Complete
            </div>
            <div class="card-body">
                <p class="text-success">Your Setup Is Now Complete, Launch Your Website Now</p>
                <a class="btn btn-primary" href="{{ url('/') }}">Launch Website</a>
            </div>
        </div>

    </div>
</div>
@endsection


All blade directives required by the Installer are set up successfully. Now we
need to create a new Language file.


STEP 3: CREATE A SETUP LANGUAGE FILE

It’s an optional step but we highly recommend you do this. If your application
is multi-lingual, then this is a must.

However, in our example, we are using language files only to show the minimum
requirement message.

Navigate to resources -> lang -> en and create a new setup.php file. Then paste
the following code:

<?php

/**
 * This Language configs are used when running the setup wizard
 */

return [
    'php_version' => 'PHP version >= 7.4.0',
    'extension_bcmath' => 'PHP Extension: BCMath',
    'extension_ctype' => 'PHP Extension: Ctype',
    'extension_json' => 'PHP Extension: JSON',
    'extension_mbstring' => 'PHP Extension: Mbstring',
    'extension_openssl' => 'PHP Extension: OpenSSL',
    'extension_pdo_mysql' => 'PHP Extension: PDO',
    'extension_tokenizer' => 'PHP Extension: Tokenizer',
    'extension_xml' => 'PHP Extension: XML',
    'env_writable' => '.env file is present and writable',
    'storage_writable' => '/storage and /storage/logs directories are writable',
];



STEP 4: MAKE SETUP MIDDLEWARE

A middleware is required to check whether the setup is complete or not. If the
setup is incomplete, the user will be automatically redirected to the setup
page.

But if the setup is completed and the user is hitting the setup page again, the
user will be redirected to the homepage of the application.

Run the following command to create your custom SetupMiddleware:

php artisan make:middleware SetupMiddleware

Paste the following code inside your middleware. The file will be located inside
app/Http/Middleware/SetupMiddleware.php

<?php

namespace App\Http\Middleware;

use Closure;
use Artisan;
use Illuminate\Http\Request;

class SetupMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        if(env('APP_KEY') === null || empty(env('APP_KEY'))  && empty(config('app.key'))){
           Artisan::call('key:generate');
           Artisan::call('config:cache');
        }
        $setupStatus = setupStatus();
        if($request->is('setup/*')){
            if($setupStatus){
                return redirect()->route('home');
            }
            return $next($request);
        }
        if(!$setupStatus){
            return redirect()->route('setup.index');
        }
        return $next($request);
    }
}


STEP 5: REGISTER YOUR MIDDLEWARE

Navigate to app/Http/Kernel.php and inside the protected $middleware array,
paste the following line:

\App\Http\Middleware\SetupMiddleware::class,

Now your middleware array should look like this:

    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \App\Http\Middleware\SetupMiddleware::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];


STEP 6: CREATE HELPER FUNCTIONS

Now, it’s time to create some helper functions that we will use further. If your
project doesn’t have any helpers, create a helper in Laravel as we need them in
our project.

Open your helper function file and paste the following functions:

/**
 * Determines if setup is complete or not
 */

function setupStatus()
{
    try {
        $checkComplete = \App\Models\Configuration::where('config', 'setup_complete')->first();
        if (!$checkComplete) {
            return false;
        }
        if ($checkComplete['value'] === '0') {
            return false;
        }
        return true;
    } catch (Exception $e) {
        return false;
    }
}

/**
 * This function is used to save the image in desired location
 */

function saveImage($image, $location)
{
    $imageName = bin2hex(random_bytes(5)) . time() . '.' . $image->extension();
    $image->move(public_path($location), $imageName);
    $url = url($location . '/' . $imageName);
    return $url;
}


STEP 7: CREATE CONFIGURATION MODEL AND MIGRATION FILES

We need to create a new table inside the database names as configurations. This
table holds all the necessary key=>value pairs that are required by the
installer.

First, create your model named Configuration by running the command given below:

php artisan make:model Configuration

Paste the following code inside that model file:

<?php

namespace App\Models;

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

class Configuration extends Model
{
    use HasFactory;
    
    public $fillable = [
        'config',
        'value',
    ];
}


To create your migration, run the following command:

php artisan make:migration create_configuration_table

Paste the following code inside that migration:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
p
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('configurations', function (Blueprint $table) {
            $table->id();
            $table->string('config');
            $table->string('value');
            $table->timestamps();
        });
    }

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


Now, we also need to populate that table with some default values. So, create
another migration by running the following command:

php artisan make:migration add_config_to_configurations_table

Paste the following code inside that migration file:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\Configuration;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Configuration::create([
            'config' => 'setup_complete',
            'value' => 0,
        ]);
        Configuration::create([
            'config' => 'setup_stage',
            'value' => 1,
        ]);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
};



STEP 9: CREATE CONTROLLERS FOR LARAVEL INSTALLER

Create a folder named Setup inside app/Http/Controllers as we are going to group
all our controllers inside the Setup folder.

Now, run the following commands one by one:

php artisan make:controller Setup/SetupController
php artisan make:controller Setup/AccountController
php artisan make:controller Setup/ConfigurationController

Paste the following code inside each of those controllers:

Code For: SetupController.php

<?php

namespace App\Http\Controllers\Setup;

use App\Http\Controllers\Controller;
use Artisan;
use Config;
use Exception;
use File;
use Illuminate\Http\Request;
use App\Models\Configuration;

class SetupController extends Controller
{
    protected array $dbConfig;

    public function __construct()
    {
        set_time_limit(8000000);
    }

    /**
     * This function is used to display the index of setup
     * @method GET /setup/start/
     * @return Renderable
     */

    public function index()
    {
        return view('setup.index');
    }

    /**
     * This function is used to check for the minimum requirements
     * @method GET /setup/requirements/
     * @return Renderable
     */

    public function requirements()
    {
        [$checks, $success] = $this->checkMinimumRequirements();
        return view('setup.requirements', compact('checks', 'success'));
    }

    /**
     * This function is used to check for the minimum requirements
     * @return Array
     */

    public function checkMinimumRequirements()
    {
        $checks = [
            'php_version' => PHP_VERSION_ID >= 70400,
            'extension_bcmath' => extension_loaded('bcmath'),
            'extension_ctype' => extension_loaded('ctype'),
            'extension_json' => extension_loaded('json'),
            'extension_mbstring' => extension_loaded('mbstring'),
            'extension_openssl' => extension_loaded('openssl'),
            'extension_pdo_mysql' => extension_loaded('pdo_mysql'),
            'extension_tokenizer' => extension_loaded('tokenizer'),
            'extension_xml' => extension_loaded('xml'),
            'env_writable' => File::isWritable(base_path('.env')),
            'storage_writable' => File::isWritable(storage_path()) && File::isWritable(storage_path('logs')),
        ];
        $success = (!in_array(false, $checks, true));
        return [$checks, $success];
    }

    /**
     * This function is used to return the view of database setup
     * @method GET /setup/database/
     * @return Renderable
     */

    public function database()
    {
        return view('setup.database');
    }

    /**
     * This function is used to accept the database submitted values and use them accordingly
     * @method POST /setup/database-submit/
     * @param Request
     * @return Renderable
     */
    public function databaseSubmit(Request $request)
    {
        try {
            $request->validate([
                'host' => 'required|ip',
                'port' => 'required|integer',
                'database' => 'required',
                'user' => 'required',
            ]);
            $this->createDatabaseConnection($request->all());
            $migration = $this->runDatabaseMigration();
            if ($migration !== true) {
                return redirect()->back()->withInput()->withErrors([$migration]);
            }
            $this->changeEnvDatabaseConfig($request->all());
            return view('setup.account');
        } catch (Exception $e) {
            return redirect()->back()->withInput()->withErrors([$e->getMessage()]);
        }
    }

    /**
     * This function is used to create a database connection
     * @param Array of User Submitted Details Of Database
     * @return Response
     */
    public function createDatabaseConnection($details)
    {
        Artisan::call('config:clear');
        $this->dbConfig = config('database.connections.mysql');
        $this->dbConfig['host'] = $details['host'];
        $this->dbConfig['port'] = $details['port'];
        $this->dbConfig['database'] = $details['database'];
        $this->dbConfig['username'] = $details['user'];
        $this->dbConfig['password'] = $details['password'];
        Config::set('database.connections.setup', $this->dbConfig);
    }

    /**
     * This function is used to run the database migration
     */

    public function runDatabaseMigration()
    {
        try {
            Artisan::call('migrate:fresh', [
                '--database' => 'setup',
                '--force' => 'true',
                '--no-interaction' => true,
            ]);
            return true;
        } catch (Exception $e) {
            return $e->getMessage();
        }
    }

        /**
     * This function is used to change the Database Config In ENV File
    */

    public function changeEnvDatabaseConfig($config)
    {
        $this->changeEnvValues('DB_HOST', $config['host']);
        $this->changeEnvValues('DB_PORT', $config['port']);
        $this->changeEnvValues('DB_DATABASE', $config['database']);
        $this->changeEnvValues('DB_USERNAME', $config['user']);
        $this->changeEnvValues('DB_PASSWORD', $config['password']);
    }


    /**
     * This function is used to change the ENV Values
     */

    private function changeEnvValues($key, $value)
    {
        file_put_contents(app()->environmentFilePath(), str_replace(
            $key . '=' . env($key),
            $key . '=' . $value,
            file_get_contents(app()->environmentFilePath())
        ));
    }

        /**
     * This function is used to print the setup complete View
     * @return Renderable
     * @method GET /setup/complete/
     */

    public function setupComplete()
    {
        try{
           $setupStage = Configuration::where('config', 'setup_stage')->firstOrFail();
           if($setupStage['value'] != '3'){
               return redirect()->back()->withInput()->withErrors(['errors' => 'Setup Is Incomplete']);
           }
           $setupStage->update(['value' => '4']);
           Configuration::where('config', 'setup_complete')->firstOrFail()->update(['value' => '1']);;
           return view('setup.complete');
        }catch(Exception $e){
            return redirect()->back()->withErrors([$e->getMessage()]);
        }
    }

}


Code For: AccountController.php

<?php

namespace App\Http\Controllers\Setup;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Configuration;
use Exception;
use App\Models\User;
use Hash;

class AccountController extends Controller
{
    /**
     * This function is used to return View of Account Setup
     * @method GET /setup/account/
     * @return Renderable
     */

    public function account()
    {
        return view('setup.account');
    }

        /**
     * This function is used to create the user Account
     * @param Request
     * @method POST /setup/account-submit/
     * @return Renderable
     */

    public function accountSubmit(Request $request)
    {
        try {
            $request->validate([
                'name' => 'required',
                'email' => 'required|email',
                'profile_pic' => 'required|max:2048|mimes:png,jpg,jpeg,gif',
                'password' => 'required|same:confirm_password',
            ]);
            $profilePic = saveImage($request->profile_pic, 'img/profile');
            User::updateOrCreate([
                'email' => $request->email,
            ],[
                'name' => $request->name,
                'email' => $request->email,
                'profile_pic' => $profilePic,
                'role_id' => 1,
                'password' => Hash::make($request->password),
            ]);
            $stage = Configuration::where('config', 'setup_stage')->firstOrFail()->update(['value' => '2']);
            return redirect()->route('setup.configuration');
        } catch (Exception $e) {
            return redirect()->route('setup.account')->withInput()->withErrors([$e->getMessage()]);
        }
    }
}


Code For: ConfigurationController.php

<?php

namespace App\Http\Controllers\Setup;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Configuration;

class ConfigurationController extends Controller
{
    /**
     * This function is used to return View of Configuration
     * @method GET /setup/configuration/
     * @return Renderable
     */

     public function configuration()
     {
         return view('setup.config');
     }

     /**
      * This function is used to save the configuration values in the database
      * @param Request
      * @return Renderable
      * @method POST /setup/configuration-submit/
      */

    public function configurationSubmit(Request $request)
    {
        try{
            $configurations = $this->processInputs($request);
            $configurations['setup_stage'] = '3';
            foreach($configurations as $key => $config){
                Configuration::updateOrCreate(
                    [
                      'config' => $key
                    ],
                    [
                      'value' => $config
                    ]
                  );
            }
            return redirect()->route('setup.complete');
        }catch(Exception $e){
            return redirect()->route('setup.config')->withInput()->withErrors([$e->getMessage()]);
        }
    }

    /**
     * This function is used to process the inputs
     * It makes the validation first and saves the images etc. to desired path
     * @param Array
     * @return Array
     */

    public function processInputs($request)
    {
        $validated = $this->validateInput($request);
        $logo = saveImage($validated['config_app_logo'], 'img');
        $favicon = saveImage($validated['config_app_favicon_icon'], 'img');
        $validated['config_app_logo'] = $logo;
        $validated['config_app_favicon_icon'] = $favicon;
        return $validated;
    }



    /**
     * This function is used to validate the config submitted input values
     * @param Array
     * @return Array
     */

     public function validateInput($request)
     {
         return $request->validate([
             'config_company_name' => 'required',
             'config_company_address' => 'required',
             'config_app_name' => 'required',
             'config_app_currency' => 'required|in:INR',
             'config_app_lang' => 'required|in:en',
             'config_app_logo' => 'required|max:2048|mimes:png,jpeg,jpg,ico,gif',
             'config_app_favicon_icon' => 'required|max:2048|mimes:png,jpeg,jpg,ico,gif',
             'config_app_timestamp' => 'required|in:Asia/Kolkata',
             'config_color_scheme_class' => 'required|in:bg-primary',
             'config_right_footer_1' => 'required',
             'config_right_footer_2' => 'required',
             'config_left_footer_1' => 'required',
             'config_left_footer_2' => 'required',
             'config_is_footer_fixed' => 'required|in:fixed-footer',
             'config_is_header_fixed' => 'required|in:fixed-header',
             'config_is_sidebar_fixed' => 'required|in:fixed-sidebar',
             'config_is_checked_notification' => 'required|in:fixed-notification',
             'config_mail_mailer' => 'required|in:smtp',
             'config_mail_host' => 'required',
             'config_mail_port' => 'required|integer',
             'config_mail_encryption' => 'required',
             'config_mail_username' => 'required',
             'config_mail_password' => 'required',
             'config_mail_from' => 'required|email',
         ]);
     }
}



STEP 10: REGISTER YOUR ROUTES

Paste the following route group code inside your web.php file:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Setup\SetupController;
use App\Http\Controllers\Setup\AccountController;
use App\Http\Controllers\Setup\ConfigurationController;

Route::get('/', [App\Http\Controllers\HomeController::class, 'index'])->name('home');

Route::prefix('setup')->group(function(){
    Route::get('start', [SetupController::class, 'index'])->name('setup.index');
    Route::get('requirements', [SetupController::class, 'requirements'])->name('setup.requirements');
    Route::get('database', [SetupController::class, 'database'])->name('setup.database');
    Route::post('database-submit', [SetupController::class, 'databaseSubmit'])->name('setup.database.submit');
    Route::get('account', [AccountController::class, 'account'])->name('setup.account');
    Route::post('account-submit', [AccountController::class, 'accountSubmit'])->name('setup.account.submit');
    Route::get('configuration', [ConfigurationController::class, 'configuration'])->name('setup.configuration');
    Route::post('configuration-submit', [ConfigurationController::class, 'configurationSubmit'])->name('setup.configuration.submit');
    Route::get('complete', [SetupController::class, 'setupComplete'])->name('setup.complete');
});

We have successfully created our custom Laravel installer for our web
application. Now, anyone tries to run your web application need to complete the
setup before using the other features of the application.


STEPS TO RUN LARAVEL INSTALLER

Open your terminal and run the following command:

php artisan serve

Once the web application is running, try opening any URL and it will redirect
you to the /setup/start/ page. That’s because Middleware is determining that
your setup is incomplete and you need to complete it first. Here are the steps

Step 1: Click on Check Minimum Requirements.

Step 2: If minimum requirements are met, Setup Database button will appear.

Step 3: Click Setup Database button.

Step 4: Enter Database Details such as host, port, and database credentials.

Step 5: Click on Submit button, if database details are right, migration will
run. Now, setup your Admin user account.

Step 6: Set your configuration values and click on Save Config.

Step 7: You’ve successfully completed the setup, now click on Launch Website.


CONCLUSION

We hope that by following our DIY guide, you will be able to create your custom
Laravel Web Installer for your web project. Web Installers are really helpful
and it helps us to deploy our Laravel software in easy way.

If you are having some questions regarding the code we’ve written in this
article, feel free to drop your comments in the comments section.


RELATED

LARAVEL INTERVIEW QUESTIONS

Following are frequently asked Laravel and PHP related interview questions for
freshers as well as experienced candidates to get the right job. Top 90+ Laravel
Interview Questions & Answers Following are frequently asked Laravel and PHP
related interview questions for freshers as well as experienced candidates to
get the right…

WHY HIRING AN EXPERIENCED LARAVEL DEVELOPER IS KEY TO YOUR SUCCESS

In the ever-evolving landscape of web development, choosing the right framework
is pivotal to the success of your projects. Laravel, known for its elegance and
developer-friendly features, has emerged as a preferred choice for building
robust and scalable web applications. However, the true magic lies not just in
the framework…

WHY YOU SHOULD HIRE AN EXPERIENCED LARAVEL DEVELOPER FOR YOUR NEXT PROJECT

In the fast-paced world of web development, choosing the right technology stack
is crucial for the success of your project. Laravel, a powerful PHP framework,
has gained immense popularity for its elegant syntax, robust features, and
developer-friendly environment. However, to harness the full potential of
Laravel, it's essential to hire…

Copy URL URL Copied
sachin bharmoria Send an email June 16, 2022Last Updated: June 16, 2022
0 70 13 minutes read

Facebook Twitter LinkedIn Pinterest Reddit WhatsApp Share via Email Print


SACHIN BHARMORIA





READ NEXT

Laravel
October 24, 2023


WHY YOU SHOULD HIRE AN EXPERIENCED LARAVEL DEVELOPER FOR YOUR NEXT PROJECT

JavaScript
November 12, 2023


WHAT IS DOMAIN AND SUBDOMAIN IN WEBSITE DEVELOPMENT?

Programming
November 10, 2023


WHY SHOULD WE HAVE A WEBSITE FOR OUR BUSINESS AND HOW IT WILL BE HELPFUL IN OUR
SALES?

Laravel
November 10, 2023


WHAT IS THE EASIEST WAY TO BUILD AN E-COMMERCE WEBSITE?

Laravel
November 9, 2023


HIRE LARAVEL DEVELOPER AT $5 PER HOUR

Programming
November 5, 2023


WHAT IS SEO AND HOW SEP HELPS TO GROW OUR WEBSITE?

Programming
November 4, 2023


WHY IS MY WEBSITE SLOW AND HOW TO OPTIMIZE IT FOR SMOOTH PERFORMANCE?

Digital Marketing
November 4, 2023


IMPORTANCE OF WEBSITE IN BUSINESS

Laravel
November 2, 2023


WHY CHOOSE A LAMP STACK WITH EXAMPLES

Programming
November 2, 2023


BENEFITS OF CONTRACTING OUT SOFTWARE DEVELOPMENT WORK TO INDIA

Laravel
October 24, 2023


WHY YOU SHOULD HIRE AN EXPERIENCED LARAVEL DEVELOPER FOR YOUR NEXT PROJECT

JavaScript
November 12, 2023


WHAT IS DOMAIN AND SUBDOMAIN IN WEBSITE DEVELOPMENT?

 * 
 * 

November 4, 2023


IMPORTANCE OF WEBSITE IN BUSINESS

November 2, 2023


WHY CHOOSE A LAMP STACK WITH EXAMPLES

November 2, 2023


BENEFITS OF CONTRACTING OUT SOFTWARE DEVELOPMENT WORK TO INDIA

October 24, 2023


WHY YOU SHOULD HIRE AN EXPERIENCED LARAVEL DEVELOPER FOR YOUR NEXT PROJECT

November 12, 2023


WHAT IS DOMAIN AND SUBDOMAIN IN WEBSITE DEVELOPMENT?

November 10, 2023


WHY SHOULD WE HAVE A WEBSITE FOR OUR BUSINESS AND HOW IT WILL BE HELPFUL IN OUR
SALES?

November 10, 2023


WHAT IS THE EASIEST WAY TO BUILD AN E-COMMERCE WEBSITE?

November 9, 2023


HIRE LARAVEL DEVELOPER AT $5 PER HOUR

November 5, 2023


WHAT IS SEO AND HOW SEP HELPS TO GROW OUR WEBSITE?

November 4, 2023


WHY IS MY WEBSITE SLOW AND HOW TO OPTIMIZE IT FOR SMOOTH PERFORMANCE?

November 4, 2023


IMPORTANCE OF WEBSITE IN BUSINESS

November 2, 2023


WHY CHOOSE A LAMP STACK WITH EXAMPLES

November 2, 2023


BENEFITS OF CONTRACTING OUT SOFTWARE DEVELOPMENT WORK TO INDIA

October 24, 2023


WHY YOU SHOULD HIRE AN EXPERIENCED LARAVEL DEVELOPER FOR YOUR NEXT PROJECT

November 12, 2023


WHAT IS DOMAIN AND SUBDOMAIN IN WEBSITE DEVELOPMENT?

November 10, 2023


WHY SHOULD WE HAVE A WEBSITE FOR OUR BUSINESS AND HOW IT WILL BE HELPFUL IN OUR
SALES?

November 10, 2023


WHAT IS THE EASIEST WAY TO BUILD AN E-COMMERCE WEBSITE?

November 9, 2023


HIRE LARAVEL DEVELOPER AT $5 PER HOUR

Thanks For Reading Our Blog Post


ARE YOU LOOKING FOR WEBSITE/APP DEVELOPMENT WILL DO IT FOR $5 PER HOUR

Don't think too much let's begin.


DETECT MOBILE OR DESKTOP IN LARAVEL


REVERSE STRING IN PYTHON (6 DIFFERENT WAYS)


RELATED ARTICLES


WHAT’S NEW IN LARAVEL 7.12

May 23, 2020


LARAVEL-HOW TO USE INSTAGRAM FEED IN LARAVEL WITH EXAMPLE

November 6, 2021


HOW TO ADD COLUMNS TO THE EXISTING TABLE IN LARAVEL THROUGH MIGRATION

May 30, 2020


PAYTM PAYMENT GATEWAY INTEGRATION WITH LARAVEL 7

March 11, 2020


LEAVE A REPLY CANCEL REPLY

Your email address will not be published. Required fields are marked *

Comment *

Name *

Email *

Website

Save my name, email, and website in this browser for the next time I comment.

Notify me of follow-up comments by email.

Notify me of new posts by email.





Δ

Check Also
Close
 * Laravel
   Run laravel project on different port
   March 19, 2022

Advertisement


What Our Customer Speaks
CodeHunger Private Limited
5.0
Based on 43 reviews

review us on
harsh singh
2 months ago

I've been working with Codehunger for the past two years, and I'm consistently
impressed with their level of expertise and commitment to client satisfaction.
Their team is knowledgeable, professional, and always willing to go the extra
mile.The software solutions they've provided have greatly improved our
operational efficiency. Their products are robust, user-friendly, and they
regularly roll out updates that enhance functionality.Moreover, their customer
support is top-notch. Whenever we encounter an issue, their response time is
remarkably quick, and they work diligently to find a solution. It's clear they
genuinely care about their clients.Overall, I highly recommend Codehunger to any
business in need of reliable, innovative IT solutions and exceptional customer
service.
swapnil krishna
2 months ago

Code hunger is highly recommendable when it comes to timely delivery and hassle
free diployment of the brief. They have the zeal to deliver as if it was all
theirs only
Nikita Mishra
2 months ago


ramashish tomar
2 months ago

I recently worked with codehunger team and they deliver a amazing website.
swati kumari
2 months ago

This evaluates the effectiveness, reliability, and performance of the software
products developed by the codehunger.ThanksSwati
Corebhr Technologies Pvt. Ltd.
2 months ago

They have developed call managing software for our business, the software really
help us to automate many of the task,Really love the task done by codehunger
team
Riddhi Roy
2 months ago

I think codehunger is one of the best company to outsource project with them,
unprecedented services provided by the team to deliver the work on time.
Sumit kumar
2 months ago

Best android app development company in patna, do the work at very reasonable
cost.
Shaiv Roy
2 months ago

Working in codehunger since inception, I love the work life balance managed by
the organization.



Recent Posts
 * How to Boost Website SEO
 * As a React Native Developer, How can I Increase the Performance of an React
   Native App
 * Unleashing Success: The Power of Ecommerce Development Companies
 * What Developer Need To Do To Make the Website Run Smoothly?
 * How to Hire Experienced App Developer at Low Cost


Our latest Works
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 


Are you thinking of app development ?


 * Recent
 * Popular
 * Comments

 * How to Boost Website SEO
   4 weeks ago
 * As a React Native Developer, How can I Increase the Performance of an React
   Native App
   4 weeks ago
 * Unleashing Success: The Power of Ecommerce Development Companies
   November 16, 2023
 * What Developer Need To Do To Make the Website Run Smoothly?
   November 14, 2023
 * How to Hire Experienced App Developer at Low Cost
   November 14, 2023

 * Learn Odia Language From Hindi
   January 14, 2021
 * Benefits and application of OOP
   February 25, 2021
 * Laravel-How to use Instagram feed in laravel with example
   November 6, 2021
 * Convert numbers to words in laravel
   September 18, 2022
 * Why PHP is known as a scripting language?
   October 13, 2021

 * Mukesh Khatri
   
   I am getting this error on this line : $account = $instagram...

 * Himanshi
   
   Still facing same issue when followed the suggested steps to...

 * Himanshi
   
   Symfony \Component \Mailer \Exception \TransportException PH...

 * Jim
   
   Is there a way to get this to work for multiple forms?...

 * Naren
   
   Great. Thanks, it helped my project. Thank you again....

Subscribe to our channel


Find us on Facebook



Follow Us


codehunger2

Social
 * Facebook
 * Twitter
 * LinkedIn
 * YouTube
 * GitHub
 * Instagram



© Copyright 2023, All Rights Reserved  |  CodeHunger Blog
 * Facebook
 * Twitter
 * LinkedIn
 * YouTube
 * GitHub
 * Instagram

Facebook Twitter LinkedIn Pinterest Share via Email
Back to top button
Close
Search for:

 * Facebook
 * Twitter
 * LinkedIn
 * YouTube
 * GitHub
 * Instagram

About Our Organizations
CodeHunger is the website and App development Company on the other side we also
give solution of programming problem step by step, even we provide video
tutorial for complex program throug our youtube channel for the easy
understanding. We post on Instagram and Facebook to help developers stay up to
date with the latest technologies.

Recent Posts
 * How to Boost Website SEO
 * As a React Native Developer, How can I Increase the Performance of an React
   Native App
 * Unleashing Success: The Power of Ecommerce Development Companies
 * What Developer Need To Do To Make the Website Run Smoothly?
 * How to Hire Experienced App Developer at Low Cost






Close
Search for

WhatsApp us