Building Web Apps with Laravel

Laravel project structure, routing and controllers, Eloquent ORM, migrations and seeders, Blade templates, and the service container.

IntermediateUpdated 2026-10-3064K views

Project Skeleton and Artisan

composer create-project laravel/laravel shop
cd shop && php artisan serve        # http://127.0.0.1:8000

# 代码生成器
php artisan make:model Article -mfsc
#   -m 迁移 -f 工厂 -s 填充 -c 控制器
php artisan migrate                 # 执行迁移
php artisan db:seed                 # 填充测试数据
php artisan route:list              # 查看全部路由

Routing and Controllers

<?php
// routes/web.php
use App\Http\Controllers\ArticleController;

Route::get('/articles', [ArticleController::class, 'index'])
    ->name('articles.index');

Route::get('/articles/{article}', [ArticleController::class, 'show'])
    ->name('articles.show');

// routes/api.php 自动加 /api 前缀与频率限制
Route::post('/articles', [ArticleController::class, 'store']);

// 控制器
class ArticleController extends Controller {
    public function show(Article $article) {   // 路由模型绑定
        return view('articles.show', compact('article'));
    }
}

Eloquent and Migrations

<?php
// database/migrations/xxxx_create_articles_table.php
public function up(): void {
    Schema::create('articles', function (Blueprint $t) {
        $t->id();
        $t->string('title');
        $t->text('body')->nullable();
        $t->foreignId('user_id')->constrained()->cascadeOnDelete();
        $t->timestamps();
    });
}

// 模型
class Article extends Model {
    protected $fillable = ['title', 'body'];

    public function user(): BelongsTo {        // 关联
        return $this->belongsTo(User::class);
    }

    public function scopePublished($q) {       // 查询作用域
        return $q->where('published', true);
    }
}

// 使用:避免 N+1 用 with() 预加载
$articles = Article::with('user')->published()->latest()->paginate(15);
The N+1 problem is the single most common Eloquent pitfall: enable Model::preventLazyLoading() in development to turn lazy loads into exceptions.

Blade and the Service Container

<?php
{{-- resources/views/articles/show.blade.php --}}
@extends('layouts.app')
@section('title', $article->title)

@section('content')
    <h1>{{ $article->title }}</h1>
    <p>by {{ $article->user->name }}</p>
    @foreach ($article->comments as $c)
        <p>{{ $c->body }}</p>
    @endforeach
@endsection

<?php
// 服务容器:绑定接口到实现,控制器只声明类型即可
$this->app->bind(PaymentGateway::class, StripeGateway::class);

// 控制器中自动注入
public function store(Request $request, PaymentGateway $gateway) {
    $data = $request->validate(['title' => 'required|max:200']);
    $gateway->charge(100);
}

Friends & Partners