URL Shortener ب Laravel 9 Darija & Vuejs 3 Darija الجزء الثالت

imadbelasri Laravel
LA

فهاد الجزء الثالت من URL Shortener ب Laravel 9 Darija & Vuejs 3 Darija غادي نزيدوا ل components ديالنا لي فيهم الفورم ديال إضافة رابط و عرض جميع الروابط.


نظرة سريعة بالفيديو


1- إضافة ل Model Url

غادي نزيدوا model جديد سميه Url الكود ديال الملف هو :

                                                    
                                                        //
<?php

namespace App\Models;

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

class Url extends Model
{
    use HasFactory;

    protected $fillable = [
        'full_url','shorten_url', 'user_id',
        'url_desc','visits'
    ];

    public function getCreatedAtAttribute($value){
        return Carbon::parse($value)->diffForHumans();
    }

    public function getRouteKeyName()
    {
        return 'shorten_url';
    }
}
                                                    
                                                

2- إضافة ل UrlController

غادي نزيدوا controller جديد سميه UrlController فيه les fonctions ديال عرض إضافة تعديل وحذف رابط.

الكود ديال الملف هو :

                                                        
                                                            //
<?php

namespace App\Http\Controllers;

use App\Models\Url;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Http\Requests\StoreUrlRequest;
use App\Http\Requests\UpdateUrlRequest;

class UrlController extends Controller
{
    //
    public function index($user_id){
        $userUrls = Url::where('user_id', $user_id)->latest()->paginate(4);
        return response()->json($userUrls);
    }

    public function store(StoreUrlRequest $request){
        $url = Url::create([
            'full_url' => $request->full_url,
            'url_desc' => $request->url_desc,
            'shorten_url' => Str::random(),
            'user_id' => $request->user_id,
            'visits' => 0,
        ]);
        return response()->json($url);
    }

    public function show($shorten_url){
        $url = Url::where('shorten_url', $shorten_url)->first();
        $url->increment('visits');
        return redirect($url->full_url);
    }

    public function update(UpdateUrlRequest $request, $shorten_url){
        $url = Url::where('shorten_url', $shorten_url)->first();
        $url->update([
            'full_url' => $request->full_url,
            'url_desc' => $request->url_desc,
            'user_id' => $request->user_id
        ]);
        return response()->json($url);
    }

    public function destroy($shorten_url){
        $url = Url::where('shorten_url', $shorten_url)->first();
        $url->delete();
        return response()->json('deleted');
    }
}
                                                        
                                                    

3- إضافة ل Component CreateLink

داخل dossier js غادي تزيد dossier components فيه زيد fichier CreateLink.vue لي غادي تكون فيه الفورم ديال إضافة رابط جديد.

الكود ديال الملف هو :

                                                        
                                                            //

<template>
  <div class="col-md-7">
    <div class="card my-4">
        <div class="card-body">
            <div class="mb-2" v-if="store.getValidationErrors">
                <ul 
                    v-for="(errorArray, index) in store.getValidationErrors"
                    :key="index"
                    class="list-group">
                    <li 
                        v-for="(error, index) in errorArray"
                        :key="index"
                        class="listgroup-item bg-danger text-white mb-1 p-2 rounded">
                        {{error}}
                    </li>
                </ul>
            </div>
            <form @submit.prevent="store.addLink(user_id)">
                <div class="form-group mb-2">
                    <input 
                        v-model="store.link.data.full_url"
                        type="text" class="form-control" placeholder="Full Url">
                </div>
                <div class="form-group mb-">
                    <textarea 
                        v-model="store.link.data.url_desc"
                        class="form-control mb-2"
                        cols="30" rows="5" placeholder="Description"></textarea>
                </div>
                <div class="form-group" v-if="store.link.updating">
                    <button 
                        @click="store.updateLink(user_id)"
                        type="button" class="btn btn-warning">
                        Update
                    </button>
                    <button 
                        @click="store.cancelEdit"
                        type="button" class="btn btn-danger mx-2">
                        Cancel
                    </button>
                </div>
                <div class="form-group" v-else>
                    <button type="submit" class="btn btn-primary">
                        Submit
                    </button>
                </div>
            </form>
        </div>
    </div>
  </div>
</template>

<script setup>
    import { inject } from 'vue';
    import { useLinkStore } from '@/stores/useLinkStore';

    //get store
    const store = useLinkStore();

    //get user id
    const user_id = inject('user_id');
</script>

<style>

</style>
                                                        
                                                    

4- إضافة ل Component LinksList

دائما داخل dossier components فيه زيد fichier LinksList.vue لي غادي نعرضوا فيه الروابط ديالنا.

الكود ديال الملف هو :

                                                        
                                                            //

<template>
    <div class="col-md-5">
        <div class="card my-4">
            <div class="card-body">
                <h4 class="mb-2 border p-2 rounded">
                    All Links
                </h4>
                <div class="list-group" v-for="link in store.getLinks" :key="link.id">
                    <li @click="data.url_id = link.id"
                        class="list-group-item list-group-item-action" style="cursor:pointer;">
                        <div class="d-flex w-100 justify-content-between">
                            <h6>
                                {{link.shorten_url}}
                            </h6>
                            <small>
                                {{link.created_at}}
                            </small>
                        </div>
                        <div class="mb-1">
                            <div>
                                <p>
                                    {{link.url_desc}}
                                </p>
                                <span class="fw-bold">
                                    {{link.visits}}
                                    <i class="fas fa-eye"></i>
                                </span>
                            </div>
                        </div>
                    </li>
                    <p 
                        v-if="data.url_id === link.id"
                        class="d-flex justify-content-around align-items-center my-2">
                        <button 
                            @click="store.editLink(link)"
                            class="btn btn-warning btn-sm">
                            <i class="fas fa-edit"></i>
                        </button>
                        <button 
                            @click="store.deleteLink(link.shorten_url, user_id)"
                            class="btn btn-danger btn-sm">
                            <i class="fas fa-trash"></i>
                        </button>
                        <button 
                            @click="copy(link.shorten_url)"
                            class="btn btn-dark btn-sm">
                            <i class="fas fa-copy"></i>
                        </button>
                        <a :href="link.full_url" target="_blank" class="btn btn-primary btn-sm">
                            <i class="fas fa-arrow-up-right-from-square"></i>
                        </a>
                    </p>
                </div>
            </div>
            <div class="card-footer bg-white">
                <div class="d-flex justify-content-between">
                    <button 
                        :disabled="!store.links.prev_page_url"
                        @click="store.previous(user_id)"
                        class="btn btn-sm btn-link">
                        <i class="fas fa-chevron-left"></i>
                        <i class="fas fa-chevron-left"></i>
                    </button>
                    <button 
                        :disabled="!store.links.next_page_url"
                        @click="store.next(user_id)"
                        class="btn btn-sm btn-link">
                        <i class="fas fa-chevron-right"></i>
                        <i class="fas fa-chevron-right"></i>
                    </button>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
    import { inject, onMounted, reactive } from "vue";
    import { useLinkStore } from '@/stores/useLinkStore';
    import Swal from 'sweetalert2';

    //get store
    const store = useLinkStore();

    const data = reactive({
        url_id : ''
    });

    const user_id = inject('user_id');

    const copy = (shorten_url) => {
        navigator.clipboard.writeText(`127.0.0.1:8000/visit/${shorten_url}`);
        Swal.fire({
            position: 'top-end',
            icon: 'success',
            title: 'Your link has been copied: ' + shorten_url,
            showConfirmButton: false,
            timer: 2500
        });
    }

    onMounted(() => store.fetchLinks(user_id));
</script>

<style>

</style>