URL Shortener ب Laravel 9 Darija & Vuejs 3 Darija الجزء الثالت
فهاد الجزء الثالت من 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>