How To Build A URL Shortener With Laravel, Vuejs and MySQL 2022

    By: Manu
    2 years ago

    In this guide we are going to create URL shortener. Wi will use Laravel 8 and VueJS. So for first of all make sure you have following requirements fulfilled.

    1. Install XAMPP in your computer. Download from here.
    2. Run these commands
    composer require laravel/ui
    
    // For creating login and register pages with VueJS setup.
    
    php artisan ui vue --auth
    
    npm install
    
    npm install vue-loader@^15.9.7 --save-dev --legacy-peer-deps
    npm update vue-loader
    
    // For compiling
    npm run dev or npm run watch
    

    After this now create a project

    Once you have a new project change "welcome.blade.php". file to "urlshortener.blade.php".

    this file code looks like this

    @extends('layouts.app')
    
    
    @section('styles')
    
    
    @endsection
    @section('content')
        <div id="app" class="wrapper_url_shortener">
            <url-shortener authorized-user="{auth()->user()->id ?? null}"></url-shortener>
        </div>
    @endsection
    

    Here we used a vuejs component so create a component with name "UrlShortener.vue". and this file code looks like this.

    <template>
        <div class="container">
            <div class="row">
                <div class="col-md-12">
                    <div class="shortner">
                        <div class="section-heading text-center">
                            <h1>URL Shortener</h1>
                            <br>
                            <div class="py-2" align="center">
                                <div class="pageIntroDescription border border-info p-3 mb-0">
                                     Professinal Url Shortener, Free and Advanced...   
                                </div>
                            </div>
                            <br>
    
    
                            <div v-if="AuthorizedUser">
                                <form action="" class="form">
                                    <div class="input-group">
                                        <input type="text" id="p1" placeholder="Put Url here"
                                         v-model="url" class="form-control
                                        addUrlInput">
                                    </div>
                                    <br>
                                    <div>
                                        <button class="btn btn-dark"
                                        v-on:click.prevent='shortenUrl'>
                                            Process Url
                                        </button>
                                    </div>
                                </form>
                                <br>
                                <p v-if="!urlNotFound" class="alert alert-danger">
                                    Url is not Valid
                                </p>
                                <div class="copyLink mb-5">
                                    <span id="output_url"></span>
                                    <span id="clipBoard" v-on:click.prevent="copyContent">
                                        {copyTextString}
                                    </span>
                                </div>
                            </div>
                            <div v-else>
                                <h5> You are required to register with us</h5>
                                <hr>
                                To shorten your urls
                                <hr>
                                <a href="/register"> 
                                    <small>
                                        Register Here
                                    </small>
                                </a>
                                or
                                <a href="/login"> 
                                    <small>
                                        Login Here
                                    </small>
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </template>
    
    
    <script>
        export default {
            mounted() {
                console.log('Component mounted.')
            },
            props:['AuthorizedUser'],
            data(){
                return {
                    url:null,
                    urlNotFound: true,
                    copyTextString: 'Copy Text To Clipboard',
                    response:null,
                }
            },
            methods:{
                shortenUrl(){
                    let self = this;
                    let newUrl = self.url;
                    let newArray = newUrl.split('//');
                    let counter = 0;
                    let resultNewUrl = Math.round((Math.pow(36,8) - Math.random() * Math.pow(36, 8))).toString(36).slice(1);
    
    
                    for(let i = 0; i < newArray.length; i++){
                        if(newArray[i] == 'http:' || newArray[i] == 'https:'){
                            counter++;
                        }
    
    
                        if(counter == 0){
                            let newArrayOne = newUrl.split('.');
                            if(newArrayOne[i] == 'www'){
                                counter++;
                            }
    
    
                            let newArrayTwo = newUrl.indexOf('.com');
                            if(newArrayTwo >= 0){
                                counter++;
                            }
                        }
    
    
                        if(counter ==0){
                            self.urlNotFound = false;
                        }else{
                            let currentUrl = window.location.href+'u/'+resultNewUrl;
                            
                            axios.post('/url/shorten',{
                                url: newUrl,
                                shortlink: currentUrl
                            }).then(function(response){
                                self.response = response.data;
                                $('.copyLink').fadeIn(500);
                                $('.copyLink').siblings('.form').find("#p1").val(self.response);
                                //self.url = self.response;
                                console.log(self.response);
                            });
                        }
                    }
                },
                copyContent(){
                    $("#p1").select();
                    this.copyTextString = 'Url Coppied Successfully';
                    document.execCommand("copy");
                    this.url = this.response;
                }
            }
        }
    </script>
    <style scoped>
        .copyLink{
            display:none;
        }
    
    
        #clipBoard{
            display:block;
            margin-top: 28px;
            background-color: #03cbf8;
            color:#fff;
            font-weight: 900;
            font-size:17px;
        }
    
    
        #clipBoard:hover{
            background-color:#333;
        }
    
    
        #clipBoard:visited, #clipBoard:active, #clipBoard:focus{
            background-color:green;
            color:#333;
        }
    
    
    </style>
    


    Mainly we get user url and check if it is valid in function "shortenUrl". and then we store url. We also have a function "copyContent" to allow user copy generated url just by clicking on button.

    Our "routes" are defined in "web.php"

    <?php
    
    
    use Illuminate\Support\Facades\Route;
    use App\Http\Controllers\UrlShortenerController;
    
    
    Route::get('/', function () {
        return view('urlshortener');
    });
    
    
    Auth::routes();
    
    
    Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
    
    
    // redirect to original url.
    
    
    Route::get('/u/{any}', [UrlShortenerController::class, 'handle']);
    
    
    // Store shorten url.
    
    
    Route::post('/url/shorten', [UrlShortenerController::class, 'store']);
    


    Also register you component in "app.js"


    Vue.component('example-component', require('./components/ExampleComponent.vue').default);
    Vue.component('url-shortener', require('./components/UrlShortener.vue').default); // Here we are registering component
    
    
    const app = new Vue({
        el: '#app',
    });
    

    the layout file must have jquery included

    <!doctype html>
    <html lang="{ str_replace('_', '-', app()->getLocale()) }">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    
    
        <!-- CSRF Token -->
        <meta name="csrf-token" content="{ csrf_token() }">
    
    
        <title>{ config('app.name', 'Laravel') }</title>
    
    
        <!-- Scripts -->
        <script src="{ asset('js/app.js') }" defer></script>
    
    
        <!-- Fonts -->
        <link rel="dns-prefetch" href="//fonts.gstatic.com">
        <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
    
    
        <!-- Styles -->
        <link href="{ asset('css/app.css') }" rel="stylesheet">
    
    
        @yield('styles')
    </head>
    <body>
        <div id="app">
            <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
                <div class="container">
                    <a class="navbar-brand" href="{ url('/') }">
                        { config('app.name', 'Laravel') }
                    </a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{ __('Toggle navigation') }">
                        <span class="navbar-toggler-icon"></span>
                    </button>
    
    
                    <div class="collapse navbar-collapse" id="navbarSupportedContent">
                        <!-- Left Side Of Navbar -->
                        <ul class="navbar-nav me-auto">
    
    
                        </ul>
    
    
                        <!-- Right Side Of Navbar -->
                        <ul class="navbar-nav ms-auto">
                            <!-- Authentication Links -->
                            @guest
                                @if (Route::has('login'))
                                    <li class="nav-item">
                                        <a class="nav-link" href="{ route('login') }">{ __('Login') }</a>
                                    </li>
                                @endif
    
    
                                @if (Route::has('register'))
                                    <li class="nav-item">
                                        <a class="nav-link" href="{ route('register') }">{ __('Register') }</a>
                                    </li>
                                @endif
                            @else
                                <li class="nav-item dropdown">
                                    <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                                        { Auth::user()->name }
                                    </a>
    
    
                                    <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                                        <a class="dropdown-item" href="{ route('logout') }"
                                           onclick="event.preventDefault();
                                                         document.getElementById('logout-form').submit();">
                                            { __('Logout') }
                                        </a>
    
    
                                        <form id="logout-form" action="{ route('logout') }" method="POST" class="d-none">
                                            @csrf
                                        </form>
                                    </div>
                                </li>
                            @endguest
                        </ul>
                    </div>
                </div>
            </nav>
    
    
            <main class="py-4">
                @yield('content')
            </main>
        </div>
        <script
        src="https://code.jquery.com/jquery-3.4.1.min.js"
        integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
        crossorigin="anonymous"></script>
    </body>
    </html>