24 β Deploy va yakuniy loyiha¶
β¬ οΈ Oldingi: 23 β Caching va performance Β· π README
Bu bobda: o'rgangan hamma narsani bitta to'liq ilovaga jamlab, uni internetga chiqaramiz. Avval real server talablarini (PHP 8.4, Composer, baza, web server), keyin production uchun xavfsiz
.envni (APP_ENV=production,APP_DEBUG=false, kuchliAPP_KEY) ko'rib chiqamiz. Keyin deploy qadamlarini βcomposer install --no-dev,migrate --force,optimize,storage:linkβ birma-bir bajaramiz, Nginx + PHP-FPM ni sozlaymiz va boshqariladigan platformalar (Laravel Forge, Cloud, Vapor) bilan tanishamiz. So'ngra yakuniy loyiha β vazifa-menejerini noldan, migration'dan deploy'gacha bosqichma-bosqich quramiz. Oxirida HTTPS, zero-downtime g'oyasi va keyingi yo'l (Livewire, Inertia, Filament, paket yozish) haqida gaplashamiz.
Muammo¶
Ilovangiz localhostda chiroyli ishlayapti. Lekin php artisan serve faqat sizning kompyuteringizda, faqat siz ochiq turganda ishlaydi. Do'stingizga ko'rsatmoqchisiz β link bera olmaysiz. Mijoz "sayt qani?" deydi β ko'rsatadigan manzil yo'q.
Internetga chiqarish β deploy (joylashtirish) β yangi qiyinchiliklar olib keladi:
- Kompyuteringizda PHP, Composer, baza tayyor turibdi. Serverda esa hech narsa yo'q β hammasini siz o'rnatasiz.
localhostda xato chiqsa, butun stack-trace ekranda ko'rinadi β bu qulay. Lekin internetda har bir mehmon shu xatoni, hatto baza parolini ko'rsa β bu falokat.php artisan servebitta so'rovni qabul qiladi. Internetda bir vaqtning o'zida yuzlab odam kirishi mumkin β bunga Nginx + PHP-FPM kerak.- Yangi versiya yuklayotganda sayt bir lahza "buzilib" qolmasligi kerak β foydalanuvchi buni sezmasligi lozim.
Sof PHP'da bularning hammasini qo'lda, har loyihada qaytadan yozardingiz. Laravel esa deploy uchun aniq, tartibli qadamlar va tayyor buyruqlar beradi. Bu bob ikki qismdan iborat: avval qanday deploy qilish, keyin nimani deploy qilish β ya'ni o'rgangan bilimni jamlaydigan to'liq loyiha.
Server nima talab qiladi?¶
Laravel 13 ilovasini ishga tushirish uchun serverda quyidagilar bo'lishi shart:
- PHP 8.4 (Laravel 13 minimal PHP 8.3 talab qiladi, lekin 8.4 tavsiya etiladi) β kerakli kengaytmalar bilan:
pdo,mbstring,openssl,tokenizer,xml,ctype,json,bcmath,curl,fileinfo. - Composer β paketlarni o'rnatish uchun (1-bobdan tanish).
- Ma'lumotlar bazasi β MySQL, PostgreSQL yoki MariaDB. Kichik loyihaga SQLite ham yetadi.
- Web server β Nginx (tavsiya) yoki Apache, PHP-FPM bilan birga.
π Lokal kompyuteringizda bularning hammasi allaqachon bor (2-bobda o'rnatgansiz). Serverda esa toza Linux (odatda Ubuntu) turadi β siz xuddi shu narsalarni qo'lda yoki Forge kabi vosita orqali o'rnatasiz.
π‘ Kerakli PHP kengaytmalari to'liq mavjudligini tekshirish uchun serverda bitta buyruq yetadi:
Bu PHP'da yoqilgan barcha kengaytmalar ro'yxatini chiqaradi. Ro'yxatda pdo_mysql, mbstring, openssl borligiga ishonch hosil qiling β biror biri yo'q bo'lsa, ilova ishlamaydi.
Production .env β eng muhim fayl¶
localhostda .env faylingiz "yumshoq" sozlangan: xatolar ko'rinadi, debug yoqilgan. Internetda esa bu xavfsizlik teshigi. Production uchun .env butunlay boshqacha bo'lishi kerak:
APP_NAME="Vazifa Menejeri"
APP_ENV=production
APP_KEY=base64:KUCHLI_TASODIFIY_KALIT_BU_YERDA
APP_DEBUG=false
APP_URL=https://mening-saytim.uz
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=vazifalar
DB_USERNAME=app_user
DB_PASSWORD=juda_kuchli_parol
SESSION_DRIVER=database
CACHE_STORE=database
QUEUE_CONNECTION=database
Bu yerda uchta qator hayot-mamot ahamiyatiga ega:
π APP_DEBUG=false β eng muhim sozlama. Agar bu true qolsa, har qanday xato yuz berganda Laravel butun stack-trace'ni, fayl yo'llarini, hatto .env qiymatlarini (baza paroli, API kalitlari) ekranda har bir mehmonga ko'rsatadi. Production'da bu doim false bo'lishi shart. false bo'lganda foydalanuvchi faqat chiroyli "500 β Server Error" sahifasini ko'radi, batafsil xato esa storage/logs/laravel.log ga yoziladi.
π APP_ENV=production β Laravel'ga "men jonli serverdaman" deb aytadi. Ba'zi xavfsizlik tekshiruvlari va ogohlantirishlar shunga qarab ishlaydi.
π APP_KEY β sessiya va shifrlangan ma'lumotlarni himoyalaydigan kalit. Bu bo'sh bo'lmasligi va kuchli (tasodifiy) bo'lishi kerak. Yangi kalit yaratish:
β .env faylini hech qachon Git'ga qo'ymang. Standart Laravel loyihasida .gitignore allaqachon .env ni o'z ichiga oladi β buni o'chirmang. Baza paroli va kalitlar Git tarixiga tushib qolsa, ularni butunlay yangilashga to'g'ri keladi.
β
Buning o'rniga .env.example faylini Git'da saqlang β unda qiymatlarsiz, faqat kalit nomlari turadi. Serverda undan nusxa olib (cp .env.example .env), haqiqiy qiymatlar bilan to'ldirasiz.
Deploy qadamlari β birma-bir¶
Kod serverga yetib bordi (odatda git clone yoki git pull orqali). Endi uni "tiriltirish" uchun aniq tartibda quyidagi buyruqlar bajariladi. Har birini alohida ko'rib chiqamiz.
1-qadam: paketlarni o'rnatish¶
composer install β composer.json dagi paketlarni o'rnatadi (lokal'da ham shunday qilgansiz). Lekin production'da ikkita muhim bayroq qo'shamiz:
--no-devβ faqat ishlash uchun zarur paketlarni o'rnatadi, test va debug paketlarini (require-devbo'limidagilar β masalan Pest, Faker, Debugbar) o'tkazib yuboradi. Serverda test kerak emas, ular faqat joy va xavfsizlik xavfini oshiradi.--optimize-autoloaderβ Composer'ning klass-qidirish jadvalini oldindan tuzib qo'yadi, shunda har so'rovda klasslar tezroq topiladi.
π --no-dev bilan o'rnatganingizdan keyin Faker yoki Pest ishlatadigan kodni production'da chaqirsangiz, "class not found" xatosi chiqadi. Shuning uchun seeder'lardagi fake() faqat lokal/test uchun β production migratsiyasida ishlatilmaydi.
2-qadam: migratsiyalarni bajarish¶
Bu baza jadvallarini yaratadi/yangilaydi (7-bobdan tanish). Yangi bayroq:
π --force β production'da (APP_ENV=production) Laravel migratsiyani bajarishdan oldin "Rostdan ham? Bu jonli baza!" deb so'raydi, chunki migratsiya ma'lumotni o'zgartirishi mumkin. --force bu savolni o'tkazib yuboradi β avtomatik deploy skriptlari uchun zarur, chunki u yerda javob beradigan odam yo'q.
β migrate:fresh yoki migrate:refresh ni production'da hech qachon ishlatmang β ular barcha jadvalni o'chirib qaytadan yaratadi, ya'ni hamma real ma'lumot yo'qoladi. Production'da faqat migrate --force (yangi migratsiyalarni qo'shadi, eskisiga tegmaydi).
3-qadam: optimallashtirish (cache)¶
Bu bitta buyruq bir nechta cache yaratadi: konfiguratsiya (config:cache), marshrutlar (route:cache), hodisalar (event:cache). Natijada Laravel har so'rovda config va route fayllarini qaytadan o'qimaydi β oldindan tuzilgan tezkor nusxani ishlatadi. Bu production'da sezilarli tezlik beradi.
π Diqqat: config:cache ishlaganidan keyin Laravel .env ni boshqa o'qimaydi β faqat cache'langan config'ni ishlatadi. Shuning uchun .env ni o'zgartirsangiz, cache'ni yangilash shart:
π‘ Lokal'da rivojlanayotganda optimize ishlatmang β config'ni har o'zgartirganda cache eskirib, "nega o'zgarishim ko'rinmayapti?" degan jumboq paydo bo'ladi. optimize β faqat production uchun.
4-qadam: storage havolasi¶
18-bobdan eslang: foydalanuvchi yuklagan fayllar storage/app/public da turadi, lekin brauzer faqat public/ papkani ko'radi. Bu buyruq public/storage β storage/app/public simvolik havolasini yaratib, fayllarni brauzerga ochadi. Yangi serverda bu havola yo'q β shuning uchun deploy'da bir marta bajariladi.
Hammasini birga β deploy skripti¶
Amalda bu qadamlar bitta skriptga jamlanadi. Mana tipik deploy.sh:
#!/bin/bash
set -e # biror buyruq xato bersa, butun skript to'xtaydi
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize
php artisan storage:link
php artisan queue:restart # eski queue worker'larni yangi kod bilan qayta ishga tushirish
π set -e muhim: agar composer install xato bersa, skript shu yerda to'xtaydi va buzuq kod bilan migrate qilib qo'ymaydi.
π php artisan queue:restart β 20-bobni eslang: queue worker'lar fon jarayoni sifatida uzluksiz ishlaydi va eski kodni xotirada saqlaydi. Bu buyruq ularga "joriy ishni tugatib, yangi kod bilan qayta tug'iling" signalini beradi.
Web server: Nginx + PHP-FPM¶
php artisan serve β faqat rivojlanish uchun. Production'da Nginx so'rovlarni qabul qiladi va PHP fayllarni PHP-FPM ga uzatadi. Tipik Nginx konfiguratsiyasi:
server {
listen 80;
server_name mening-saytim.uz;
root /var/www/vazifalar/public; # DIQQAT: public/ ga ishora qiladi
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}
π Eng muhim qator: root .../public. Web server ildizi loyiha papkasiga emas, balki uning ichidagi public/ papkaga ishora qilishi shart. Faqat public/ brauzerga ochiq bo'ladi β .env, app/, vendor/ esa yashirin qoladi. Agar root ni loyiha ildiziga qo'ysangiz, har kim mening-saytim.uz/.env ni ochib baza parolingizni o'qiy oladi β bu jiddiy xato.
π try_files ... /index.php β Laravel'ning "bitta kirish nuqtasi" (single entry point) tamoyili: barcha so'rovlar public/index.php orqali o'tadi, u esa marshrutlarga (3-bobdagi routes/) yo'naltiradi.
Boshqariladigan platformalar β osonroq yo'l¶
Nginx, PHP-FPM, SSL'ni qo'lda sozlash mumkin, lekin bu vaqt va xatolar olib keladi. Laravel jamoasi buni yengillashtiradigan rasmiy vositalar taklif qiladi:
- Laravel Forge β siz oddiy VPS server (DigitalOcean, Hetzner va h.k.) berasiz, Forge unga Nginx, PHP, MySQL, SSL'ni o'rnatib, deploy tugmasini beradi. Server siznikida qoladi, sozlash Forge'da.
- Laravel Cloud β to'liq boshqariladigan platforma: server umuman ko'rinmaydi, siz faqat kodni push qilasiz, qolganini platforma qiladi (avtomatik masshtablash bilan).
- Laravel Vapor β AWS'da "serversiz" (serverless) deploy. Juda katta yuklamaga avtomatik moslashadi, lekin sozlash murakkabroq.
π‘ Boshlovchi uchun tartib shunday: avval qo'lda (VPS + Nginx) bir marta deploy qilib, ichki mexanikani his qiling. Keyin real loyihalarda Forge yoki Cloud bilan vaqtni tejang. Sehrni tushunmasdan turib avtomatlashtirishga ishonmaslik kerak.
HTTPS β majburiy talab¶
Bugun HTTPS (qulfli yashil "https://") β majburiy. Usiz brauzerlar "Bu sayt xavfsiz emas" ogohlantirishini ko'rsatadi, login parollari shifrlanmagan holda uzatiladi.
Yaxshi yangilik: bepul. Let's Encrypt sertifikatlari tekin va Forge/Cloud avtomatik o'rnatadi. Qo'lda esa certbot vositasi bir buyruqda hal qiladi.
Laravel tomonida bitta sozlash kerak: .env da APP_URL ni https:// bilan yozing va AppServiceProvider da production'da HTTPS'ni majburlang:
namespace App\Providers;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
if ($this->app->environment('production')) {
URL::forceScheme('https');
}
}
}
π URL::forceScheme('https') β Laravel yaratadigan barcha havolalar (route(), url(), asset URL'lar) https:// bilan boshlanishini kafolatlaydi. Busiz aralash (mixed) kontent muammosi chiqishi mumkin: sahifa HTTPS, lekin ichidagi rasm HTTP β brauzer bloklab qo'yadi.
Zero-downtime g'oyasi¶
"Zero-downtime deploy" β yangi versiyani chiqarganda saytning bir lahza ham "o'lmasligi". Oddiy deploy'da git pull paytida fayllar yarmi yangi, yarmi eski bo'lib, foydalanuvchi xato ko'rishi mumkin.
Asosiy g'oya β atomik almashtirish: yangi versiya butunlay alohida papkaga tayyorlanadi, faqat hammasi tayyor bo'lgach, bitta lahzada "joriy" havolasi yangi papkaga o'tkaziladi:
/var/www/vazifalar/
βββ releases/
β βββ 2026-06-10-153000/ <- eski versiya
β βββ 2026-06-11-100000/ <- yangi versiya (to'liq tayyor)
βββ current -> releases/2026-06-11-100000/ <- bitta havola almashadi
βββ shared/
βββ .env <- versiyalar orasida umumiy
βββ storage/ <- yuklangan fayllar yo'qolmaydi
π Forge, Cloud, Vapor va Envoyer kabi vositalar buni avtomatik qiladi. Qo'lda qilish murakkab, shuning uchun boshlovchi uchun: avval oddiy deploy bilan boshlang (kichik sayt uchun bir necha soniya "downtime" katta muammo emas), keyin loyiha o'sganda zero-downtime'ga o'ting.
YAKUNIY LOYIHA: vazifa-menejeri (noldan deploy'gacha)¶
Endi eng qiziq qism β o'rgangan hamma narsani bitta loyihada birlashtiramiz. Quramiz: oddiy vazifa-menejeri (task manager). Har foydalanuvchi tizimga kiradi (auth), o'z vazifalarini qo'shadi, ko'radi, tahrirlaydi, o'chiradi (CRUD), faqat o'zinikini ko'radi (avtorizatsiya), forma tekshiriladi (validatsiya), kodni test bilan tasdiqlaymiz va deploy qilamiz.
Bu β kichraytirilgan, lekin to'liq Laravel ilova skeleti. Real loyihalar (blog, do'kon, CRM) aynan shu qatlamlardan iborat.
1-bosqich: loyihani yaratish¶
π laravel new so'raganda autentifikatsiya starter kit'ni (masalan Livewire yoki React) tanlash mumkin β bu bizga tayyor login/register sahifalarini beradi (13-bobdan tanish). Bu yerda mantiqni ko'rsatish uchun starter kit borligini nazarda tutamiz; siz tanlamagan bo'lsangiz, routes/web.php da oddiy auth marshrutlari ham yetadi.
2-bosqich: migratsiya (jadval tuzilishi)¶
Vazifalar jadvalini yaratamiz:
-m migratsiyani ham yaratadi. Migratsiya faylini to'ldiramiz (7-bobdan tanish):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->text('description')->nullable();
$table->boolean('is_done')->default(false);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('tasks');
}
};
π foreignId('user_id')->constrained()->cascadeOnDelete() β har vazifa bitta foydalanuvchiga tegishli; foydalanuvchi o'chsa, uning vazifalari ham o'chadi (9-bobdagi munosabat va 7-bobdagi cascade).
3-bosqich: model va munosabat¶
app/Models/Task.php:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Task extends Model
{
protected $fillable = ['title', 'description', 'is_done'];
protected function casts(): array
{
return ['is_done' => 'boolean'];
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
app/Models/User.php ga teskari munosabatni qo'shamiz:
use Illuminate\Database\Eloquent\Relations\HasMany;
public function tasks(): HasMany
{
return $this->hasMany(Task::class);
}
π $fillable da user_id yo'q β buni ataylab qildik: foydalanuvchi formada user_id jo'natib boshqaning vazifasini "egallab" olmasligi uchun (8-bobdagi mass-assignment himoyasi). user_id ni kodda, ishonchli manbadan ($request->user()) o'rnatamiz.
4-bosqich: marshrut va kontroller¶
routes/web.php:
use App\Http\Controllers\TaskController;
Route::resource('tasks', TaskController::class)
->middleware('auth');
π ->middleware('auth') β barcha vazifa marshrutlari faqat tizimga kirganlarga ochiq (15-bobdagi middleware). Tashqaridan kirmoqchi bo'lgan login sahifasiga yo'naltiriladi.
Kontroller (app/Http/Controllers/TaskController.php) β yurakdagi mantiq:
namespace App\Http\Controllers;
use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Gate;
use Illuminate\View\View;
class TaskController extends Controller
{
public function index(Request $request): View
{
$tasks = $request->user()->tasks()->latest()->get();
return view('tasks.index', ['tasks' => $tasks]);
}
public function create(): View
{
return view('tasks.create');
}
public function store(Request $request): RedirectResponse
{
$data = $request->validate([
'title' => ['required', 'string', 'max:255'],
'description' => ['nullable', 'string'],
]);
$request->user()->tasks()->create($data);
return redirect()->route('tasks.index')
->with('status', 'Vazifa qoshildi.');
}
public function edit(Task $task): View
{
Gate::authorize('update', $task);
return view('tasks.edit', ['task' => $task]);
}
public function update(Request $request, Task $task): RedirectResponse
{
Gate::authorize('update', $task);
$data = $request->validate([
'title' => ['required', 'string', 'max:255'],
'description' => ['nullable', 'string'],
'is_done' => ['boolean'],
]);
$task->update($data);
return redirect()->route('tasks.index')
->with('status', 'Vazifa yangilandi.');
}
public function destroy(Task $task): RedirectResponse
{
Gate::authorize('delete', $task);
$task->delete();
return redirect()->route('tasks.index')
->with('status', 'Vazifa ochirildi.');
}
}
π $request->user()->tasks()->create($data) β vazifa avtomatik joriy foydalanuvchiga bog'lanadi, user_id qo'lda yozilmaydi. Bu yondashuv mass-assignment xavfini ham, xatoni ham yo'qotadi.
π $request->user()->tasks()->latest()->get() β index faqat joriy foydalanuvchining vazifalarini oladi. Boshqaning vazifasi umuman so'ralmaydi β bu birinchi himoya qatlami.
5-bosqich: avtorizatsiya (Policy)¶
Ikkinchi himoya qatlami β Policy (14-bobdan tanish). U edit/update/destroy da "bu aynan o'sha foydalanuvchimi?" deb tekshiradi:
app/Policies/TaskPolicy.php:
namespace App\Policies;
use App\Models\Task;
use App\Models\User;
class TaskPolicy
{
public function update(User $user, Task $task): bool
{
return $user->id === $task->user_id;
}
public function delete(User $user, Task $task): bool
{
return $user->id === $task->user_id;
}
}
π $user->id === $task->user_id β vazifa egasi joriy foydalanuvchi bo'lsagina true. Kontrollerdagi Gate::authorize('update', $task) shu metodni chaqiradi; mos kelmasa Laravel 403 Forbidden qaytaradi. Shunday qilib, URL'da boshqaning vazifa ID'sini qo'lda yozsa ham (masalan /tasks/99/edit), tizim ruxsat bermaydi.
6-bosqich: Blade ko'rinishlari¶
resources/views/tasks/index.blade.php:
@extends('layouts.app')
@section('content')
<h1>Mening vazifalarim</h1>
@if (session('status'))
<p style="color:green">{{ session('status') }}</p>
@endif
<a href="{{ route('tasks.create') }}">+ Yangi vazifa</a>
<ul>
@forelse ($tasks as $task)
<li>
<strong>{{ $task->title }}</strong>
@if ($task->is_done) (bajarildi) @endif
<a href="{{ route('tasks.edit', $task) }}">Tahrirlash</a>
<form action="{{ route('tasks.destroy', $task) }}" method="POST"
style="display:inline">
@csrf
@method('DELETE')
<button type="submit">Ochirish</button>
</form>
</li>
@empty
<li>Hali vazifa yoq. Birinchisini qoshing!</li>
@endforelse
</ul>
@endsection
resources/views/tasks/create.blade.php:
@extends('layouts.app')
@section('content')
<h1>Yangi vazifa</h1>
<form action="{{ route('tasks.store') }}" method="POST">
@csrf
<label>Sarlavha</label>
<input type="text" name="title" value="{{ old('title') }}">
@error('title')
<p style="color:red">{{ $message }}</p>
@enderror
<label>Tavsif</label>
<textarea name="description">{{ old('description') }}</textarea>
<button type="submit">Saqlash</button>
</form>
@endsection
π @method('DELETE') β HTML formalar faqat GET/POST'ni biladi, shuning uchun DELETE/PUT uchun bu yashirin maydon kerak (5 va 6-boblardan tanish). @csrf esa har formada β busiz 419 xatosi chiqadi.
π old('title') β validatsiya o'tmay forma qaytsa, foydalanuvchi yozgani yo'qolmaydi (12-bobdan tanish).
7-bosqich: test¶
Deploy'dan oldin asosiy oqimni test bilan tasdiqlaymiz (22-bobdan tanish). Pest test:
use App\Models\Task;
use App\Models\User;
test('foydalanuvchi vazifa qosha oladi', function () {
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/tasks', [
'title' => 'Sut sotib olish',
'description' => 'Magazindan',
]);
$response->assertRedirect('/tasks');
$this->assertDatabaseHas('tasks', [
'title' => 'Sut sotib olish',
'user_id' => $user->id,
]);
});
test('foydalanuvchi boshqaning vazifasini ochira olmaydi', function () {
$egasi = User::factory()->create();
$begona = User::factory()->create();
$task = Task::factory()->for($egasi)->create();
$response = $this->actingAs($begona)->delete("/tasks/{$task->id}");
$response->assertForbidden(); // 403
$this->assertDatabaseHas('tasks', ['id' => $task->id]); // ochirilmagan
});
π Ikkinchi test β eng muhimi: avtorizatsiya haqiqatan ishlashini tasdiqlaydi. Begona foydalanuvchi 403 oladi va vazifa o'chmaydi. Bu testsiz, xavfsizlik teshigini sezmay qolish oson.
8-bosqich: deploy¶
Endi bobning birinchi qismidagi qadamlar bilan loyihani serverga chiqaramiz:
# Serverda, birinchi marta:
git clone https://github.com/foydalanuvchi/vazifalar.git
cd vazifalar
cp .env.example .env
# .env ni production qiymatlari bilan to'ldiring (APP_DEBUG=false va h.k.)
composer install --no-dev --optimize-autoloader
php artisan key:generate
php artisan migrate --force
php artisan optimize
php artisan storage:link
Nginx'ni public/ ga yo'naltiring, HTTPS'ni yoqing β va sayt jonli! Keyingi har yangilanishda yuqoridagi deploy.sh skriptini ishlatasiz.
β Tabriklaymiz β siz to'liq Laravel ilovani noldan deploy'gacha qurdingiz: migration -> model -> munosabat -> controller -> validatsiya -> avtorizatsiya -> Blade -> test -> deploy. Bu skelet ustiga endi xohlagan loyihangizni qurishingiz mumkin.
Keyingi yo'l β bu yer manzil emas, boshlanish¶
Kitob tugadi, lekin Laravel olami katta. Mana qayerga borish mumkin:
- Livewire / Inertia.js β JavaScript yozmasdan (Livewire) yoki Vue/React bilan (Inertia) zamonaviy, "jonli" interfeyslar yaratish. Sahifa qayta yuklanmasdan yangilanadi.
- Filament β admin-panel va boshqaruv interfeyslarini deyarli kod yozmasdan quradigan kuchli vosita. CRUD panellar daqiqalarda tayyor bo'ladi.
- Paket yozish β o'z kodingizni qayta ishlatiladigan Composer paketiga aylantirib, butun jamiyat bilan ulashish.
- Chuqurroq mavzular β Broadcasting (real-time), Octane (juda yuqori tezlik), Horizon (queue boshqaruvi), Pennant (feature flags), Telescope (debug).
π‘ Eng yaxshi o'rganish yo'li β real loyiha qurish. O'zingizga kerakli bir narsani (shaxsiy blog, byudjet hisoblagich, kichik do'kon) tanlang va uni boshidan oxirigacha quring. Tiqilib qolganingizda rasmiy hujjat (laravel.com/docs) va bu kitobning tegishli bobiga qayting. Omad!
24-bob mashqlari¶
Quyidagi mashqlarni bajaring β birinchilari deploy konfiguratsiyasiga, oxirgilari to'liq loyiha qurishga oid. Har biri oldingisidan bir qadam murakkabroq. Yechimlarini o'zingiz yozing.
- Yangi loyiha yaratib,
.envfaylidan nusxa oling (.env.productiondeb) va undagiAPP_ENVniproduction,APP_DEBUGnifalseqiling; ikki fayl orasidagi farqni o'zingiz uchun ro'yxatlang. - Loyihada ataylab xato yarating (masalan kontrollerda mavjud bo'lmagan metod chaqiring).
APP_DEBUG=trueda brauzerda nima ko'rinishini,APP_DEBUG=falseda nima ko'rinishini solishtiring va farqni yozib qoying. php artisan key:generateni ishlating va.envdagiAPP_KEYo'zgarganini tekshiring; kalitbase64:bilan boshlanishini tasdiqlang..gitignorefaylida.envborligini tekshiring;git statusbajarib.env"untracked" ro'yxatida ko'rinmasligiga ishonch hosil qiling.php artisan optimizeni ishlatibbootstrap/cache/ichida config va route cache fayllari paydo bo'lganini ko'ring; keyinphp artisan optimize:clearbilan ularni tozalang va papka bo'shaganini tekshiring.config:cacheqilingandan keyin.envdaAPP_NAMEni o'zgartiring va saytda o'zgarish ko'rinmasligini kuzating;optimize:cleardan keyin o'zgarish ko'rinishini tasdiqlang (bu nega muhimligini izohlang).composer install --no-devni ishlating vavendor/ichidapestphpyokifakerphppapkalari yo'qolganini tekshiring; keyin oddiycomposer installbilan ular qaytib kelishini ko'ring.- Test bazasi yaratib (yoki SQLite),
php artisan migrate --forceni ishlating;--forcesizproductionmuhitida buyruq tasdiq so'rashini kuzating. php artisan storage:linkni ishlating vapublic/storagesimvolik havolasi yaratilganini tekshiring; havolani o'chirib qayta yaratib ko'ring.AppServiceProvider::boot()da production'daURL::forceScheme('https')ni qo'shing;app('env')qiymatini o'zgartirib, faqatproductionda bu ishlashini tekshiring.- Yuqoridagi
deploy.shskriptini yozing,set -eqatorini qo'shing va biror buyruqni ataylab xato qilib, skript shu yerda to'xtashini tasdiqlang. - Nginx konfiguratsiya namunasini yozing va
rootqatorini loyiha ildiziga (public/siz) qo'yib ko'ring β.envbrauzerda ochilishini (lokal sinov serverida) kuzating, keyinrootnipublic/ga qaytaring. - Yakuniy loyihani boshlang:
Taskmodeli va migratsiyasiniuser_id,title,description,is_doneustunlari bilan yarating vamigrateqiling. TaskmodeligabelongsTo(User::class)vaUsermodeligahasMany(Task::class)munosabatlarini qo'shing; Tinker'daUser::first()->tasksishlashini tekshiring.TaskControllerni--resource --model=Taskbilan yarating vaRoute::resource('tasks', ...)->middleware('auth')ni qo'shing;php artisan route:list --path=tasksbilan 7 marshrutni ko'ring.storemetodida validatsiya (titlemajburiy,max:255) qo'shing va$request->user()->tasks()->create(...)orqali vazifani joriy foydalanuvchiga bog'lang; brauzerda yangi vazifa qo'shib sinang.TaskPolicyyarating,updatevadeletemetodlarida$user->id === $task->user_idtekshiruvini yozing va kontrollerdaGate::authorize(...)ni chaqiring (use Illuminate\Support\Facades\Gate;); URL'da boshqaning vazifa ID'sini ochib403kelishini tasdiqlang.tasks.indexvatasks.createBlade ko'rinishlarini yozing:@forelsebilan vazifalar ro'yxati,@csrfva@method('DELETE')bilan o'chirish formasi,@errorbilan validatsiya xabarlari.- Pest testlarini yozing: (a) foydalanuvchi vazifa qo'sha oladi (
assertDatabaseHas), (b) begona foydalanuvchi boshqaning vazifasini o'chira olmaydi (assertForbidden);php artisan testbilan ikkalasi o'tishini tasdiqlang. - To'liq loyihani sinov serveriga (yoki bepul platformaga) deploy qiling:
git clone->.envto'ldirish (APP_DEBUG=false) ->composer install --no-dev->key:generate->migrate --force->optimize->storage:link; saytni HTTPS bilan brauzerda ochib, vazifa qo'shishni jonli serverda sinang.