modul 00 / start: Laravel, framework-uri & MVC
ce este Laravel & de ce un framework
Laravel e cel mai popular framework PHP pentru construirea de aplicații web moderne. Dacă știi PHP de bază, Laravel îți dă structura, uneltele și convențiile ca să construiești aplicații reale rapid, curat și sigur. Acest curs urmează documentația și bootcamp-ul oficial Laravel.
ce e un framework și de ce l-ai folosi
Fără framework, ai rescrie de fiecare dată aceleași lucruri: rutare, conectare la bază de date, securitate, șabloane, autentificare. Un framework îți oferă toate acestea gata făcute, testate și organizate, ca să te concentrezi pe logica aplicației tale, nu pe reinventarea infrastructurii.
- Structură — un loc anume pentru fiecare tip de cod (convenții comune, echipe care se înțeleg).
- Securitate — protecții încorporate (SQL injection, CSRF, XSS) fără efort manual.
- Productivitate — unelte care generează cod, rulează sarcini, automatizează.
- Comunitate & ecosistem — pachete, documentație excelentă, resurse.
de ce Laravel în special
- Sintaxă elegantă — cod expresiv, plăcut de scris și citit („developer happiness” e o valoare declarată).
- Baterii incluse — routing, ORM (Eloquent), template engine (Blade), autentificare, cozi, cache, e-mail, teste — tot ce-ți trebuie.
- Ecosistem bogat — Breeze/Jetstream (auth), Sanctum/Passport (API auth), Livewire, Forge (deploy), Vapor (serverless), Nova (admin).
- Documentație remarcabilă — printre cele mai bune din industrie.
arhitectura MVC — inima Laravel
Laravel organizează codul după modelul MVC (Model-View-Controller), o separare a responsabilităților:
| Componentă | Rol | În Laravel |
| Model | Datele & logica de business (vorbește cu baza de date) | Clase Eloquent (app/Models) |
| View | Prezentarea (ce vede utilizatorul — HTML) | Template-uri Blade (resources/views) |
| Controller | Coordonatorul: primește cererea, cheamă modelul, alege view-ul | Clase Controller (app/Http/Controllers) |
Fluxul: cererea vine → ruta o trimite la un controller → controller-ul folosește un model pentru date → returnează un view cu datele. Această separare face codul organizat, testabil și mentenabil — fiecare piesă are un singur rol.
de reținut
Un framework nu e „PHP complicat” — e PHP organizat și amplificat. Laravel îți dă o casă gata construită (structură, securitate, unelte) în care îți pui mobila (logica aplicației). Modelul MVC — cererea → rută → controller → model → view — e harta mentală pe care o vei folosi în tot cursul. Odată ce „vezi” fluxul, restul e să înveți fiecare piesă.
modul 00 / start: Laravel, framework-uri & MVC
instalare, Artisan & structura proiectului
de ce ai nevoie
- PHP (versiune recentă) și Composer — managerul de dependențe PHP (ca npm pentru JS).
- O bază de date (MySQL, PostgreSQL, sau SQLite pentru dezvoltare simplă).
- Un mediu local: Laravel Herd (recomandat, simplu), Sail (Docker), sau Valet (Mac).
crearea unui proiect
# cu installer-ul Laravel:
laravel new blog
# sau cu Composer:
composer create-project laravel/laravel blog
# pornești serverul de dezvoltare:
cd blog
php artisan serve // → http://localhost:8000
Artisan — asistentul din linia de comandă
Artisan e unealta CLI a Laravel — generează cod, rulează sarcini, automatizează. Îl vei folosi constant:
php artisan serve // pornește serverul local
php artisan make:controller PostController // creează un controller
php artisan make:model Post -m // model + migrație
php artisan migrate // rulează migrațiile
php artisan route:list // listează toate rutele
php artisan tinker // REPL interactiv pentru a experimenta
make:* generează schelete de cod (controllere, modele, migrații) — economisește timp și impune convenții. tinker îți dă o consolă unde poți rula cod Laravel live (perfect pentru a testa modele).
structura proiectului — unde stă ce
| Folder | Ce conține |
| routes/ | Definițiile rutelor (web.php, api.php) |
| app/Http/Controllers/ | Controllerele |
| app/Models/ | Modelele Eloquent |
| resources/views/ | Template-urile Blade |
| database/migrations/ | Migrațiile (structura tabelelor) |
| config/ | Fișierele de configurare |
| public/ | Punctul de intrare (index.php) & assets publice |
| .env | Configurarea de mediu (DB, chei, secrete) — NU se pune în Git |
fișierul .env — configurarea de mediu
.env ține setările specifice mediului (date DB, chei, moduri): diferite pe local vs producție, fără a schimba codul. Nu se comite niciodată în Git (conține secrete). Laravel citește din el prin config() și env().
de reținut
Composer gestionează dependențele, Artisan îți automatizează munca (generare de cod, migrații, tinker), iar structura de foldere convențională îți spune exact unde pune fiecare piesă MVC. Plus .env pentru configurare sigură. Cu aceste unelte în mână, ești gata să construiești — următoarul pas e să primești cereri și să le direcționezi: routing.
modul 01 / routing
rute & verbe HTTP
Routing-ul e primul lucru pe care îl întâlnește o cerere: decide „ce cod rulează pentru acest URL”. E poarta de intrare a aplicației tale.
o rută simplă
Rutele web se definesc în routes/web.php:
use Illuminate\Support\Facades\Route;
Route::get('/salut', function () {
return 'Salut, lume!';
});
Aceasta spune: „când cineva accesează /salut printr-o cerere GET, rulează această funcție și returnează textul”. O rută leagă un verb HTTP + URL de o acțiune (o funcție sau o metodă de controller).
verbele HTTP
| Verb | Folosit pentru | Metodă Route |
| GET | Citirea/afișarea datelor | Route::get() |
| POST | Crearea de date noi (formulare) | Route::post() |
| PUT / PATCH | Actualizarea datelor | Route::put() / patch() |
| DELETE | Ștergerea datelor | Route::delete() |
Aceste verbe reflectă operațiile CRUD (Create, Read, Update, Delete) — coloana vertebrală a majorității aplicațiilor web. O resursă (ex: „articole”) are tipic toate patru.
parametri de rută
Route::get('/articol/{id}', function ($id) {
return 'Articolul ' . $id;
});
// /articol/42 → „Articolul 42”
// parametru opțional (cu ?):
Route::get('/user/{nume?}', function ($nume = 'vizitator') {
return 'Salut ' . $nume;
});
Segmentele dinamice din {acolade} devin argumente ale funcției. Așa afișezi conținut specific: articolul 42, profilul unui utilizator etc. Poți restricționa formatul cu ->where('id', '[0-9]+') (doar numere).
legarea la controllere
În aplicații reale, rutele trimit la metode de controller (modulul 2), nu la funcții inline:
use App\Http\Controllers\ArticolController;
Route::get('/articole', [ArticolController::class, 'index']);
Route::get('/articole/{articol}', [ArticolController::class, 'show']);
de reținut
O rută = verb HTTP + URL → acțiune. Verbele HTTP nu sunt arbitrare: mapează pe operațiile CRUD (GET citește, POST creează, PUT/PATCH actualizează, DELETE șterge). Parametrii din acolade fac rutele dinamice. Pentru orice altceva decât demo-uri, rutele leagă la controllere — ceea ce urmează.
modul 01 / routing
rute cu nume, grupuri & organizare
rute cu nume — nu hardcoda URL-uri
Dai un nume unei rute, apoi te referi la ea prin nume, nu prin URL:
Route::get('/articole/{id}', [ArticolController::class, 'show'])
->name('articole.show');
// generezi URL-ul prin nume:
route('articole.show', ['id' => 42]); // → /articole/42
// în Blade:
<a href="{{ route('articole.show', $articol) }}">...</a>
De ce contează: dacă schimbi URL-ul (/articole → /blog), toate link-urile care folosesc numele rutei se actualizează automat. Nu cauți și înlocuiești URL-uri prin tot codul. Bună practică fundamentală.
grupuri de rute — DRY pentru configurări comune
Când mai multe rute au ceva în comun (prefix, middleware), le grupezi:
Route::prefix('admin')->group(function () {
Route::get('/dashboard', ...); // → /admin/dashboard
Route::get('/utilizatori', ...); // → /admin/utilizatori
});
// grup cu middleware (ex: doar utilizatori autentificați):
Route::middleware('auth')->group(function () {
Route::get('/profil', ...);
Route::get('/setari', ...);
});
Middleware (modulul 8) sunt filtre prin care trece cererea (ex: „ești autentificat?”). Grupul aplică middleware-ul tuturor rutelor din el, o singură dată.
resource routes — toate rutele CRUD dintr-o linie
Route::resource('articole', ArticolController::class);
O singură linie generează toate cele 7 rute CRUD standard (index, create, store, show, edit, update, destroy) legate la metodele controllerului cu același nume. Convenție peste configurare — economisește mult cod repetitiv (modulul 2).
route:list — vederea de ansamblu
php artisan route:list
Afișează toate rutele aplicației: verb, URL, nume, controller. Instrumentul tău de referință când „ce rute am și unde duc?”.
web.php vs api.php
- routes/web.php — rute pentru pagini web (cu sesiuni, cookies, protecție CSRF).
- routes/api.php — rute pentru API (stateless, prefixate cu /api, autentificare prin token). Modulul 10.
de reținut
Rutele cu nume te scapă de URL-uri hardcodate (schimbi într-un loc, se propagă peste tot). Grupurile aplică prefixe și middleware la mai multe rute deodată (DRY). Route::resource generează întregul set CRUD dintr-o linie. Aceste trei tehnici transformă un fișier de rute haotic într-unul curat și mentenabil — semnul unui proiect Laravel bine organizat.
modul 02 / controllers & ciclul unei cereri
controllere: organizarea logicii
Punerea întregii logici în funcții inline în fișierul de rute devine repede haotică. Controllerele grupează logica înrudită în clase — coordonatorii din MVC. O rută trimite cererea, controllerul o gestionează.
crearea unui controller
php artisan make:controller ArticolController
Generează o clasă în app/Http/Controllers/:
namespace App\Http\Controllers;
use App\Models\Articol;
class ArticolController extends Controller
{
public function index()
{
$articole = Articol::all(); // ia datele din model
return view('articole.index', ['articole' => $articole]);
}
public function show(Articol $articol) // route model binding
{
return view('articole.show', ['articol' => $articol]);
}
}
Fiecare metodă gestionează o acțiune (afișează lista, arată unul, salvează). Metoda ia datele (din model), apoi returnează un view cu ele — MVC în acțiune.
resource controllers — tiparul CRUD complet
php artisan make:controller ArticolController --resource
Generează un controller cu cele 7 metode standard, corespunzând rutelor CRUD:
| Metodă | Rol | Verb/URL tipic |
| index | Lista tuturor | GET /articole |
| create | Formularul de creare | GET /articole/create |
| store | Salvează cel nou | POST /articole |
| show | Afișează unul | GET /articole/{id} |
| edit | Formularul de editare | GET /articole/{id}/edit |
| update | Salvează modificările | PUT/PATCH /articole/{id} |
| destroy | Șterge | DELETE /articole/{id} |
Împreună cu Route::resource (modulul 1), ai un CRUD complet, convențional, cu efort minim. Aceste nume de metode sunt un standard pe care orice dezvoltator Laravel îl recunoaște.
route model binding — magia care îți economisește cod
Ai observat show(Articol $articol)? Laravel vede parametrul de rută {articol} și automat caută articolul cu acel ID în baza de date și ți-l dă gata, ca obiect. Dacă nu există → 404 automat. Nu mai scrii Articol::find($id) manual — route model binding.
de reținut
Controllerele îți țin logica organizată: o clasă per resursă, o metodă per acțiune. Resource controllers + Route::resource îți dau tiparul CRUD complet cu convenții standard. Iar route model binding transformă un parametru de rută direct în modelul din baza de date. Regula bună: controllerele să fie subțiri — coordonează, dar logica grea de business stă în modele/servicii.
modul 02 / controllers & ciclul unei cereri
ciclul unei cereri & injecția de dependențe
ciclul de viață al unei cereri
Ce se întâmplă când vine o cerere în Laravel, pe scurt:
- Cererea intră prin public/index.php (punctul unic de intrare).
- Se pornește aplicația (bootstrap): se încarcă service container-ul și service providers (modulul 9).
- Cererea trece prin middleware globale (ex: verificări de sesiune, CSRF).
- Router-ul potrivește URL-ul cu o rută → aplică middleware-ul rutei → cheamă controllerul.
- Controllerul rulează logica (modele, servicii) → returnează un răspuns (view, JSON, redirect).
- Răspunsul trece înapoi prin middleware → se trimite browserului.
Nu trebuie să memorezi fiecare detaliu, dar modelul mental — intrare unică → bootstrap → middleware → rută → controller → răspuns → middleware — te ajută să înțelegi unde se conectează fiecare piesă.
injecția de dependențe (DI) & service container
Laravel are un service container puternic care „știe” cum să construiască obiecte de care ai nevoie. Când ceri o dependență (type-hint într-un parametru), Laravel ți-o oferă automat — dependency injection.
use Illuminate\Http\Request;
public function store(Request $request)
{
// Laravel „injectează” automat obiectul Request
$titlu = $request->input('titlu');
}
- Ceri un tip (Request) → containerul ți-l construiește și ți-l dă. Nu-l instanțiezi manual.
- Merge cu orice clasă înregistrată în container: servicii proprii, repository-uri, cazuri de utilizare.
- Rezultatul: cod decuplat și testabil (poți înlocui dependențele cu mock-uri la teste).
obiectul Request — datele cererii
$request->input('email'); // un câmp de formular
$request->query('pagina'); // un parametru din URL (?pagina=2)
$request->all(); // toate datele
$request->has('nume'); // există câmpul?
$request->user(); // utilizatorul autentificat
Prin Request accesezi tot ce a trimis clientul: input-uri de formular, parametri de query, fișiere, headere. E poarta ta către datele cererii.
de reținut
Ciclul cererii (intrare → middleware → rută → controller → răspuns) e scheletul pe care rulează orice aplicație Laravel. Injecția de dependențe — ceri un tip, containerul ți-l dă — e ce face codul decuplat și testabil, un principiu central al Laravel. Iar obiectul Request e poarta ta către datele trimise de utilizator (pe care le vei valida în modulul 7). Piesele încep să se lege.
modul 03 / Blade: template engine
Blade: sintaxă & afișarea datelor
Blade e motorul de template-uri al Laravel — cum construiești HTML-ul (view-urile din MVC) folosind date din controllere. E simplu, puternic și se compilează în PHP pur (deci e rapid).
afișarea datelor — sigur din start
<h1>{{ $titlu }}</h1>
<p>Salut, {{ $user->nume }}</p>
Sintaxa {{ }} afișează o valoare. Crucial: Blade escapează automat conținutul (previne XSS) — datele de la utilizator sunt tratate ca text, nu ca cod. Această siguranță din start e un avantaj major.
- {{ $var }} — afișare escapată (sigură, implicit).
- {!! $var !!} — afișare NEescapată (HTML brut) — folosește-o doar pentru conținut de încredere, niciodată pentru input de utilizator.
transmiterea datelor din controller
// în controller:
return view('salut', ['nume' => 'Ana']);
// sau:
return view('salut')->with('nume', 'Ana');
// sau compact:
return view('salut', compact('nume'));
În view, variabila $nume e disponibilă direct. Datele curg din controller (care le-a luat din model) către template — MVC.
structuri de control
@if ($user->esteAdmin)
<p>Bun venit, admin!</p>
@elseif ($user)
<p>Bun venit!</p>
@else
<p>Autentifică-te.</p>
@endif
@foreach ($articole as $articol)
<h2>{{ $articol->titlu }}</h2>
@endforeach
@forelse ($articole as $articol)
<li>{{ $articol->titlu }}</li>
@empty
<li>Niciun articol.</li>
@endforelse
Directivele @if, @foreach, @forelse (cu caz gol!) îți dau logică curată în template, fără PHP inline dezordonat. @forelse e elegant: iterează sau afișează un mesaj când lista e goală.
de reținut
Blade îți dă HTML dinamic curat: {{ }} afișează sigur (escapat automat — protecție XSS gratuită), directivele @if/@foreach dau logică lizibilă, iar datele curg din controller. Regula de aur: foloseste {{ }} pentru datele de utilizator (escapat); {!! !!} doar pentru HTML de încredere. Următorul pas: layout-uri și componente, ca să nu repeți structura.
modul 03 / Blade: template engine
layout-uri, componente & organizarea view-urilor
Fiecare pagină are părți comune: header, footer, meniu, <head>. A le copia în fiecare view e o coșmar de întreținere. Blade oferă două mecanisme moderne pentru refolosire: moștenirea de layout și componentele.
layout-uri cu moștenire
Definești un layout de bază cu „găuri” (sections) pe care paginile le umplu:
// resources/views/layouts/app.blade.php
<html><body>
<nav>...meniu comun...</nav>
@yield('continut') // „gaura” care se umple
<footer>...</footer>
</body></html>
// o pagină care extinde layout-ul:
@extends('layouts.app')
@section('continut')
<h1>Pagina mea</h1>
@endsection
Pagina moștenește structura comună și umple doar partea ei — o singură sursă pentru header/footer, ușor de întreținut.
componente Blade — abordarea modernă
Componentele sunt bucăți de UI refolosibile, cu propriile date — mai puternice și mai curate decât moștenirea pentru multe cazuri.
php artisan make:component Alert
// resources/views/components/alert.blade.php
<div class="alert alert-{{ $tip }}">
{{ $slot }} // conținutul pus între taguri
</div>
// utilizare oriunde:
<x-alert tip="succes">
Salvat cu succes!
</x-alert>
- O definești o dată, o folosești ca un tag HTML (<x-alert>) oriunde.
- $slot = conținutul dintre taguri; atributele (tip="succes") devin variabile.
- Componentele fac UI-ul DRY și consistent — un buton, un card, o alertă definite o dată.
partials cu @include
@include('partials.header')
@include('partials.card', ['articol' => $articol])
Pentru bucăți simple, refolosibile, incluzi un sub-template. Componentele sunt însă preferate pentru UI cu parametri.
organizarea view-urilor
- Structurează în subfoldere: views/articole/index.blade.php → referit ca view('articole.index').
- Layout-uri în views/layouts/, componente în views/components/, partials în views/partials/.
- Convenția: numele view-ului cu punct = calea folderelor.
de reținut
Layout-urile (@extends / @yield / @section) îți dau structura comună o singură dată. Componentele (<x-component> cu $slot și atribute) sunt calea modernă spre UI refolosibil și consistent. Împreună, elimină duplicarea din view-uri — la fel cum funcțiile o elimină din cod. Un front-end Laravel bine făcut e o compunere de layout-uri și componente, alimentate cu date din controllere.
modul 04 / baza de date & migrații
migrații: versionarea schemei
Aplicațiile au nevoie de o bază de date. Laravel îți dă o abordare elegantă: migrațiile — definirea structurii bazei de date în cod PHP, versionat în Git. Gata cu „exportă baza de date și trimite-o colegului”.
configurarea (în .env)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=blog
DB_USERNAME=root
DB_PASSWORD=secret
Laravel suportă MySQL, PostgreSQL, SQLite, SQL Server. Pentru dezvoltare rapidă, SQLite (un singur fișier) e cel mai simplu.
ce sunt migrațiile & de ce contează
O migrație e un fișier PHP care descrie o modificare a structurii bazei de date (creează un tabel, adaugă o coloană). Beneficii:
- Versionare — structura DB trăiește în cod, în Git, alături de aplicație. Fiecare coleg rulează aceleași migrații și obține aceeași structură.
- Reproductibilitate — pe orice mediu (local, staging, producție) rulezi php artisan migrate și obții schema corectă.
- Istoric & rollback — poți anula ultima modificare (migrate:rollback).
crearea unei migrații
php artisan make:migration create_articole_table
# sau odată cu modelul:
php artisan make:model Articol -m
// database/migrations/..._create_articole_table.php
public function up(): void
{
Schema::create('articole', function (Blueprint $table) {
$table->id(); // cheie primară auto-increment
$table->string('titlu');
$table->text('continut');
$table->boolean('publicat')->default(false);
$table->foreignId('user_id')->constrained(); // cheie străină
$table->timestamps(); // created_at & updated_at automat
});
}
public function down(): void // cum se anulează
{
Schema::dropIfExists('articole');
}
- up() — ce se aplică; down() — cum se anulează (pentru rollback).
- Schema builder ($table->string() etc.) descrie coloanele în PHP, independent de baza de date concretă.
rularea migrațiilor
php artisan migrate // aplică migrațiile ne-rulate
php artisan migrate:rollback // anulează ultimul „batch”
php artisan migrate:fresh // șterge tot și rerulează (dev!)
php artisan migrate:fresh --seed // + populează cu date de test
de reținut
Migrațiile = control al versiunilor pentru structura bazei de date. Definești schema în cod (schema builder), o versionezi în Git, și oricine rulează migrate obține aceeași structură. Gata cu „la mine merge, la tine nu” din diferențe de bază de date. Definirea coloanelor cu tipuri (string, text, foreignId) și timestamps() automat face schema curată și expresivă.
modul 04 / baza de date & migrații
tipuri de coloane, chei străine & seeders
tipuri de coloane frecvente
| Metodă | Tip de dată |
| $table->id() | Cheie primară auto-increment (BIGINT) |
| $table->string('nume', 100) | VARCHAR (text scurt) |
| $table->text('descriere') | TEXT (text lung) |
| $table->integer / decimal | Numere |
| $table->boolean('activ') | true/false |
| $table->date / dateTime | Date/timp |
| $table->json('setari') | Date JSON |
| $table->timestamps() | created_at + updated_at (gestionate automat) |
modificatori utili
$table->string('email')->unique(); // valoare unică
$table->text('bio')->nullable(); // poate fi NULL
$table->boolean('activ')->default(true); // valoare implicită
$table->integer('stoc')->unsigned(); // doar pozitiv
chei străine — legături între tabele
$table->foreignId('user_id')->constrained();
// creează coloana user_id + o leagă de tabelul users
// cu ștergere în cascadă:
$table->foreignId('user_id')
->constrained()->onDelete('cascade');
Cheile străine impun integritatea referențială: un articol trebuie să aparțină unui utilizator existent. onDelete('cascade') = dacă utilizatorul e șters, articolele lui se șterg automat. Aceste legături sunt baza relațiilor Eloquent (modulul 6).
seeders — populează baza cu date de test
Un seeder umple baza de date cu date inițiale sau de test — util în dezvoltare, ca să nu introduci manual conținut de fiecare dată.
php artisan make:seeder ArticolSeeder
public function run(): void
{
Articol::factory()->count(50)->create(); // 50 articole fictive
}
factories — date fictive realiste
Factory-urile definesc cum arată un model fictiv (cu date generate de Faker: nume, texte, e-mailuri false, dar realiste). Combinate cu seeders, populezi baza cu sute de înregistrări credibile într-o secundă — perfect pentru dezvoltare și teste.
// database/factories/ArticolFactory.php
public function definition(): array
{
return [
'titlu' => fake()->sentence(),
'continut' => fake()->paragraphs(3, true),
];
}
de reținut
Schema builder (tipuri + modificatori) descrie tabelele expresiv în PHP; cheile străine (foreignId->constrained) leagă tabelele și impun integritatea — fundamentul relațiilor. Seeders + factories îți umplu baza cu date realiste de test într-o comandă. Împreună cu migrațiile, ai un flux complet și profesionist pentru baza de date: definești (migrații), legi (chei străine), populezi (seeders) — totul în cod, versionat.
modul 05 / Eloquent ORM: bazele
modele Eloquent & CRUD
Eloquent e ORM-ul (Object-Relational Mapper) Laravel — cea mai iubită parte a framework-ului. Îți permite să lucrezi cu baza de date folosind obiecte PHP elegante, nu SQL brut. Un rând din tabel devine un obiect; un tabel devine o clasă model.
ce e un ORM și de ce contează
În loc de SELECT * FROM articole WHERE id = 5, scrii Articol::find(5) și primești un obiect cu care lucrezi natural. ORM-ul traduce între obiecte PHP și rânduri de bază de date. Beneficii: cod lizibil, mai puține erori, protecție automată contra SQL injection, portabilitate între baze de date.
un model
php artisan make:model Articol
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Articol extends Model
{
// atât! Eloquent deduce restul din convenții
}
convenții — mai puțin cod
- Modelul Articol (singular) → tabelul articole... de fapt Eloquent presupune pluralul englez (articols); pentru nume proprii setezi protected $table = 'articole';.
- Cheie primară: id (implicit).
- Timestamps: created_at / updated_at gestionate automat.
- Convenție peste configurare: dacă respecți convențiile, scrii cod minim.
CRUD cu Eloquent
// CREATE:
$articol = Articol::create([
'titlu' => 'Primul articol',
'continut' => 'Text...',
]);
// READ:
$toate = Articol::all(); // toate
$unul = Articol::find(5); // după id (null dacă lipsește)
$sau404 = Articol::findOrFail(5); // 404 dacă lipsește
// UPDATE:
$articol->titlu = 'Titlu nou';
$articol->save();
// sau:
$articol->update(['titlu' => 'Titlu nou']);
// DELETE:
$articol->delete();
Observă cât de citibil e — fiecare operație CRUD e o linie expresivă. Fără SQL, fără conexiuni manuale, fără riscul SQL injection.
de reținut
Eloquent transformă baza de date în obiecte PHP elegante: un model per tabel, metode expresive pentru CRUD (create, find, save, delete). Convenția peste configurare înseamnă că modelele cer cod minim. Iar findOrFail aruncă automat 404 — se leagă frumos cu route model binding (modulul 2). Următoarea lecție: interogări mai puternice și mass assignment.
modul 05 / Eloquent ORM: bazele
query builder Eloquent & mass assignment
interogări cu condiții
Eloquent îți dă un query builder fluent pentru interogări complexe, citindu-se aproape ca engleza:
// articole publicate, cele mai recente:
Articol::where('publicat', true)
->orderBy('created_at', 'desc')
->limit(10)
->get();
// primul care se potrivește:
Articol::where('titlu', 'Salut')->first();
// condiții multiple:
Articol::where('publicat', true)
->where('vizualizari', '>', 100)
->get();
metode utile
| Metodă | Ce face |
| where(col, val) | Filtrează |
| orderBy(col, dir) | Sortează |
| first() / get() | Primul rezultat / toate |
| count() / exists() | Numără / verifică existența |
| pluck('titlu') | O listă doar cu o coloană |
| paginate(15) | Paginare automată (+ linkuri în Blade!) |
paginate() e o bijuterie: îți dă paginare completă (cu link-uri gata de afișat în Blade) dintr-o singură metodă.
colecții — rezultatele nu sunt simple array-uri
Eloquent returnează colecții (Collection), nu array-uri simple. Colecțiile au metode puternice, ca în JS:
$articole->filter(fn($a) => $a->publicat);
$articole->map(fn($a) => $a->titlu);
$articole->sortBy('titlu');
$articole->pluck('titlu');
mass assignment & securitatea $fillable
Când folosești Articol::create($request->all()), umpli mai multe câmpuri deodată din datele utilizatorului — mass assignment. Pericol: un atacator ar putea trimite câmpuri neintenționate (ex: is_admin). Laravel te protejează: trebuie să declari explicit ce câmpuri sunt permise.
class Articol extends Model
{
protected $fillable = ['titlu', 'continut', 'publicat'];
// doar aceste câmpuri pot fi umplute în masă
}
- $fillable — lista albă: doar aceste câmpuri se pot seta prin create/update în masă.
- Alternativ $guarded — lista neagră (câmpuri interzise).
- Fără una dintre ele, mass assignment aruncă eroare — protecție din start. Nu ocoli asta punând tot în fillable la întâmplare.
de reținut
Query builder-ul Eloquent (where, orderBy, paginate) exprimă interogări complexe fluent și lizibil, returnând colecții bogate. Iar $fillable e o protecție de securitate esențială pentru mass assignment — declari explicit ce câmpuri pot fi umplute din input-ul utilizatorului. Eloquent e „limbajul” prin care aplicația ta vorbește cu datele; stăpânirea lui e centrală în Laravel. Următorul nivel: relațiile.
modul 06 / Eloquent: relații
tipuri de relații
Datele reale sunt legate: un utilizator are multe articole, un articol are multe comentarii, o postare are multe etichete. Eloquent modelează aceste legături elegant, ca metode pe modele — nu mai scrii JOIN-uri manual.
one-to-many (unul la mulți)
Cea mai comună relație: un utilizator are multe articole; un articol aparține unui utilizator.
// în modelul User:
public function articole()
{
return $this->hasMany(Articol::class);
}
// în modelul Articol:
public function user()
{
return $this->belongsTo(User::class);
}
Le folosești ca proprietăți, natural:
$user->articole; // colecția articolelor utilizatorului
$articol->user; // utilizatorul care a scris articolul
$articol->user->nume; // numele autorului
Eloquent știe din cheia străină (user_id, din migrația de la modulul 4) cum să lege datele. Definești relația o dată, o folosești oriunde.
tipurile principale de relații
| Relație | Exemplu | Metode |
| One-to-Many | Un user are multe articole | hasMany / belongsTo |
| One-to-One | Un user are un profil | hasOne / belongsTo |
| Many-to-Many | Un articol are multe etichete și invers | belongsToMany |
| Has-Many-Through | O țară are articole prin utilizatori | hasManyThrough |
| Polymorphic | Comentarii pe articole ȘI pe video-uri | morphMany / morphTo |
many-to-many & tabelul pivot
Un articol are multe etichete, o etichetă e pe multe articole. Legătura se ține într-un tabel pivot (ex: articol_eticheta):
// în Articol:
public function etichete()
{
return $this->belongsToMany(Eticheta::class);
}
// utilizare:
$articol->etichete; // etichetele articolului
$articol->etichete()->attach($id); // adaugă o etichetă
$articol->etichete()->detach($id); // scoate o etichetă
$articol->etichete()->sync([1, 2, 3]); // setează exact acestea
crearea prin relații
// creezi un articol legat automat de user:
$user->articole()->create([
'titlu' => 'Nou',
'continut' => '...',
]); // user_id se setează automat!
de reținut
Eloquent modelează relațiile ca metode pe modele (hasMany, belongsTo, belongsToMany), pe care apoi le accesezi ca proprietăți naturale ($user->articole). Cheile străine (migrațiile) fac legătura posibilă; relațiile o exprimă elegant. Nu mai scrii JOIN-uri — descrii legăturile o dată. Dar atenție la cum le încarci — problema N+1 din lecția următoare e capcana #1 a începătorilor Eloquent.
modul 06 / Eloquent: relații
eager loading & problema N+1
Relațiile sunt puternice, dar ascund o capcană de performanță clasică: problema N+1. E printre cele mai frecvente probleme de performanță în aplicațiile Laravel — și e ușor de evitat odată ce o înțelegi.
problema N+1
Imaginează-ți că afișezi 50 de articole, fiecare cu numele autorului:
$articole = Articol::all(); // 1 interogare
foreach ($articole as $articol) {
echo $articol->user->nume; // O INTEROGARE per articol!
}
- 1 interogare pentru articole + 50 de interogări (una per articol, pentru autor) = 51 de interogări.
- Cu 500 de articole → 501 interogări. Baza de date se sufocă, pagina se încetinește dramatic.
- Se numește N+1: 1 interogare inițială + N interogări suplimentare.
soluția: eager loading cu with()
$articole = Articol::with('user')->get();
// 2 interogări TOTAL, indiferent de câte articole!
foreach ($articole as $articol) {
echo $articol->user->nume; // deja încărcat, zero interogări suplimentare
}
with('user') spune Eloquent să încarce autorii din start, într-o singură interogare suplimentară (folosind WHERE IN). 2 interogări în loc de 51 — indiferent de numărul de articole. Aceasta e eager loading (încărcare anticipată), opusul lui lazy loading (încărcare la cerere, care produce N+1).
relații imbricate & multiple
// mai multe relații:
Articol::with(['user', 'etichete'])->get();
// relații imbricate (autorul + profilul autorului):
Articol::with('user.profil')->get();
// cu condiții:
Articol::with(['comentarii' => function ($q) {
$q->where('aprobat', true);
}])->get();
cum detectezi N+1
- Unelte precum Laravel Debugbar sau Telescope îți arată câte interogări rulează pe fiecare pagină — dacă vezi zeci/sute, ai N+1.
- Poți forța Laravel să arunce eroare la lazy loading în dezvoltare (Model::preventLazyLoading()) — te obligă să folosești with().
de reținut
Problema N+1 apare când accesezi o relație într-o buclă fără a o încărca anticipat — 1 + N interogări, dezastru de performanță. Soluția e simplă și esențială: with('relatie') (eager loading) încarcă tot din start, în 2 interogări. Regula practică: dacă accesezi o relație într-o buclă, folosește with(). Aceasta e una dintre cele mai importante lecții de performanță din tot Laravel-ul — o greșeală pe care aproape toți începătorii o fac o dată.
modul 07 / validare & procesarea formularelor
validarea input-ului
Niciodată nu ai încredere în datele de la utilizator (lecția din QA/WP se repetă). Înainte de a le salva, trebuie validate: e email-ul valid? titlul e completat? Laravel face validarea remarcabil de simplă și elegantă.
validare de bază în controller
public function store(Request $request)
{
$validat = $request->validate([
'titlu' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'varsta' => 'nullable|integer|min:18',
'continut' => 'required|min:10',
]);
// dacă ajungem aici, totul e valid:
Articol::create($validat);
return redirect('/articole');
}
Magia: dacă validarea eșuează, Laravel automat îl redirecționează pe utilizator înapoi la formular, cu erorile și cu datele introduse. Dacă trece, primești datele validate (curate) și continui. Nu scrii niciun if manual.
reguli de validare comune
| Regulă | Verifică |
| required | Câmpul e completat |
| email | Format de e-mail valid |
| min / max | Lungime/valoare minimă/maximă |
| unique:tabel | Valoarea nu există deja (ex: email unic) |
| confirmed | Are un câmp {nume}_confirmation identic (parole) |
| integer / numeric / string | Tipul valorii |
| nullable | Poate lipsi (opțional) |
| in:a,b,c | Una dintre valorile permise |
Regulile se combină cu | (sau ca array). Sunt zeci disponibile, plus reguli proprii.
afișarea erorilor în Blade
@error('titlu')
<span class="eroare">{{ $message }}</span>
@enderror
// păstrarea datelor introduse (old input):
<input name="titlu" value="{{ old('titlu') }}">
- @error('camp') — afișează mesajul de eroare pentru un câmp (dacă există).
- old('camp') — repune valoarea introdusă anterior, ca utilizatorul să nu rescrie tot formularul după o eroare. Detaliu mic, experiență mare.
de reținut
Validarea Laravel e declarativă și automată: descrii regulile (required|email|max:255), iar Laravel gestionează singur redirecționarea la eroare, mesajele și păstrarea input-ului. Combinat cu @error și old() în Blade, ai un flux complet de formular robust cu efort minim. Iar datele validate sunt curate și sigure de folosit. Următorul pas: să scoți validarea din controller pentru cod mai curat — Form Requests.
modul 07 / validare & procesarea formularelor
Form Requests, mesaje & CSRF
Form Requests — validare separată, cod curat
Când regulile de validare devin multe, aglomerează controllerul. Form Request-urile mută validarea într-o clasă dedicată — controller mai subțire, reguli reutilizabile.
php artisan make:request StoreArticolRequest
class StoreArticolRequest extends FormRequest
{
public function authorize(): bool
{
return true; // sau logică de permisiune
}
public function rules(): array
{
return [
'titlu' => 'required|max:255',
'continut' => 'required|min:10',
];
}
}
Apoi doar tastezi tipul în controller — validarea se face automat înainte de a intra în metodă:
public function store(StoreArticolRequest $request)
{
// dacă ajungem aici, e deja validat!
Articol::create($request->validated());
}
- authorize() — poate verifica și permisiunile (are dreptul acest utilizator?).
- rules() — regulile, într-un singur loc reutilizabil.
- Controllerul rămâne curat — primește deja date validate.
mesaje de eroare personalizate
public function messages(): array
{
return [
'titlu.required' => 'Titlul este obligatoriu.',
'continut.min' => 'Conținutul e prea scurt.',
];
}
Poți traduce/personaliza fiecare mesaj — util pentru interfețe în română.
protecția CSRF în formulare
Fiecare formular POST în Laravel trebuie să includă un token CSRF — protecție împotriva cererilor false (cross-site request forgery). E o singură directivă:
<form method="POST" action="/articole">
@csrf // generează token-ul ascuns — OBLIGATORIU
<input name="titlu">
<button>Salvează</button>
</form>
// pentru PUT/PATCH/DELETE (HTML acceptă doar GET/POST):
<form method="POST">
@csrf
@method('PUT') // „falsifică” verbul HTTP
</form>
- @csrf — Laravel refuză cererile POST fără token valid. Uitarea lui = eroarea „419 Page Expired”.
- @method('PUT') — fiindcă HTML acceptă doar GET/POST, „spoofezi” verbul pentru update/delete.
de reținut
Form Requests scot validarea (și autorizarea) din controller într-o clasă dedicată — cod curat, reutilizabil, cu validare automată la intrare. @csrf în fiecare formular POST e o protecție de securitate obligatorie (uitarea lui = eroarea 419). Împreună cu validarea declarativă și old()/@error, ai fluxul complet, sigur și elegant de gestionare a formularelor — una dintre zonele unde Laravel strălucește cel mai tare.
modul 08 / autentificare & autorizare
autentificarea
Aproape orice aplicație are utilizatori care se autentifică. Laravel face autentificarea sigură surprinzător de simplă — nu-ți construiești propriul sistem de parole (periculos), folosești ce oferă framework-ul.
autentificare vs autorizare
- Autentificare (authentication) — cine ești? Verificarea identității (login cu email + parolă). „Ești cine spui că ești.”
- Autorizare (authorization) — ce ai voie să faci? Verificarea permisiunilor (poți edita acest articol?). „Ai dreptul să faci asta.”
Două concepte distincte, ambele esențiale. Autentificarea vine prima (te loghezi), autorizarea a doua (ce poți face odată logat).
starter kits — autentificare gata făcută
Nu construiești login/înregistrare/resetare parolă de la zero. Laravel oferă starter kits care le generează complet:
| Kit | Ce oferă |
| Laravel Breeze | Simplu, minimal: login, register, reset parolă, verificare email — Blade + Tailwind |
| Laravel Jetstream | Mai bogat: 2FA, sesiuni, echipe, tokenuri API |
| Fortify | Doar back-end-ul de autentificare (fără UI) — pentru front-end propriu |
O comandă instalează un sistem complet de autentificare, sigur și testat. Regula de aur a securității: nu-ți scrie propriul sistem de parole/autentificare — folosește ce e verificat de mii de proiecte.
lucrul cu utilizatorul autentificat
use Illuminate\Support\Facades\Auth;
Auth::check(); // e cineva autentificat? (true/false)
Auth::user(); // obiectul utilizatorului curent
Auth::id(); // ID-ul lui
$request->user(); // tot utilizatorul (din request)
Auth::logout(); // delogare
// în Blade:
@auth
<p>Salut, {{ auth()->user()->name }}</p>
@else
<a href="/login">Autentifică-te</a>
@endauth
protejarea rutelor cu middleware auth
Route::middleware('auth')->group(function () {
Route::get('/profil', ...); // doar utilizatori logați
Route::get('/setari', ...);
});
Middleware-ul auth (modulul de rute) verifică automat autentificarea și redirecționează la login pe cei nelogați. Un filtru simplu, o protecție solidă.
de reținut
Autentificare = cine ești; autorizare = ce ai voie. Pentru autentificare, folosește starter kits (Breeze/Jetstream) — nu-ți scrie propriul sistem de parole. Auth::user() îți dă utilizatorul curent, iar middleware-ul auth protejează rutele. Cu identitatea rezolvată, întrebarea următoare e permisiunile — autorizarea prin gates & policies.
modul 08 / autentificare & autorizare
autorizarea: middleware, gates & policies
Autentificarea îți spune cine e utilizatorul. Autorizarea decide ce are voie să facă. Laravel oferă trei niveluri, de la simplu la structurat.
middleware — poarta la nivel de rută
Prima linie: middleware verifică o condiție înainte ca cererea să ajungă la controller.
// doar autentificați:
Route::get('/admin', ...)->middleware('auth');
// middleware propriu (ex: doar admini):
Route::get('/admin', ...)->middleware('admin');
Middleware-ul e ideal pentru verificări largi („trebuie să fii logat”, „trebuie să fii admin”). Pentru permisiuni fine (poți edita ACEST articol anume?), folosești gates și policies.
gates — verificări simple, punctuale
Un gate e o funcție care răspunde da/nu la o întrebare de permisiune:
// definire (într-un service provider):
Gate::define('editeaza-articol', function ($user, $articol) {
return $user->id === $articol->user_id; // e autorul?
});
// utilizare în controller:
if (Gate::allows('editeaza-articol', $articol)) {
// are voie
}
// în Blade:
@can('editeaza-articol', $articol)
<a href="...">Editează</a>
@endcan
policies — autorizare organizată per model
Când ai multe permisiuni pentru un model (vezi, creează, editează, șterge un Articol), le grupezi într-o policy — o clasă dedicată autorizării acelui model.
php artisan make:policy ArticolPolicy --model=Articol
class ArticolPolicy
{
public function update(User $user, Articol $articol): bool
{
return $user->id === $articol->user_id;
}
public function delete(User $user, Articol $articol): bool
{
return $user->id === $articol->user_id || $user->esteAdmin;
}
}
// utilizare în controller:
$this->authorize('update', $articol); // aruncă 403 dacă n-are voie
// sau:
if ($request->user()->can('update', $articol)) { ... }
- Fiecare metodă a policy-ului = o acțiune (view, create, update, delete).
- Laravel leagă automat policy-ul de model (convenție).
- authorize() aruncă automat 403 Forbidden dacă permisiunea lipsește — nu scrii if-uri peste tot.
când folosești ce
| Nivel | Pentru |
| Middleware | Verificări largi la nivel de rută (logat? admin?) |
| Gate | Permisiuni simple, punctuale, care nu țin de un model |
| Policy | Setul de permisiuni al unui model (recomandat pentru CRUD) |
de reținut
Cele trei niveluri de autorizare se completează: middleware pentru verificări largi la rută, gates pentru permisiuni simple, policies pentru setul organizat de permisiuni al unui model (calea recomandată pentru CRUD). $this->authorize() aruncă 403 automat, iar @can ascunde elegant butoanele în Blade. Împreună cu autentificarea, ai controlul complet: cine intră și ce poate face fiecare — fundamentul securității oricărei aplicații.
modul 09 / concepte avansate
service container, providers, evenimente
Sub eleganța Laravel stau câteva concepte arhitecturale puternice. Nu trebuie să le stăpânești din prima zi, dar înțelegerea lor te ridică de la „folosesc Laravel” la „înțeleg Laravel”.
service container — inima framework-ului
Ai văzut injecția de dependențe (modulul 2). Mecanismul din spate e service container-ul: un „depozit” inteligent care știe cum să construiască și să livreze obiecte. Când ceri o dependență, containerul o rezolvă (o creează cu tot ce-i trebuie) și ți-o dă.
// legi o interfață de o implementare:
$this->app->bind(PaymentGateway::class, StripeGateway::class);
// oriunde ceri PaymentGateway, primești StripeGateway
// schimbi implementarea într-un singur loc — decuplare totală
Beneficiul: cod decuplat (depinzi de interfețe, nu de clase concrete) și testabil (înlocuiești implementarea cu un mock la teste). E principiul care face aplicațiile mari mentenabile.
service providers — locul de configurare
Service providers sunt locul central unde se „înregistrează” lucrurile în aplicație: legături în container, evenimente, rute, configurări. Fiecare pachet Laravel are unul. La bootstrap, Laravel rulează toate providerele — de aici pornește totul.
evenimente & listeners — cod decuplat
Sistemul de evenimente îți permite să declanșezi „ceva s-a întâmplat” fără ca acel cod să știe cine reacționează. Ex: „un utilizator s-a înregistrat” → un listener trimite email de bun venit, altul îl adaugă la newsletter.
// declanșezi un eveniment:
UserRegistered::dispatch($user);
// listeneri separați reacționează:
// - TrimiteEmailBunVenit
// - AdaugaLaNewsletter
// codul care înregistrează userul NU știe de ei
- Decuplare: adaugi/scoți reacții fără a atinge codul care declanșează evenimentul.
- Similar cu hooks din WordPress — filozofia „anunță, nu apela direct”.
de reținut
Service container-ul (rezolvarea dependențelor) și service providers (configurarea) sunt fundația arhitecturală invizibilă a Laravel — motivul pentru care codul e decuplat și testabil. Evenimentele îți permit cod decuplat, reactiv (ca hooks). Nu trebuie să le folosești intens ca începător, dar înțelegerea lor explică de ce Laravel e construit așa și te pregătește pentru aplicații mari.
modul 09 / concepte avansate
cozi (queues), comenzi Artisan & testare
cozi (queues) — munca grea, în fundal
Unele sarcini sunt lente: trimiterea de e-mailuri, procesarea de imagini, apeluri către API-uri externe. A face utilizatorul să aștepte după ele e o experiență proastă. Cozile mută aceste sarcini în fundal, ca răspunsul să fie instant.
// în loc să trimiți email-ul acum (blochează):
Mail::to($user)->send(new BunVenit());
// îl pui la coadă (răspuns instant, email-ul pleacă în fundal):
Mail::to($user)->queue(new BunVenit());
// job propriu la coadă:
ProceseazaVideo::dispatch($video);
- Sarcina se pune într-o coadă (Redis, baza de date etc.); un proces worker (php artisan queue:work) o preia și o execută separat.
- Utilizatorul primește răspunsul imediat; munca grea se întâmplă „în spate”.
- Esențial pentru performanță și scalabilitate în aplicații reale.
comenzi Artisan proprii
Poți crea propriile comenzi CLI pentru sarcini recurente (curățenie, rapoarte, import-uri):
php artisan make:command CurataArticole
// apoi o rulezi:
php artisan articole:curata
// sau o programezi automat (scheduler), zilnic la 3:00:
// în app/Console: $schedule->command('articole:curata')->dailyAt('03:00');
Task scheduling-ul Laravel îți permite să programezi comenzi (ca un cron, dar în cod), pentru automatizări recurente.
testarea automată
Laravel are testarea în ADN — vine cu PHPUnit/Pest configurate. Testele îți dau încredere că aplicația funcționează și că nu strici nimic când modifici.
// un test simplu:
public function test_pagina_articole_se_incarca(): void
{
$response = $this->get('/articole');
$response->assertStatus(200);
}
public function test_utilizator_poate_crea_articol(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/articole', [
'titlu' => 'Test', 'continut' => 'Continut de test',
]);
$this->assertDatabaseHas('articole', ['titlu' => 'Test']);
}
- Feature tests — testează fluxuri întregi (o cerere HTTP → răspuns/efect în DB).
- Unit tests — testează bucăți izolate de logică.
- Helpers puternici: actingAs (simulează un user logat), assertDatabaseHas (verifică baza de date), factories pentru date de test.
- Rulezi cu php artisan test.
de reținut
Cozile mută munca lentă în fundal (răspuns instant pentru utilizator) — esențiale pentru performanță. Comenzile Artisan proprii + scheduler-ul automatizează sarcinile recurente. Iar testarea, integrată nativ, îți dă încrederea să dezvolți rapid fără a strica ce merge. Aceste unelte marchează trecerea de la aplicații mici la aplicații de producție, scalabile și de încredere — exact ce construiești în finalul cursului.
modul 10 / API, deploy, proiect & test final
API-uri REST & deploy
Aplicațiile moderne expun adesea un API — pentru aplicații JavaScript (React, Vue), mobile, sau integrări. Laravel excelează și aici. Plus, orice aplicație trebuie în cele din urmă livrată (deploy).
rute API
API-urile trăiesc în routes/api.php (prefixate automat cu /api, stateless — fără sesiuni):
// routes/api.php
Route::get('/articole', [ArticolController::class, 'index']);
Route::apiResource('articole', ArticolController::class);
// apiResource = resource fără rutele de formular (create/edit)
Un controller API returnează JSON, nu view-uri:
public function index()
{
return Articol::all(); // Laravel îl serializează automat în JSON!
}
API Resources — controlezi forma JSON-ului
Nu vrei mereu să expui toate coloanele brute. API Resources transformă modelele în structura JSON exactă pe care o vrei:
php artisan make:resource ArticolResource
public function toArray($request): array
{
return [
'id' => $this->id,
'titlu' => $this->titlu,
'autor' => $this->user->nume, // formatezi cum vrei
];
}
Controlezi exact ce câmpuri și ce format expune API-ul — ascunzi date interne, formatezi elegant.
autentificare API cu Sanctum
API-urile nu folosesc sesiuni; se autentifică cu tokenuri. Laravel Sanctum e soluția ușoară: emiți un token la login, clientul îl trimite în fiecare cerere (header Authorization: Bearer {token}).
// protejezi rutele API:
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('articole', ArticolController::class);
});
noțiuni de deploy
Când aplicația e gata, o pui pe un server. Pași tipici:
- Server: PHP, web server (Nginx), bază de date. Unelte care simplifică: Laravel Forge (provisioning + deploy), Envoyer (zero-downtime), Vapor (serverless pe AWS), sau platforme ca DigitalOcean/hosting dedicat.
- .env de producție: APP_ENV=production, APP_DEBUG=false (NICIODATĂ true în producție — expune erori!).
- Optimizări: php artisan config:cache, route:cache, view:cache (compilează pentru viteză), composer install --optimize-autoloader --no-dev.
- Migrații: php artisan migrate --force pe server.
- HTTPS, backup-uri, un worker pentru cozi, un cron pentru scheduler.
de reținut
Laravel face din back-end o sursă de API JSON curat: apiResource pentru rute, API Resources pentru forma răspunsului, Sanctum pentru autentificare cu token. Iar deploy-ul, deși un domeniu în sine, se simplifică enorm cu unelte ca Forge — reține doar esențialul: APP_DEBUG=false în producție, optimizările de cache, și migrațiile cu --force. Ești gata să construiești și să livrezi.
modul 10 / API, deploy, proiect & test final
proiect ghidat: aplicație completă
Pui tot cursul la lucru construind o aplicație Laravel completă — un mini-blog cu utilizatori, exact tiparul pe care se construiesc nenumărate aplicații reale. Lucrează pas cu pas, local.
ce construiești: un blog cu autori
Utilizatorii se autentifică, își scriu articole (CRUD complet), le pot edita/șterge doar pe ale lor, iar vizitatorii citesc articolele publicate.
cerințe funcționale
- Autentificare: înregistrare, login, logout (cu un starter kit).
- CRUD de articole: listă, vizualizare, creare, editare, ștergere.
- Fiecare articol aparține unui utilizator (relație); un user are multe articole.
- Autorizare: un utilizator editează/șterge doar articolele proprii (policy).
- Validare la creare/editare (Form Request).
- Categorii sau etichete (relație many-to-many) — opțional/bonus.
planul, pe modulele cursului
- Setup (mod. 0): proiect nou, .env cu baza de date, un starter kit (Breeze) pentru autentificare.
- Baza de date (mod. 4): migrație pentru articole (titlu, continut, publicat, user_id cheie străină, timestamps); un factory + seeder pentru date de test.
- Model & relații (mod. 5, 6): modelul Articol cu $fillable; relațiile Articol belongsTo User și User hasMany Articol.
- Rute & controller (mod. 1, 2): Route::resource('articole', ...) + un resource controller; rutele de scriere protejate cu middleware auth.
- Validare (mod. 7): un Form Request pentru store/update; @csrf și @error/old() în formulare.
- Autorizare (mod. 8): o ArticolPolicy (update/delete doar pentru autor); $this->authorize() în controller, @can în Blade pentru butoane.
- View-uri (mod. 3): layout comun + componente; liste cu @foreach, paginare cu paginate(); eager loading (with('user')) ca să eviți N+1 la afișarea autorilor.
definiția lui „gata”
- Te poți înregistra, autentifica, deloga.
- Poți crea/edita/șterge articole; le vezi listate (paginat) și individual.
- Nu poți edita/șterge articolele altcuiva (policy returnează 403).
- Validarea respinge input invalid, cu mesaje și input păstrat.
- Zero N+1 la afișarea autorilor (with() aplicat); @csrf pe toate formularele.
- Bonus: categorii/etichete (many-to-many), un API JSON (apiResource + Sanctum), teste pentru fluxurile principale.
felicitări
Ai parcurs Laravel de la fundamente la o aplicație completă: MVC, routing, controllere, Blade, migrații, Eloquent (CRUD, relații, N+1), validare, autentificare & autorizare, concepte avansate și API — și le-ai combinat într-un blog funcțional cu utilizatori și permisiuni. Ai acum abilitatea de a construi aplicații web reale, sigure și structurate, cu unul dintre cele mai puternice framework-uri din lume. Urmează testul final: 20 de întrebări din tot cursul. Prag: 70%. Succes!