Laravel 11: Budowa kompletnej aplikacji od podstaw

Kompleksowy przewodnik po budowie aplikacji w Laravel 11 z uwierzytelnianiem, REST API, Eloquent ORM i wdrożeniem produkcyjnym. Praktyczny poradnik dla początkujących i średnio zaawansowanych programistów.

Poradnik Laravel 11 dotyczący budowy kompletnej aplikacji

Laravel 11 redefiniuje nowoczesne programowanie w PHP dzięki uproszczonej architekturze i zoptymalizowanej wydajności. Ta główna wersja usuwa wiele domyślnych plików konfiguracyjnych, wprowadza lżejszą strukturę projektu i znacząco poprawia komfort pracy programisty. Niniejszy przewodnik prowadzi przez budowę kompletnej aplikacji do zarządzania zadaniami — od instalacji po wdrożenie produkcyjne.

Najważniejsze zmiany w Laravel 11

Laravel 11 przyjmuje minimalistyczną strukturę: brak plików Kernel, skonsolidowana konfiguracja w bootstrap/app.php i czystszy katalog app/. Framework wymaga minimalnie PHP 8.2 i natywnie integruje SQLite do szybkiego startu.

Instalacja i konfiguracja projektu

Laravel 11 instaluje się przez Composer lub dedykowany instalator Laravel. Nowa struktura projektu jest lżejsza, z mniejszą liczbą plików konfiguracyjnych do zarządzania od samego początku.

bash
# terminal
# Install the Laravel installer (recommended)
composer global require laravel/installer

# Create a new Laravel 11 project
laravel new task-manager

# Or directly with Composer
composer create-project laravel/laravel task-manager

# Navigate to the project
cd task-manager

Instalator oferuje kilka interaktywnych opcji: wybór starter kitu (Breeze, Jetstream), frameworka testowego (Pest, PHPUnit) i bazy danych.

bash
# terminal
# Start the development server
php artisan serve

# Server starts at http://localhost:8000

Konfiguracja bazy danych

Laravel 11 domyślnie używa SQLite, co jest idealne do pracy deweloperskiej. W przypadku aplikacji produkcyjnych konfiguracja MySQL lub PostgreSQL odbywa się w pliku .env.

env
# .env
# MySQL configuration
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=task_manager
DB_USERNAME=root
DB_PASSWORD=secret

# PostgreSQL configuration (alternative)
# DB_CONNECTION=pgsql
# DB_HOST=127.0.0.1
# DB_PORT=5432
# DB_DATABASE=task_manager
# DB_USERNAME=postgres
# DB_PASSWORD=secret

Weryfikacja połączenia z bazą danych odbywa się za pomocą komendy Artisan.

bash
# terminal
# Verify database connection
php artisan db:show

# Run default migrations
php artisan migrate

Tworzenie modeli i migracji

Eloquent ORM upraszcza manipulację danymi dzięki ekspresyjnym modelom. Komenda make:model generuje model, migrację, kontroler i fabrykę za jednym razem.

bash
# terminal
# Generate Task model with migration, factory, seeder, and controller
php artisan make:model Task -mfsc

# -m : migration
# -f : factory
# -s : seeder
# -c : controller

Ta komenda tworzy cztery niezbędne pliki do kompletnego zarządzania zadaniami.

php
<?php
// database/migrations/2026_01_14_000000_create_tasks_table.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

// Migration to create the tasks table
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('tasks', function (Blueprint $table) {
            // Auto-incrementing primary key
            $table->id();
            // Relationship with the owner user
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            // Task title (required)
            $table->string('title');
            // Detailed description (optional)
            $table->text('description')->nullable();
            // Status: pending, in_progress, completed
            $table->string('status')->default('pending');
            // Priority: low, medium, high
            $table->string('priority')->default('medium');
            // Due date (optional)
            $table->date('due_date')->nullable();
            // Completion marker
            $table->timestamp('completed_at')->nullable();
            // Automatic timestamps (created_at, updated_at)
            $table->timestamps();
            // Soft deletes for trash functionality
            $table->softDeletes();

            // Indexes to optimize frequent queries
            $table->index(['user_id', 'status']);
            $table->index('due_date');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('tasks');
    }
};

Migracja definiuje strukturę tabeli z relacjami, indeksami i soft delete, aby zapobiec przypadkowej utracie danych.

php
<?php
// app/Models/Task.php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;

class Task extends Model
{
    // Traits for advanced functionality
    use HasFactory, SoftDeletes;

    // Mass-assignable attributes
    protected $fillable = [
        'user_id',
        'title',
        'description',
        'status',
        'priority',
        'due_date',
        'completed_at',
    ];

    // Automatic attribute casting
    protected function casts(): array
    {
        return [
            'due_date' => 'date',
            'completed_at' => 'datetime',
        ];
    }

    // Constants for valid statuses
    public const STATUS_PENDING = 'pending';
    public const STATUS_IN_PROGRESS = 'in_progress';
    public const STATUS_COMPLETED = 'completed';

    // Constants for priorities
    public const PRIORITY_LOW = 'low';
    public const PRIORITY_MEDIUM = 'medium';
    public const PRIORITY_HIGH = 'high';

    // Relationship: a task belongs to a user
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    // Scope: pending tasks
    public function scopePending(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_PENDING);
    }

    // Scope: in-progress tasks
    public function scopeInProgress(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_IN_PROGRESS);
    }

    // Scope: completed tasks
    public function scopeCompleted(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_COMPLETED);
    }

    // Scope: overdue tasks
    public function scopeOverdue(Builder $query): Builder
    {
        return $query->where('due_date', '<', now())
                     ->whereNull('completed_at');
    }

    // Scope: tasks for a specific user
    public function scopeForUser(Builder $query, int $userId): Builder
    {
        return $query->where('user_id', $userId);
    }

    // Accessor: check if task is overdue
    public function getIsOverdueAttribute(): bool
    {
        return $this->due_date
            && $this->due_date->isPast()
            && !$this->completed_at;
    }

    // Method: mark as completed
    public function markAsCompleted(): void
    {
        $this->update([
            'status' => self::STATUS_COMPLETED,
            'completed_at' => now(),
        ]);
    }
}

Model Task wykorzystuje Eloquent scopes do czytelnych i wielokrotnie używalnych zapytań. Stałe centralizują dozwolone wartości statusów i priorytetów.

Soft Deletes

Trait SoftDeletes dodaje kolumnę deleted_at. Usunięte zadania nie znikają z bazy danych, lecz zostają oznaczone jako usunięte. Metoda withTrashed() pozwala uwzględnić je w zapytaniach.

Konfiguracja uwierzytelniania z Breeze

Laravel Breeze zapewnia kompletne uwierzytelnianie z widokami Blade lub API. Instalacja zajmuje kilka minut i generuje wszystko, co potrzebne: trasy, kontrolery, widoki i testy.

bash
# terminal
# Install Laravel Breeze
composer require laravel/breeze --dev

# Install the Blade stack (traditional)
php artisan breeze:install blade

# Or for API only (SPA/mobile)
php artisan breeze:install api

# Compile assets
npm install && npm run build

# Run migrations (users, sessions tables, etc.)
php artisan migrate

Breeze generuje trasy uwierzytelniania, kontrolery i widoki do rejestracji, logowania, resetowania hasła i weryfikacji e-mail.

php
<?php
// app/Models/User.php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }

    // Relationship: a user owns multiple tasks
    public function tasks(): HasMany
    {
        return $this->hasMany(Task::class);
    }

    // Shortcut: user's pending tasks
    public function pendingTasks(): HasMany
    {
        return $this->tasks()->pending();
    }

    // Shortcut: user's overdue tasks
    public function overdueTasks(): HasMany
    {
        return $this->tasks()->overdue();
    }
}

Gotowy na rozmowy o Laravel?

Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.

Tworzenie kontrolerów i tras

Kontroler orkiestruje logikę biznesową pomiędzy żądaniami HTTP a modelem. Laravel 11 zachęca do stosowania kontrolerów jednoakcyjnych lub zasobów RESTful.

php
<?php
// app/Http/Controllers/TaskController.php

namespace App\Http\Controllers;

use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Illuminate\Support\Facades\Gate;

class TaskController extends Controller
{
    // List tasks for the authenticated user
    public function index(Request $request): View
    {
        // Retrieve tasks with optional filtering
        $tasks = $request->user()
            ->tasks()
            ->when($request->status, fn($q, $status) => $q->where('status', $status))
            ->when($request->priority, fn($q, $priority) => $q->where('priority', $priority))
            ->orderBy('due_date')
            ->orderBy('priority', 'desc')
            ->paginate(15);

        return view('tasks.index', compact('tasks'));
    }

    // Creation form
    public function create(): View
    {
        return view('tasks.create');
    }

    // Store a new task
    public function store(Request $request): RedirectResponse
    {
        // Validate incoming data
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string|max:5000',
            'priority' => 'required|in:low,medium,high',
            'due_date' => 'nullable|date|after_or_equal:today',
        ]);

        // Create the task linked to the user
        $request->user()->tasks()->create($validated);

        return redirect()
            ->route('tasks.index')
            ->with('success', 'Task created successfully.');
    }

    // Display a task
    public function show(Task $task): View
    {
        // Verify user ownership
        Gate::authorize('view', $task);

        return view('tasks.show', compact('task'));
    }

    // Edit form
    public function edit(Task $task): View
    {
        Gate::authorize('update', $task);

        return view('tasks.edit', compact('task'));
    }

    // Update a task
    public function update(Request $request, Task $task): RedirectResponse
    {
        Gate::authorize('update', $task);

        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string|max:5000',
            'status' => 'required|in:pending,in_progress,completed',
            'priority' => 'required|in:low,medium,high',
            'due_date' => 'nullable|date',
        ]);

        // Update completed_at if status = completed
        if ($validated['status'] === Task::STATUS_COMPLETED && !$task->completed_at) {
            $validated['completed_at'] = now();
        }

        $task->update($validated);

        return redirect()
            ->route('tasks.index')
            ->with('success', 'Task updated.');
    }

    // Delete a task
    public function destroy(Task $task): RedirectResponse
    {
        Gate::authorize('delete', $task);

        $task->delete();

        return redirect()
            ->route('tasks.index')
            ->with('success', 'Task deleted.');
    }

    // Mark as completed (quick action)
    public function complete(Task $task): RedirectResponse
    {
        Gate::authorize('update', $task);

        $task->markAsCompleted();

        return back()->with('success', 'Task completed!');
    }
}

Kontroler wykorzystuje Gates do autoryzacji, wbudowaną walidację i route model binding, co zapewnia zwięzły i bezpieczny kod.

Definiowanie tras

Trasy definiują adresy URL i przypisują je do akcji kontrolera. Laravel 11 centralizuje trasy w pliku routes/web.php.

php
<?php
// routes/web.php

use App\Http\Controllers\TaskController;
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

// Public homepage
Route::get('/', function () {
    return view('welcome');
});

// Routes protected by authentication
Route::middleware(['auth', 'verified'])->group(function () {
    // Dashboard with statistics
    Route::get('/dashboard', function () {
        $user = auth()->user();

        return view('dashboard', [
            'totalTasks' => $user->tasks()->count(),
            'pendingTasks' => $user->tasks()->pending()->count(),
            'completedTasks' => $user->tasks()->completed()->count(),
            'overdueTasks' => $user->tasks()->overdue()->count(),
        ]);
    })->name('dashboard');

    // RESTful routes for tasks
    Route::resource('tasks', TaskController::class);

    // Quick action to complete a task
    Route::patch('/tasks/{task}/complete', [TaskController::class, 'complete'])
        ->name('tasks.complete');

    // Profile routes (generated by Breeze)
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});

// Authentication routes (generated by Breeze)
require __DIR__.'/auth.php';

Metoda Route::resource() automatycznie generuje siedem standardowych tras RESTful: index, create, store, show, edit, update i destroy.

Konfiguracja polityk autoryzacji

Polityki centralizują logikę autoryzacji dla każdego modelu. Określają, kto może wykonywać jakie operacje na zasobach.

bash
# terminal
# Generate the policy for Task
php artisan make:policy TaskPolicy --model=Task
php
<?php
// app/Policies/TaskPolicy.php

namespace App\Policies;

use App\Models\Task;
use App\Models\User;

class TaskPolicy
{
    // Check before all methods
    // Returning true bypasses all checks (admin)
    public function before(User $user, string $ability): ?bool
    {
        if ($user->is_admin) {
            return true;
        }

        return null; // Continue to specific methods
    }

    // Can view the list of tasks
    public function viewAny(User $user): bool
    {
        return true; // Any authenticated user
    }

    // Can view a specific task
    public function view(User $user, Task $task): bool
    {
        return $user->id === $task->user_id;
    }

    // Can create a task
    public function create(User $user): bool
    {
        return true;
    }

    // Can update a task
    public function update(User $user, Task $task): bool
    {
        return $user->id === $task->user_id;
    }

    // Can delete a task
    public function delete(User $user, Task $task): bool
    {
        return $user->id === $task->user_id;
    }

    // Can restore a soft-deleted task
    public function restore(User $user, Task $task): bool
    {
        return $user->id === $task->user_id;
    }

    // Can permanently delete
    public function forceDelete(User $user, Task $task): bool
    {
        return $user->id === $task->user_id;
    }
}

Laravel automatycznie wykrywa polityki dzięki konwencjom nazewniczym. TaskPolicy stosuje się do modelu Task.

Bezpieczeństwo polityk

Polityki są kluczowe dla bezpieczeństwa. Bez nich użytkownik mógłby manipulować adresami URL, aby uzyskać dostęp do zadań innych użytkowników. Zawsze należy weryfikować własność zasobów.

Budowa REST API

Laravel upraszcza tworzenie RESTful API dzięki dedykowanym trasom, zasobom JSON i Sanctum do uwierzytelniania.

bash
# terminal
# Install Sanctum (included by default since Laravel 11)
php artisan install:api

# This command:
# - Publishes Sanctum migrations
# - Adds the HasApiTokens trait to the User model
# - Configures API routes
php
<?php
// app/Http/Controllers/Api/TaskController.php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\TaskResource;
use App\Http\Resources\TaskCollection;
use App\Models\Task;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;

class TaskController extends Controller
{
    // Paginated list of tasks
    public function index(Request $request): AnonymousResourceCollection
    {
        $tasks = $request->user()
            ->tasks()
            ->when($request->status, fn($q, $s) => $q->where('status', $s))
            ->when($request->priority, fn($q, $p) => $q->where('priority', $p))
            ->when($request->boolean('overdue'), fn($q) => $q->overdue())
            ->latest()
            ->paginate($request->input('per_page', 15));

        return TaskResource::collection($tasks);
    }

    // Create a task
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string|max:5000',
            'priority' => 'required|in:low,medium,high',
            'due_date' => 'nullable|date|after_or_equal:today',
        ]);

        $task = $request->user()->tasks()->create($validated);

        return response()->json([
            'message' => 'Task created successfully.',
            'data' => new TaskResource($task),
        ], 201);
    }

    // Display a task
    public function show(Task $task): TaskResource
    {
        $this->authorize('view', $task);

        return new TaskResource($task);
    }

    // Update a task
    public function update(Request $request, Task $task): TaskResource
    {
        $this->authorize('update', $task);

        $validated = $request->validate([
            'title' => 'sometimes|required|string|max:255',
            'description' => 'nullable|string|max:5000',
            'status' => 'sometimes|required|in:pending,in_progress,completed',
            'priority' => 'sometimes|required|in:low,medium,high',
            'due_date' => 'nullable|date',
        ]);

        if (isset($validated['status'])
            && $validated['status'] === Task::STATUS_COMPLETED
            && !$task->completed_at) {
            $validated['completed_at'] = now();
        }

        $task->update($validated);

        return new TaskResource($task->fresh());
    }

    // Delete a task
    public function destroy(Task $task): JsonResponse
    {
        $this->authorize('delete', $task);

        $task->delete();

        return response()->json([
            'message' => 'Task deleted successfully.',
        ]);
    }
}

Zasoby API do transformacji danych

Zasoby API przekształcają modele Eloquent w ustrukturyzowane odpowiedzi JSON, precyzyjnie kontrolując eksponowane dane.

php
<?php
// app/Http/Resources/TaskResource.php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class TaskResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'description' => $this->description,
            'status' => $this->status,
            'priority' => $this->priority,
            'due_date' => $this->due_date?->format('Y-m-d'),
            'is_overdue' => $this->is_overdue,
            'completed_at' => $this->completed_at?->toISOString(),
            'created_at' => $this->created_at->toISOString(),
            'updated_at' => $this->updated_at->toISOString(),
            // Conditional inclusion of the user
            'user' => $this->whenLoaded('user', fn() => [
                'id' => $this->user->id,
                'name' => $this->user->name,
            ]),
        ];
    }
}

Trasy API z uwierzytelnianiem Sanctum

php
<?php
// routes/api.php

use App\Http\Controllers\Api\TaskController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

// Route to retrieve the authenticated user
Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

// API routes protected by Sanctum
Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('tasks', TaskController::class);

    // Dashboard statistics
    Route::get('/dashboard/stats', function (Request $request) {
        $user = $request->user();

        return response()->json([
            'total' => $user->tasks()->count(),
            'pending' => $user->tasks()->pending()->count(),
            'in_progress' => $user->tasks()->inProgress()->count(),
            'completed' => $user->tasks()->completed()->count(),
            'overdue' => $user->tasks()->overdue()->count(),
        ]);
    });
});

Testy automatyczne z Pest

Laravel 11 domyślnie integruje Pest PHP — elegancki i ekspresyjny framework testowy. Testy zapewniają poprawne działanie aplikacji po każdej modyfikacji.

php
<?php
// tests/Feature/TaskTest.php

use App\Models\Task;
use App\Models\User;

// Test: a user can view their tasks
test('user can view their tasks', function () {
    $user = User::factory()->create();
    $tasks = Task::factory()->count(5)->for($user)->create();

    $response = $this->actingAs($user)->get('/tasks');

    $response->assertOk();
    $response->assertViewHas('tasks');
});

// Test: a user can create a task
test('user can create a task', function () {
    $user = User::factory()->create();

    $response = $this->actingAs($user)->post('/tasks', [
        'title' => 'New task',
        'description' => 'Task description',
        'priority' => 'high',
        'due_date' => now()->addDays(7)->format('Y-m-d'),
    ]);

    $response->assertRedirect('/tasks');

    $this->assertDatabaseHas('tasks', [
        'user_id' => $user->id,
        'title' => 'New task',
        'priority' => 'high',
    ]);
});

// Test: title validation required
test('task title is required', function () {
    $user = User::factory()->create();

    $response = $this->actingAs($user)->post('/tasks', [
        'title' => '',
        'priority' => 'medium',
    ]);

    $response->assertSessionHasErrors('title');
});

// Test: a user cannot view another user's task
test('user cannot view another users task', function () {
    $user = User::factory()->create();
    $otherUser = User::factory()->create();
    $task = Task::factory()->for($otherUser)->create();

    $response = $this->actingAs($user)->get("/tasks/{$task->id}");

    $response->assertForbidden();
});

// Test: mark a task as completed
test('user can complete a task', function () {
    $user = User::factory()->create();
    $task = Task::factory()->for($user)->create(['status' => 'pending']);

    $response = $this->actingAs($user)->patch("/tasks/{$task->id}/complete");

    $response->assertRedirect();

    $task->refresh();
    expect($task->status)->toBe('completed');
    expect($task->completed_at)->not->toBeNull();
});

// API test: retrieve tasks
test('api returns paginated tasks', function () {
    $user = User::factory()->create();
    Task::factory()->count(20)->for($user)->create();

    $response = $this->actingAs($user, 'sanctum')
        ->getJson('/api/tasks?per_page=10');

    $response->assertOk()
        ->assertJsonCount(10, 'data')
        ->assertJsonStructure([
            'data' => [
                '*' => ['id', 'title', 'status', 'priority', 'due_date'],
            ],
            'links',
            'meta',
        ]);
});

Uruchamianie testow z Pest.

bash
# terminal
# Run all tests
php artisan test

# Tests with code coverage
php artisan test --coverage

# Tests for a specific file
php artisan test tests/Feature/TaskTest.php

# Parallel tests (faster)
php artisan test --parallel

Optymalizacje produkcyjne

Przed wdrożeniem kilka optymalizacji poprawia wydajność aplikacji Laravel.

bash
# terminal
# Cache configuration
php artisan config:cache

# Cache routes
php artisan route:cache

# Cache views
php artisan view:cache

# Optimize Composer autoloader
composer install --optimize-autoloader --no-dev

# Generate asset manifest
npm run build

Konfiguracja pliku .env dla produkcji

env
# .env.production
APP_NAME="Task Manager"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://taskmanager.example.com

# Cache and session via Redis (recommended)
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

# Database
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=task_manager_prod
DB_USERNAME=app_user
DB_PASSWORD=strong_password_here

# Mail
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=postmaster@taskmanager.example.com
MAIL_PASSWORD=secret
MAIL_ENCRYPTION=tls
Zmienne wrażliwe

Nigdy nie commituj pliku .env do repozytorium Git. Plik .env.example służy jako szablon, a zmienne wrażliwe konfiguruje się bezpośrednio na serwerze produkcyjnym lub przez menedżery sekretów.

Podsumowanie

Laravel 11 znacząco upraszcza nowoczesne programowanie w PHP dzięki uproszczonej strukturze i inteligentnym konwencjom. Niniejszy przewodnik obejmuje podstawy budowy kompletnej aplikacji: modele Eloquent, uwierzytelnianie, kontrolery RESTful, polityki autoryzacji, API z Sanctum i testy automatyczne.

Lista kontrolna dla wysokiej jakości aplikacji Laravel

  • Migracje do wszystkich zmian w schemacie bazy danych
  • Polityki zabezpieczające dostęp do zasobów
  • Walidacja wszystkich danych wejściowych w kontrolerach
  • Zasoby API do kontrolowania eksponowanych danych
  • Testy dla krytycznych funkcjonalności
  • Konfiguracja cache i optymalizacji przed wdrożeniem
  • Zabezpieczenie wrażliwych zmiennych środowiskowych

Zacznij ćwiczyć!

Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.

Ekosystem Laravel kontynuuje rozwój dzięki pakietom takim jak Livewire do reaktywnych interfejsów, Horizon do zarządzania kolejkami i Octane do wyjątkowej wydajności. Opanowanie tych podstaw otwiera drzwi do solidnych i łatwych w utrzymaniu aplikacji PHP.

Tagi

#laravel
#php
#rest api
#eloquent
#tutorial

Udostępnij

Powiązane artykuły