Programování

Laravel pro začátečníky: první aplikace s modelem, migrací a API

Založte projekt v Laravelu, vytvořte model s migrací, kontroler s validací a JSON API. Vysvětlení struktury, Eloquentu a příkazů Artisan.

12. 10. 2026 · 4 min čtení

Laravel je nejpopulárnější PHP framework a pro nový webový projekt v PHP bývá rozumnou výchozí volbou. Má hotové řešení pro routing, databázi, validaci, fronty i autentizaci. V tomto návodu postavíme malé API pro správu článků a projdeme klíčové pojmy.

Instalace

Laravel 12 vyžaduje PHP 8.2 nebo novější a Composer. Nový projekt založíte takto:

composer create-project laravel/laravel blog-api
cd blog-api
php artisan serve

Aplikace poběží na http://127.0.0.1:8000. Alternativně můžete použít instalátor laravel new blog-api, který se nainstaluje přes composer global require laravel/installer.

Výchozí databáze je od Laravelu 11 SQLite (soubor database/database.sqlite), takže nemusíte nic nastavovat. Pro MySQL nebo PostgreSQL upravte .env:

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=blog
DB_USERNAME=blog
DB_PASSWORD=tajne-heslo

Soubor .env nikdy necommitujte – je v .gitignore a jako šablona slouží .env.example.

Kde co je

Adresář Obsah
app/Models Eloquent modely
app/Http/Controllers kontrolery
routes/web.php webové routy
routes/api.php API routy (vzniká až příkazem install:api)
database/migrations migrace schématu
config/ konfigurace (čte hodnoty z .env)
storage/logs/laravel.log log aplikace

API routy

Od Laravelu 11 je routes/api.php volitelný. Přidáte ho příkazem:

php artisan install:api

Ten zároveň nainstaluje Laravel Sanctum pro tokenovou autentizaci. Routy v tomto souboru mají automaticky prefix /api.

Model a migrace

Jedním příkazem vytvoříte model, migraci, kontroler a form request:

php artisan make:model Article -mcR --api

Přepínače: -m migrace, -c kontroler, -R form requesty pro validaci, --api kontroler bez metod create a edit (ty slouží jen pro HTML formuláře).

Upravte migraci v database/migrations/xxxx_create_articles_table.php:

public function up(): void
{
    Schema::create('articles', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->string('slug')->unique();
        $table->text('body');
        $table->timestamp('published_at')->nullable();
        $table->timestamps();
    });
}

A spusťte ji:

php artisan migrate

V modelu app/Models/Article.php povolte hromadné přiřazení vybraných polí:

class Article extends Model
{
    protected $fillable = ['title', 'slug', 'body', 'published_at'];

    protected function casts(): array
    {
        return ['published_at' => 'datetime'];
    }
}

$fillable chrání před tím, aby si někdo poslal v požadavku třeba is_admin a model ho uložil.

Validace

app/Http/Requests/StoreArticleRequest.php:

public function authorize(): bool
{
    return true; // tady by měla být kontrola oprávnění
}

public function rules(): array
{
    return [
        'title' => ['required', 'string', 'max:200'],
        'slug'  => ['required', 'alpha_dash', 'unique:articles,slug'],
        'body'  => ['required', 'string'],
        'published_at' => ['nullable', 'date'],
    ];
}

Pokud validace selže, Laravel u požadavku s hlavičkou Accept: application/json automaticky vrátí 422 s chybami podle polí.

Kontroler

app/Http/Controllers/ArticleController.php:

class ArticleController extends Controller
{
    public function index()
    {
        return Article::whereNotNull('published_at')
            ->latest('published_at')
            ->paginate(20);
    }

    public function store(StoreArticleRequest $request)
    {
        $article = Article::create($request->validated());
        return response()->json($article, 201);
    }

    public function show(Article $article)
    {
        return $article;
    }

    public function update(UpdateArticleRequest $request, Article $article)
    {
        $article->update($request->validated());
        return $article;
    }

    public function destroy(Article $article)
    {
        $article->delete();
        return response()->noContent();
    }
}

Article $article v parametru je route model binding – Laravel podle ID z URL načte model, a pokud neexistuje, vrátí 404. paginate(20) vrátí data i metadata stránkování.

Do routes/api.php přidejte jeden řádek:

use App\Http\Controllers\ArticleController;

Route::apiResource('articles', ArticleController::class);

Výpis všech rout zobrazí php artisan route:list.

Vyzkoušení

curl -X POST http://127.0.0.1:8000/api/articles \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -d '{"title":"Ahoj Laravel","slug":"ahoj-laravel","body":"Text","published_at":"2026-10-12"}'

curl http://127.0.0.1:8000/api/articles

Bez hlavičky Accept: application/json by vás Laravel při chybě validace přesměroval zpět, jako u HTML formuláře.

Tinker na rychlé pokusy

php artisan tinker
Article::count();
Article::where('slug', 'ahoj-laravel')->first()->title;

Časté začátečnické chyby

  • N+1 dotazy – v cyklu přistupujete k relaci ($article->author->name) a pro každý řádek vznikne dotaz. Řešení: Article::with('author')->get(). Při vývoji pomůže Model::preventLazyLoading() v AppServiceProvider.
  • APP_DEBUG=true na produkci – zobrazí stack trace i hodnoty z prostředí.
  • Chybějící APP_KEY – vygenerujte php artisan key:generate.
  • Práva – webový server musí mít zápis do storage/ a bootstrap/cache/.

Před nasazením

composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize

optimize nacachuje konfiguraci, routy, události i šablony. Po každé změně .env je nutné cache obnovit znovu.

Pro práci na existujícím Laravel projektu se hodí nahrát ho do ColdHost AI jako projekt (ZIP nebo GitHub) – AI pak vidí modely i migrace pohromadě a navrhované úpravy jsou konzistentní s vaším kódem.