摘要

Laravel 12 是目前最流行的 PHP Web 框架之一,以其优雅的语法、强大的功能和完善的生态系统而闻名。本教程基于 Laravel 12 版本,详细介绍了从环境搭建、项目初始化、路由和控制器、视图到数据库操作的完整 Web 开发流程,帮助初学者快速掌握 Laravel 框架的核心概念和实战技能,为 Web 开发之旅打下坚实的基础。

Laravel 12 教程 - Web 开发实战入门

前言

欢迎阅读《Laravel 12 教程 - Web 开发实战入门》!本教程基于最新的 Laravel 12 版本,旨在帮助初学者快速掌握 Laravel 框架的核心概念和实战技能,为您的 Web 开发之旅打下坚实的基础。Laravel 12 作为 PHP 生态中最流行的 Web 框架之一,提供了简洁优雅的语法、强大的功能和完善的生态系统,是现代 Web 开发的理想选择。

为什么选择 Laravel 12?

Laravel 12 是目前最流行的 PHP Web 框架之一,它以优雅的语法、强大的功能和完善的生态系统而闻名。选择 Laravel 12 的原因包括:

  • 简洁优雅的语法:Laravel 12 提供了简洁明了的语法,让代码更加易读和易维护
  • 丰富的功能:Laravel 12 内置了路由、控制器、视图、数据库操作、认证等全套 Web 开发所需的功能
  • 强大的生态系统:Laravel 12 拥有丰富的扩展包和活跃的社区支持
  • 现代化的开发体验:Laravel 12 支持依赖注入、服务容器、中间件等现代 PHP 开发特性
  • 完善的文档:Laravel 12 提供了详尽的官方文档,学习曲线平缓
  • 性能优化:Laravel 12 在性能方面进行了多项优化,提供更快的响应速度
  • 安全性:Laravel 12 内置了多种安全特性,如 CSRF 保护、密码加密等
  • 可扩展性:Laravel 12 的模块化设计使其易于扩展和定制

本教程的目标

通过本教程的学习,您将能够:

  • 搭建 Laravel 12 开发环境
  • 理解 Laravel 12 的核心概念和工作原理
  • 掌握 Laravel 12 的基本功能和使用方法
  • 开发一个完整的 Laravel 12 Web 应用
  • 将 Laravel 12 应用部署到生产环境
  • 运用 Laravel 12 的最佳实践进行 Web 开发
  • 解决 Laravel 12 开发中常见的问题
  • 为进一步学习 Laravel 12 高级特性打下基础

前置知识

本教程适合具有以下基础的读者:

  • 基本的 PHP 编程知识
  • 基本的 HTML、CSS 和 JavaScript 知识
  • 基本的数据库概念

如果您是完全的初学者,建议先学习一些 PHP 和 Web 开发的基础知识,再开始本教程的学习。

教程结构

本教程分为以下几个部分:

  1. 环境搭建:安装 PHP、Composer 和 Laravel 12
  2. 项目初始化:创建 Laravel 12 项目和了解目录结构
  3. 路由和控制器:学习 Laravel 12 的路由系统和控制器
  4. 视图:学习 Laravel 12 的 Blade 模板引擎
  5. 数据库操作:学习 Laravel 12 的数据库操作方法
  6. 表单处理:学习 Laravel 12 的表单验证和处理
  7. 认证系统:学习 Laravel 12 的用户认证系统
  8. 文件上传和存储:学习 Laravel 12 的文件处理功能
  9. 部署:学习如何部署 Laravel 12 应用

现在,让我们开始 Laravel 的学习之旅吧!

1. Laravel 12 环境搭建

要开始使用 Laravel 12,我们需要搭建一个合适的开发环境。Laravel 12 需要以下软件:

  • PHP 8.2 或更高版本
  • Composer(PHP 依赖管理工具)
  • 数据库(MySQL、PostgreSQL、SQLite 等)

Laravel 12 对环境有特定的要求,确保您的系统满足这些要求,以便顺利运行 Laravel 12 应用。

1.1 Laravel 12 PHP 安装要求

Laravel 12 要求 PHP 8.2 或更高版本,并且需要安装以下 PHP 扩展:

  • PHP CLI
  • PHP MBString
  • PHP XML
  • PHP MySQL
  • PHP CURL
  • PHP GD
  • PHP ZIP

Windows 系统

  1. 使用 XAMPP

    • 访问 XAMPP 官网 下载最新版本的 XAMPP
    • 运行安装程序,选择安装 PHP 8.2 或更高版本
    • 安装完成后,启动 XAMPP 控制面板,启动 Apache 服务
  2. 使用 WAMP

    • 访问 WAMP 官网 下载最新版本的 WAMP
    • 运行安装程序,选择安装 PHP 8.2 或更高版本
    • 安装完成后,启动 WAMP 服务

macOS 系统

  1. 使用 Homebrew

    1
    2
    3
    4
    5
    # 安装 Homebrew(如果未安装)
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    # 安装 PHP
    brew install php
  2. 使用 MAMP

    • 访问 MAMP 官网 下载最新版本的 MAMP
    • 运行安装程序,选择安装 PHP 8.2 或更高版本
    • 安装完成后,启动 MAMP 服务

Linux 系统

  1. Ubuntu/Debian

    1
    2
    3
    4
    5
    # 更新包列表
    sudo apt update

    # 安装 PHP 8.2 及所需扩展
    sudo apt install php8.2 php8.2-cli php8.2-mbstring php8.2-xml php8.2-mysql php8.2-curl php8.2-gd php8.2-zip
  2. CentOS/RHEL

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 安装 EPEL 仓库
    sudo yum install epel-release

    # 安装 REMI 仓库
    sudo yum install https://rpms.remirepo.net/enterprise/remi-release-8.rpm

    # 启用 PHP 8.2 模块
    sudo dnf module enable php:remi-8.2

    # 安装 PHP 及所需扩展
    sudo yum install php php-cli php-mbstring php-xml php-mysqlnd php-curl php-gd php-zip

1.2 Laravel 12 Composer 安装

Composer 是 PHP 的依赖管理工具,Laravel 12 依赖于 Composer 来管理其依赖项。确保安装最新版本的 Composer 以获得最佳的 Laravel 12 开发体验。

Windows 系统

  1. 访问 Composer 官网 下载 Composer-Setup.exe
  2. 运行安装程序,按照提示完成安装
  3. 安装完成后,打开命令提示符,运行 composer --version 验证安装成功

macOS/Linux 系统

1
2
3
4
5
6
7
8
# 下载并安装 Composer
curl -sS https://getcomposer.org/installer | php

# 移动到全局路径
sudo mv composer.phar /usr/local/bin/composer

# 验证安装成功
composer --version

安装完成后,Composer 将成为 Laravel 12 项目管理的重要工具,用于安装依赖、创建项目和更新框架。

1.3 Laravel 12 安装

Laravel 12 提供了多种安装方式,我们推荐使用 Composer 或 Laravel Installer。

使用 Composer 创建 Laravel 12 项目

1
2
3
4
5
# 创建 Laravel 12 项目
composer create-project laravel/laravel:^12.0 project-name

# 进入项目目录
cd project-name

使用 Laravel Installer 安装 Laravel 12

  1. 安装 Laravel Installer

    1
    composer global require laravel/installer
  2. 添加 Composer 全局目录到 PATH

    • Windows:将 %APPDATA%\Composer\vendor\bin 添加到系统环境变量 PATH
    • macOS/Linux:将 ~/.composer/vendor/bin 添加到 ~/.bashrc~/.zshrc 文件中
  3. 创建 Laravel 12 项目

    1
    2
    3
    4
    laravel new project-name

    # 进入项目目录
    cd project-name

Laravel 12 安装完成后,您就可以开始构建现代化的 Web 应用了。

1.4 Laravel 12 验证安装

安装完成后,我们可以通过以下命令验证 Laravel 12 项目是否创建成功:

1
2
# 启动 Laravel 12 开发服务器
php artisan serve

然后在浏览器中访问 http://localhost:8000,如果看到 Laravel 12 的欢迎页面,则说明安装成功。Laravel 12 的欢迎页面通常会显示当前 Laravel 版本信息和一些快速开始的链接。

1.5 Laravel 12 数据库配置

Laravel 12 默认使用 MySQL 作为数据库,但也支持 PostgreSQL、SQLite 等其他数据库。我们需要配置数据库连接以确保 Laravel 12 应用能够正常访问数据库。

  1. 创建数据库

    • 使用 MySQL 命令行或 phpMyAdmin 创建一个新的数据库
  2. 配置 Laravel 12 数据库连接

    • 打开 .env 文件,修改数据库配置:
    1
    2
    3
    4
    5
    6
    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=your_database_name
    DB_USERNAME=your_database_username
    DB_PASSWORD=your_database_password

Laravel 12 数据库配置完成后,您就可以开始使用 Laravel 的数据库功能了,包括数据库迁移、Eloquent ORM 和查询构建器等。

现在,我们的 Laravel 12 开发环境已经搭建完成,接下来我们将创建一个新的 Laravel 12 项目并了解其目录结构。

2. Laravel 12 项目初始化和目录结构

2.1 Laravel 12 项目创建

我们已经在环境搭建章节中介绍了两种创建 Laravel 12 项目的方法,这里再简要回顾一下:

使用 Composer 创建 Laravel 12 项目

1
2
3
4
5
# 创建 Laravel 12 项目
composer create-project laravel/laravel:^12.0 project-name

# 进入项目目录
cd project-name

使用 Laravel Installer 创建 Laravel 12 项目

1
2
3
4
5
# 创建 Laravel 12 项目
laravel new project-name

# 进入项目目录
cd project-name

2.2 Laravel 12 目录结构

Laravel 12 项目的目录结构组织得非常清晰,遵循了现代 PHP 应用的最佳实践。下面是 Laravel 12 的主要目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
project-name/
├── app/ # Laravel 12 应用核心代码
│ ├── Console/ # Laravel 12 命令行工具
│ ├── Exceptions/ # Laravel 12 异常处理
│ ├── Http/ # Laravel 12 HTTP 相关代码
│ │ ├── Controllers/ # Laravel 12 控制器
│ │ ├── Middleware/ # Laravel 12 中间件
│ │ └── Requests/ # Laravel 12 请求验证
│ ├── Models/ # Laravel 12 数据模型
│ ├── Providers/ # Laravel 12 服务提供者
│ └── View/ # Laravel 12 视图相关代码
├── bootstrap/ # Laravel 12 引导文件
├── config/ # Laravel 12 配置文件
├── database/ # Laravel 12 数据库相关文件
│ ├── factories/ # Laravel 12 数据工厂
│ ├── migrations/ # Laravel 12 数据库迁移
│ └── seeders/ # Laravel 12 数据填充
├── public/ # Laravel 12 公共目录(网站根目录)
│ ├── assets/ # Laravel 12 静态资源
│ └── index.php # Laravel 12 入口文件
├── resources/ # Laravel 12 资源文件
│ ├── css/ # Laravel 12 CSS 文件
│ ├── js/ # Laravel 12 JavaScript 文件
│ └── views/ # Laravel 12 视图文件
├── routes/ # Laravel 12 路由文件
├── storage/ # Laravel 12 存储目录
│ ├── app/ # Laravel 12 应用存储
│ ├── framework/ # Laravel 12 框架存储
│ └── logs/ # Laravel 12 日志文件
├── tests/ # Laravel 12 测试文件
├── vendor/ # Laravel 12 依赖包
├── .env # Laravel 12 环境变量
├── .env.example # Laravel 12 环境变量示例
├── composer.json # Laravel 12 Composer 配置
├── package.json # Laravel 12 NPM 配置
├── phpunit.xml # Laravel 12 PHPUnit 配置
├── vite.config.js # Laravel 12 Vite 配置
└── artisan # Laravel 12 Artisan 命令行工具

Laravel 12 的目录结构设计合理,便于开发者组织和管理代码,同时也符合现代 PHP 应用的最佳实践。

2.3 Laravel 12 重要目录和文件详解

app 目录

app 目录包含了 Laravel 12 应用的核心代码,是我们开发的主要场所。

  • Console/:包含 Laravel 12 自定义的 Artisan 命令
  • Exceptions/:包含 Laravel 12 异常处理类
  • Http/:包含 Laravel 12 HTTP 相关的代码,如控制器、中间件和请求验证
  • Models/:包含 Laravel 12 Eloquent 模型类
  • Providers/:包含 Laravel 12 服务提供者类,用于注册服务和引导应用
  • View/:包含 Laravel 12 视图相关的代码,如视图组件

config 目录

config 目录包含了 Laravel 12 应用的配置文件,如数据库配置、邮件配置、缓存配置等。

database 目录

database 目录包含了 Laravel 12 数据库相关的文件:

  • factories/:包含 Laravel 12 数据工厂类,用于生成测试数据
  • migrations/:包含 Laravel 12 数据库迁移文件,用于定义数据库表结构
  • seeders/:包含 Laravel 12 数据填充类,用于填充初始数据

public 目录

public 目录是 Laravel 12 网站的根目录,包含了入口文件 index.php 和静态资源。

resources 目录

resources 目录包含了 Laravel 12 应用的资源文件:

  • css/:包含 Laravel 12 CSS 文件
  • js/:包含 Laravel 12 JavaScript 文件
  • views/:包含 Laravel 12 Blade 模板文件

routes 目录

routes 目录包含了 Laravel 12 应用的路由定义文件:

  • web.php:定义 Laravel 12 Web 路由
  • api.php:定义 Laravel 12 API 路由
  • console.php:定义 Laravel 12 控制台路由
  • channels.php:定义 Laravel 12 广播频道

storage 目录

storage 目录包含了 Laravel 12 应用的存储文件:

  • app/:用于存储 Laravel 12 应用生成的文件
  • framework/:用于存储 Laravel 12 框架生成的文件,如缓存
  • logs/:用于存储 Laravel 12 日志文件

vendor 目录

vendor 目录包含了 Laravel 12 Composer 安装的依赖包。

.env 文件

.env 文件包含了 Laravel 12 应用的环境变量,如数据库连接信息、邮件配置等。这个文件不应该提交到版本控制系统中。

artisan 文件

artisan 是 Laravel 12 的命令行工具,用于执行各种命令,如生成控制器、运行迁移等。

2.4 Laravel 12 配置文件

Laravel 12 的配置文件位于 config 目录中,采用 PHP 数组格式,易于理解和修改。下面是一些 Laravel 12 重要的配置文件:

config/app.php

Laravel 12 应用的主要配置文件,包含应用名称、时区、语言等配置。

config/database.php

Laravel 12 数据库配置文件,包含数据库连接信息。

config/mail.php

Laravel 12 邮件配置文件,包含邮件发送配置。

config/cache.php

Laravel 12 缓存配置文件,包含缓存驱动配置。

config/session.php

Laravel 12 会话配置文件,包含会话驱动配置。

Laravel 12 的配置文件设计合理,便于开发者根据项目需求进行定制和修改。

2.5 Laravel 12 环境变量

Laravel 12 使用 .env 文件来存储环境变量,这些变量可以在配置文件中使用,便于在不同环境中使用不同的配置。下面是一些 Laravel 12 重要的环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Laravel 12 应用配置
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

# Laravel 12 数据库配置
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

# Laravel 12 邮件配置
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"

Laravel 12 的环境变量设计使得应用在不同环境(如开发、测试、生产)中可以使用不同的配置,提高了应用的可移植性和安全性。

2.6 Laravel 12 Artisan 命令行工具

Artisan 是 Laravel 12 提供的命令行工具,非常强大和灵活,是 Laravel 开发中的重要工具。下面是一些 Laravel 12 常用的 Artisan 命令:

查看所有 Laravel 12 命令

1
php artisan list

生成 Laravel 12 控制器

1
php artisan make:controller ControllerName

生成 Laravel 12 模型

1
php artisan make:model ModelName

生成 Laravel 12 迁移

1
php artisan make:migration create_table_name

运行 Laravel 12 迁移

1
php artisan migrate

生成 Laravel 12 数据填充

1
php artisan make:seeder SeederName

运行 Laravel 12 数据填充

1
php artisan db:seed

启动 Laravel 12 开发服务器

1
php artisan serve

Laravel 12 Artisan 命令行工具提供了丰富的命令,大大提高了开发效率,是 Laravel 12 开发中不可或缺的工具。

2.7 Laravel 12 项目初始化示例

现在,让我们创建一个简单的 Laravel 12 项目,来熟悉一下整个流程:

  1. 创建 Laravel 12 项目

    1
    2
    composer create-project laravel/laravel:^12.0 blog
    cd blog
  2. 启动 Laravel 12 开发服务器

    1
    php artisan serve
  3. 访问 Laravel 12 应用
    在浏览器中访问 http://localhost:8000,你应该能看到 Laravel 12 的欢迎页面。

  4. 查看 Laravel 12 目录结构
    浏览 Laravel 12 项目的目录结构,了解各个目录和文件的作用。

通过这个简单的 Laravel 12 项目初始化示例,你可以快速熟悉 Laravel 12 的基本使用流程,为后续的学习打下基础。

现在,我们已经了解了 Laravel 12 项目的初始化过程和目录结构,接下来我们将学习 Laravel 12 的路由系统和控制器。

3. Laravel 12 路由和控制器

3.1 Laravel 12 路由基础

路由是 Laravel 12 应用的入口点,它定义了 URL 如何映射到应用的功能。Laravel 12 的路由定义在 routes 目录下的文件中,主要包括 web.phpapi.php。Laravel 12 的路由系统非常强大,支持多种路由类型和参数。

Laravel 12 基本路由

在 Laravel 12 的 routes/web.php 文件中,我们可以定义基本的路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use Illuminate\Support\Facades\Route;

// Laravel 12 基本 GET 路由
Route::get('/', function () {
return view('welcome');
});

// Laravel 12 基本 POST 路由
Route::post('/submit', function () {
// 处理表单提交
});

// Laravel 12 基本 PUT 路由
Route::put('/update/{id}', function ($id) {
// 更新资源
});

// Laravel 12 基本 DELETE 路由
Route::delete('/delete/{id}', function ($id) {
// 删除资源
});

Laravel 12 支持多种 HTTP 请求方法的路由,包括 GET、POST、PUT、DELETE 等,满足不同场景的需求。

Laravel 12 路由参数

我们可以在 Laravel 12 路由中定义参数,这些参数会传递给路由处理函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Laravel 12 必选路由参数
Route::get('/user/{id}', function ($id) {
return 'User ' . $id;
});

// Laravel 12 可选路由参数
Route::get('/user/{name?}', function ($name = 'Guest') {
return 'Hello ' . $name;
});

// Laravel 12 带正则表达式约束的路由参数
Route::get('/user/{id}', function ($id) {
return 'User ' . $id;
})->where('id', '[0-9]+');

// Laravel 12 全局参数约束
// 在 RouteServiceProvider 中定义

Laravel 12 的路由参数系统非常灵活,支持必选参数、可选参数和带正则表达式约束的参数,满足各种复杂场景的需求。

Laravel 12 命名路由

我们可以为 Laravel 12 路由指定一个名称,这样在生成 URL 或重定向时可以使用这个名称,提高代码的可维护性:

1
2
3
4
5
6
7
8
9
10
// Laravel 12 命名路由定义
Route::get('/user/{id}', function ($id) {
return 'User ' . $id;
})->name('user.show');

// Laravel 12 使用命名路由生成 URL
$url = route('user.show', ['id' => 1]);

// Laravel 12 使用命名路由重定向
return redirect()->route('user.show', ['id' => 1]);

Laravel 12 的命名路由系统使得 URL 生成和重定向更加灵活和可维护,特别是在路由 URL 发生变化时,只需要修改路由定义,而不需要修改所有使用该路由的地方。

Laravel 12 路由组

Laravel 12 路由组允许我们为一组路由共享属性,如中间件、命名空间、前缀等,减少代码重复:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Laravel 12 带前缀的路由组
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
return 'Admin Users';
});
Route::get('/posts', function () {
return 'Admin Posts';
});
});

// Laravel 12 带命名空间的路由组
Route::namespace('Admin')->group(function () {
// 控制器在 App\Http\Controllers\Admin 命名空间下
Route::get('/admin/users', 'UserController@index');
});

// Laravel 12 带中间件的路由组
Route::middleware('auth')->group(function () {
Route::get('/dashboard', function () {
return 'Dashboard';
});
});

Laravel 12 的路由组系统非常强大,可以组合使用多种属性,如同时指定前缀、命名空间和中间件,使路由定义更加清晰和简洁。

3.2 Laravel 12 控制器

控制器是 Laravel 12 中处理 HTTP 请求的类,它们将请求逻辑组织成可维护的方法。Laravel 12 控制器位于 app/Http/Controllers 目录中,是 MVC 架构中的重要组成部分。

创建 Laravel 12 控制器

我们可以使用 Laravel 12 Artisan 命令生成控制器:

1
2
3
4
5
6
7
8
# 创建 Laravel 12 基本控制器
php artisan make:controller UserController

# 创建 Laravel 12 资源控制器
php artisan make:controller PostController --resource

# 创建 Laravel 12 带有模型的资源控制器
php artisan make:controller CommentController --resource --model=Comment

Laravel 12 提供了多种控制器生成方式,满足不同场景的需求,提高开发效率。

Laravel 12 基本控制器

一个 Laravel 12 基本控制器如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
public function index()
{
// Laravel 12 显示用户列表
}

public function show($id)
{
// Laravel 12 显示单个用户
}

public function create()
{
// Laravel 12 显示创建用户的表单
}

public function store(Request $request)
{
// Laravel 12 存储新用户
}

public function edit($id)
{
// Laravel 12 显示编辑用户的表单
}

public function update(Request $request, $id)
{
// Laravel 12 更新用户
}

public function destroy($id)
{
// Laravel 12 删除用户
}
}

Laravel 12 基本控制器提供了一种组织请求处理逻辑的方式,将相关的方法集中在一个类中,提高代码的可维护性和可读性。

Laravel 12 资源控制器

Laravel 12 资源控制器是一种特殊的控制器,它为典型的 CRUD 操作提供了预设的方法,减少重复代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
/**
* Laravel 12 显示所有帖子
*/
public function index()
{
$posts = Post::all();
return view('posts.index', compact('posts'));
}

/**
* Laravel 12 显示创建帖子的表单
*/
public function create()
{
return view('posts.create');
}

/**
* Laravel 12 存储新帖子
*/
public function store(Request $request)
{
$post = Post::create($request->all());
return redirect()->route('posts.show', $post->id);
}

/**
* Laravel 12 显示单个帖子
*/
public function show(Post $post)
{
return view('posts.show', compact('post'));
}

/**
* Laravel 12 显示编辑帖子的表单
*/
public function edit(Post $post)
{
return view('posts.edit', compact('post'));
}

/**
* Laravel 12 更新帖子
*/
public function update(Request $request, Post $post)
{
$post->update($request->all());
return redirect()->route('posts.show', $post->id);
}

/**
* Laravel 12 删除帖子
*/
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index');
}
}

Laravel 12 资源控制器自动为 CRUD 操作生成预设方法,包括 index、create、store、show、edit、update 和 destroy,大大减少了重复代码,提高了开发效率。

3.3 Laravel 12 路由与控制器结合

我们可以将 Laravel 12 路由指向控制器的方法,而不是使用闭包函数,这样可以更好地组织代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use App\Http\Controllers\UserController;

// Laravel 12 基本路由指向控制器方法
Route::get('/users', [UserController::class, 'index']);
Route::get('/users/{id}', [UserController::class, 'show']);

// Laravel 12 资源路由
Route::resource('posts', 'PostController');

// Laravel 12 部分资源路由
Route::resource('posts', 'PostController')->only([
'index', 'show'
]);

Route::resource('posts', 'PostController')->except([
'create', 'store', 'update', 'destroy'
]);

// Laravel 12 API 资源路由(无创建和编辑方法)
Route::apiResource('products', 'ProductController');

Laravel 12 的路由与控制器结合使用,使得代码结构更加清晰,职责更加分明,提高了代码的可维护性和可读性。

3.4 Laravel 12 路由模型绑定

Laravel 12 路由模型绑定允许我们自动将路由参数绑定到对应的模型实例,减少重复代码,提高开发效率:

Laravel 12 隐式路由模型绑定

1
2
3
4
5
6
7
8
9
// Laravel 12 路由定义
Route::get('/posts/{post}', [PostController::class, 'show']);

// Laravel 12 控制器方法
public function show(Post $post)
{
// Laravel 12 会自动查找 ID 为 $post 的 Post 模型实例
return view('posts.show', compact('post'));
}

Laravel 12 显式路由模型绑定

我们可以在 Laravel 12 的 RouteServiceProvider 中定义显式绑定:

1
2
3
4
5
6
7
8
9
10
11
12
// 在 Laravel 12 RouteServiceProvider 的 boot 方法中
public function boot()
{
parent::boot();

Route::model('user', App\Models\User::class);
}

// 然后在 Laravel 12 路由中使用
Route::get('/users/{user}', function (App\Models\User $user) {
return $user;
});

Laravel 12 的路由模型绑定系统使得控制器代码更加简洁,减少了手动查找模型实例的代码,提高了代码的可读性和可维护性。

3.5 Laravel 12 中间件

Laravel 12 中间件是处理 HTTP 请求的过滤器,它们可以在请求到达控制器之前或之后执行操作,用于实现认证、日志记录、CSRF 保护等功能。

Laravel 12 应用中间件到路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Laravel 12 单个路由
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware('auth');

// Laravel 12 路由组
Route::middleware(['auth', 'admin'])->group(function () {
Route::get('/admin/dashboard', function () {
return view('admin.dashboard');
});
});

// Laravel 12 控制器
class UserController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('admin')->only('index');
$this->middleware('guest')->except('index');
}
}

Laravel 12 中间件系统非常灵活,可以应用于单个路由、路由组或整个控制器,也可以通过 onlyexcept 方法指定中间件应用于控制器的哪些方法。

3.6 Laravel 12 路由和控制器实战示例

现在,让我们创建一个简单的 Laravel 12 博客应用,来演示路由和控制器的使用:

  1. 创建 Laravel 12 控制器

    1
    php artisan make:controller PostController --resource
  2. 定义 Laravel 12 资源路由
    routes/web.php 文件中:

    1
    2
    3
    use App\Http\Controllers\PostController;

    Route::resource('posts', PostController::class);
  3. 实现 Laravel 12 控制器方法
    app/Http/Controllers/PostController.php 文件中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    namespace App\Http\Controllers;

    use Illuminate\Http\Request;

    class PostController extends Controller
    {
    public function index()
    {
    return view('posts.index');
    }

    public function create()
    {
    return view('posts.create');
    }

    public function store(Request $request)
    {
    // Laravel 12 这里我们暂时只做重定向
    return redirect()->route('posts.index');
    }

    public function show($id)
    {
    return view('posts.show', ['id' => $id]);
    }

    public function edit($id)
    {
    return view('posts.edit', ['id' => $id]);
    }

    public function update(Request $request, $id)
    {
    // Laravel 12 这里我们暂时只做重定向
    return redirect()->route('posts.show', $id);
    }

    public function destroy($id)
    {
    // Laravel 12 这里我们暂时只做重定向
    return redirect()->route('posts.index');
    }
    }
  4. 创建 Laravel 12 视图文件
    我们将在后面的章节中创建视图文件。

通过这个 Laravel 12 路由和控制器实战示例,你可以了解如何在实际项目中使用 Laravel 12 的路由和控制器,为后续的学习打下基础。

3.7 Laravel 12 路由缓存

对于 Laravel 12 生产环境,我们可以缓存路由以提高性能,减少路由解析时间:

1
2
3
4
5
# 生成 Laravel 12 路由缓存
php artisan route:cache

# 清除 Laravel 12 路由缓存
php artisan route:clear

Laravel 12 路由缓存功能可以显著提高应用的性能,特别是在路由数量较多的情况下。但需要注意的是,每次修改路由后都需要重新生成路由缓存。

3.8 Laravel 12 路由列表

我们可以使用 Laravel 12 Artisan 命令查看应用的所有路由,了解路由的定义和映射关系:

1
php artisan route:list

Laravel 12 路由列表命令会显示应用中所有已定义的路由,包括路由方法、URI、名称、对应的控制器方法等信息,是开发过程中非常有用的工具。

现在,我们已经了解了 Laravel 12 的路由系统和控制器,接下来我们将学习 Laravel 12 的视图系统。

4. Laravel 12 视图

4.1 Laravel 12 视图基础

视图是 Laravel 12 应用的用户界面,Laravel 12 使用 Blade 模板引擎来渲染视图。Laravel 12 视图文件位于 resources/views 目录中,使用 .blade.php 扩展名。Blade 模板引擎提供了简洁的语法和强大的功能,是 Laravel 12 视图系统的核心。

Laravel 12 创建视图

我们可以在 Laravel 12 的 resources/views 目录中创建视图文件,使用 .blade.php 扩展名:

1
2
3
4
5
# 创建 Laravel 12 简单视图
resources/views/welcome.blade.php

# 创建 Laravel 12 嵌套目录视图
resources/views/posts/index.blade.php

Laravel 12 支持嵌套目录结构来组织视图文件,这样可以更好地管理复杂应用的视图。

Laravel 12 渲染视图

在 Laravel 12 控制器中,我们可以使用 view 辅助函数来渲染视图,传递数据到视图:

1
2
3
4
5
6
7
8
9
10
11
12
// Laravel 12 基本渲染
return view('welcome');

// Laravel 12 渲染嵌套目录视图
return view('posts.index');

// Laravel 12 传递数据到视图
return view('welcome', ['name' => 'John']);

// Laravel 12 使用 compact 传递数据
$name = 'John';
return view('welcome', compact('name'));

Laravel 12 提供了多种渲染视图的方式,包括基本渲染、嵌套目录视图渲染和数据传递,满足不同场景的需求。

4.2 Laravel 12 Blade 模板引擎

Blade 是 Laravel 12 提供的强大模板引擎,它提供了简洁的语法和丰富的功能,是 Laravel 12 视图系统的核心组件。Laravel 12 的 Blade 模板引擎支持模板继承、包含、条件语句、循环等多种功能,使视图开发更加高效和灵活。

Laravel 12 Blade 模板引擎基本语法

Laravel 12 Blade 模板引擎提供了简洁的语法和强大的功能,以下是常用的基本语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{{-- Laravel 12 Blade 注释 --}}

{{-- Laravel 12 输出变量(自动转义) --}}
Hello, {{ $name }}!

{{-- Laravel 12 输出变量(不转义) --}}
{!! $html !!}

{{-- Laravel 12 控制结构 --}}
@if (count($posts) > 0)
There are {{ count($posts) }} posts.
@else
There are no posts.
@endif

{{-- Laravel 12 循环 --}}
@foreach ($posts as $post)
<p>{{ $post->title }}</p>
@endforeach

@for ($i = 0; $i < 10; $i++)
<p>Item {{ $i }}</p>
@endfor

@while (true)
<p>Loop forever</p>
@endwhile

{{-- Laravel 12 包含子视图 --}}
@include('partials.header')

{{-- Laravel 12 继承布局 --}}
@extends('layouts.app')

@section('content')
<p>This is the content section</p>
@endsection

Laravel 12 Blade 模板引擎的基本语法简洁明了,支持注释、变量输出、控制结构、循环、子视图包含和布局继承等功能,使视图开发更加高效和灵活。

Laravel 12 Blade 指令

Laravel 12 Blade 提供了许多有用的指令,简化视图开发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{{-- Laravel 12 条件指令 --}}
@if (condition)
// 内容
@elseif (anotherCondition)
// 内容
@else
// 内容
@endif

{{-- Laravel 12 身份验证指令 --}}
@auth
// 已登录用户可见
@endauth

@guest
// 未登录用户可见
@endguest

{{-- Laravel 12 环境指令 --}}
@env('local')
// 本地环境可见
@endenv

{{-- Laravel 12 推送到栈 --}}
@push('scripts')
<script src="/js/script.js"></script>
@endpush

{{-- Laravel 12 栈输出 --}}
@stack('scripts')

{{-- Laravel 12 组件 --}}
<x-alert type="error" :message="$message" />

{{-- Laravel 12 插槽 --}}
<x-card>
<x-slot name="header">
Card Header
</x-slot>

Card Content

<x-slot name="footer">
Card Footer
</x-slot>
</x-card>

Laravel 12 Blade 指令提供了丰富的功能,包括条件判断、身份验证状态检查、环境检测、资源管理和组件系统等,使视图开发更加简洁和高效。

Laravel 12 自定义指令

Laravel 12 允许我们在 AppServiceProvider 中定义自定义 Blade 指令,扩展 Blade 模板引擎的功能:

1
2
3
4
5
6
7
8
9
10
11
// 在 Laravel 12 AppServiceProvider 的 boot 方法中
public function boot()
{
// 定义 Laravel 12 自定义指令
Blade::directive('datetime', function ($expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}

// 在 Laravel 12 视图中使用
@datetime($date)

Laravel 12 自定义指令功能非常强大,可以根据项目需求创建各种自定义指令,简化视图代码,提高开发效率。

4.3 Laravel 12 布局

Laravel 12 布局允许我们创建一致的页面结构,减少代码重复,提高视图的可维护性。Laravel 12 布局使用 Blade 模板引擎的 @extends@yield 指令来实现,是 Laravel 12 视图系统的重要组成部分。

Laravel 12 创建布局

我们可以在 Laravel 12 中创建布局文件,定义一致的页面结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{{-- Laravel 12 布局文件: resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'Laravel 12 App')</title>
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
@stack('styles')
</head>
<body>
<header>
<nav>
<!-- Laravel 12 导航菜单 -->
</nav>
</header>

<main>
@yield('content')
</main>

<footer>
<!-- Laravel 12 页脚内容 -->
</footer>

<script src="{{ asset('js/app.js') }}"></script>
@stack('scripts')
</body>
</html>

Laravel 12 布局文件使用 @yield 指令定义内容区域,使用 @stack 指令定义可堆叠的资源区域,使页面结构更加清晰和可维护。

Laravel 12 使用布局

我们可以在 Laravel 12 视图中使用布局,继承一致的页面结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{{-- Laravel 12 视图文件: resources/views/posts/index.blade.php --}}
@extends('layouts.app')

@section('title', 'Posts')

@push('styles')
<link rel="stylesheet" href="{{ asset('css/posts.css') }}">
@endpush

@section('content')
<h1>Posts</h1>

@foreach ($posts as $post)
<div class="post">
<h2>{{ $post->title }}</h2>
<p>{{ $post->content }}</p>
</div>
@endforeach
@endsection

@push('scripts')
<script src="{{ asset('js/posts.js') }}"></script>
@endpush

Laravel 12 使用布局的方式非常简单,通过 @extends 指令继承布局文件,通过 @section 指令填充内容区域,通过 @push 指令添加页面特定的资源,使视图开发更加模块化和可维护。

4.4 Laravel 12 组件

Laravel 12 组件是可重用的视图片段,可以接受属性和插槽,使视图开发更加模块化和可维护。Laravel 12 组件系统非常强大,支持类组件和匿名组件,是 Laravel 12 视图系统的重要组成部分。

Laravel 12 创建组件

我们可以使用 Laravel 12 Artisan 命令生成组件,创建可重用的视图片段:

1
2
3
4
5
# 创建 Laravel 12 组件
php artisan make:component Alert

# 创建 Laravel 12 嵌套组件
php artisan make:component Forms/Input

Laravel 12 提供了便捷的 Artisan 命令来生成组件,支持基本组件和嵌套组件,使组件开发更加高效和规范化。

Laravel 12 组件结构

Laravel 12 组件由组件类和组件视图两部分组成,以下是组件视图的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{{-- Laravel 12 组件视图: resources/views/components/alert.blade.php --}}
<div class="alert alert-{{ $type }}">
{{ $message }}
</div>

{{-- Laravel 12 带插槽的组件 --}}
<div class="card">
@if (isset($header))
<div class="card-header">
{{ $header }}
</div>
@endif

<div class="card-body">
{{ $slot }}
</div>

@if (isset($footer))
<div class="card-footer">
{{ $footer }}
</div>
@endif
</div>

Laravel 12 组件结构支持传递属性和插槽,使组件更加灵活和可重用。组件视图使用 Blade 模板语法,可以包含 HTML、PHP 代码和 Blade 指令。

Laravel 12 使用组件

我们可以在 Laravel 12 视图中使用组件,实现视图片段的重用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{{-- Laravel 12 组件基本使用 --}}
<x-alert type="success" message="Operation completed successfully!" />

{{-- Laravel 12 组件使用插槽 --}}
<x-card>
<x-slot name="header">
<h3>Card Title</h3>
</x-slot>

<p>This is the card content.</p>

<x-slot name="footer">
<button class="btn btn-primary">Submit</button>
</x-slot>
</x-card>

Laravel 12 使用组件的方式非常简单,通过 <x-组件名> 标签来使用组件,支持传递属性和使用插槽,使视图开发更加模块化和可维护。组件是 Laravel 12 视图系统的重要组成部分,可以大大提高开发效率和代码质量。

Laravel 12 组件类

我们可以为 Laravel 12 组件创建对应的类,用于处理逻辑和数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Laravel 12 组件类: app/View/Components/Alert.php
namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
public $type;
public $message;

public function __construct($type = 'info', $message = '')
{
$this->type = $type;
$this->message = $message;
}

public function render()
{
return view('components.alert');
}
}

Laravel 12 组件类负责处理组件的逻辑和数据,通过构造函数接受属性,通过 render 方法返回组件视图,使组件开发更加模块化和可维护。组件类是 Laravel 12 组件系统的重要组成部分,为组件提供了强大的逻辑处理能力。

4.5 Laravel 12 视图助手函数

Laravel 12 提供了许多有用的视图助手函数,简化视图开发,提高开发效率:

Laravel 12 URL 助手

Laravel 12 提供了丰富的 URL 助手函数,用于生成各种类型的 URL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{{-- Laravel 12 生成应用 URL --}}
{{ url('/') }}

{{-- Laravel 12 生成安全 URL --}}
{{ secure_url('/') }}

{{-- Laravel 12 生成资源 URL --}}
{{ asset('css/app.css') }}

{{-- Laravel 12 生成路由 URL --}}
{{ route('posts.show', ['id' => 1]) }}

{{-- Laravel 12 生成控制器动作 URL --}}
{{ action([PostController::class, 'show'], ['id' => 1]) }}

Laravel 12 URL 助手函数非常强大,支持生成应用 URL、安全 URL、资源 URL、路由 URL 和控制器动作 URL 等多种类型的 URL,满足不同场景的需求。

Laravel 12 表单助手

Laravel 12 提供了表单助手函数,用于生成表单相关的 HTML 元素:

1
2
3
4
5
{{-- Laravel 12 CSRF 令牌 --}}
{{ csrf_field() }}

{{-- Laravel 12 方法字段 --}}
{{ method_field('PUT') }}

Laravel 12 表单助手函数简化了表单开发,特别是 CSRF 保护和 HTTP 方法伪造等功能,提高了表单的安全性和可靠性。

Laravel 12 认证助手

Laravel 12 提供了认证助手函数,用于检查用户认证状态和获取用户信息:

1
2
3
4
5
{{-- Laravel 12 检查用户是否已认证 --}}
{{ auth()->check() }}

{{-- Laravel 12 获取当前用户 --}}
{{ auth()->user() }}

Laravel 12 认证助手函数简化了用户认证相关的操作,使视图中可以方便地检查用户状态和获取用户信息,提高了视图开发的效率和可读性。

4.6 Laravel 12 视图实战示例

现在,让我们为之前创建的 Laravel 12 博客应用创建视图文件,演示 Laravel 12 视图系统的实际使用:

  1. 创建 Laravel 12 布局文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    {{-- Laravel 12 布局文件: resources/views/layouts/app.blade.php --}}
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'Laravel 12 Blog')</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
    </head>
    <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container">
    <a class="navbar-brand" href="{{ route('posts.index') }}">Laravel 12 Blog</a>
    <div class="collapse navbar-collapse">
    <ul class="navbar-nav mr-auto">
    <li class="nav-item">
    <a class="nav-link" href="{{ route('posts.index') }}">Home</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" href="{{ route('posts.create') }}">Create Post</a>
    </li>
    </ul>
    </div>
    </div>
    </nav>

    <div class="container mt-4">
    @yield('content')
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    </body>
    </html>
  2. 创建 Laravel 12 帖子列表视图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    {{-- Laravel 12 帖子列表视图: resources/views/posts/index.blade.php --}}
    @extends('layouts.app')

    @section('title', 'Posts')

    @section('content')
    <h1>Posts</h1>

    <div class="mb-4">
    <a href="{{ route('posts.create') }}" class="btn btn-primary">Create Post</a>
    </div>

    <div class="list-group">
    <!-- Laravel 12 暂时使用模拟数据 -->
    <a href="{{ route('posts.show', ['id' => 1]) }}" class="list-group-item list-group-item-action">
    <h5 class="mb-1">Post 1</h5>
    <p class="mb-1">This is the first post.</p>
    </a>
    <a href="{{ route('posts.show', ['id' => 2]) }}" class="list-group-item list-group-item-action">
    <h5 class="mb-1">Post 2</h5>
    <p class="mb-1">This is the second post.</p>
    </a>
    </div>
    @endsection
  3. 创建 Laravel 12 帖子创建视图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    {{-- Laravel 12 帖子创建视图: resources/views/posts/create.blade.php --}}
    @extends('layouts.app')

    @section('title', 'Create Post')

    @section('content')
    <h1>Create Post</h1>

    <form action="{{ route('posts.store') }}" method="POST">
    @csrf

    <div class="mb-3">
    <label for="title" class="form-label">Title</label>
    <input type="text" class="form-control" id="title" name="title" required>
    </div>

    <div class="mb-3">
    <label for="content" class="form-label">Content</label>
    <textarea class="form-control" id="content" name="content" rows="3" required></textarea>
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
    </form>
    @endsection
  4. 创建 Laravel 12 帖子显示视图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    {{-- Laravel 12 帖子显示视图: resources/views/posts/show.blade.php --}}
    @extends('layouts.app')

    @section('title', 'Post')

    @section('content')
    <h1>Post {{ $id }}</h1>

    <div class="card">
    <div class="card-body">
    <h5 class="card-title">Post {{ $id }}</h5>
    <p class="card-text">This is post {{ $id }} content.</p>
    <a href="{{ route('posts.edit', ['id' => $id]) }}" class="btn btn-primary">Edit</a>
    <form action="{{ route('posts.destroy', ['id' => $id]) }}" method="POST" style="display: inline;">
    @csrf
    @method('DELETE')
    <button type="submit" class="btn btn-danger">Delete</button>
    </form>
    <a href="{{ route('posts.index') }}" class="btn btn-secondary">Back</a>
    </div>
    </div>
    @endsection
  5. 创建 Laravel 12 帖子编辑视图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    {{-- Laravel 12 帖子编辑视图: resources/views/posts/edit.blade.php --}}
    @extends('layouts.app')

    @section('title', 'Edit Post')

    @section('content')
    <h1>Edit Post {{ $id }}</h1>

    <form action="{{ route('posts.update', ['id' => $id]) }}" method="POST">
    @csrf
    @method('PUT')

    <div class="mb-3">
    <label for="title" class="form-label">Title</label>
    <input type="text" class="form-control" id="title" name="title" value="Post {{ $id }}" required>
    </div>

    <div class="mb-3">
    <label for="content" class="form-label">Content</label>
    <textarea class="form-control" id="content" name="content" rows="3" required>This is post {{ $id }} content.</textarea>
    </div>

    <button type="submit" class="btn btn-primary">Update</button>
    <a href="{{ route('posts.show', ['id' => $id]) }}" class="btn btn-secondary">Cancel</a>
    </form>
    @endsection

4.7 Laravel 12 视图缓存

对于 Laravel 12 生产环境,Laravel 12 会自动缓存编译后的 Blade 模板,以提高性能。视图缓存可以显著减少模板编译时间,提升应用响应速度:

1
2
3
4
5
# Laravel 12 清除视图缓存
php artisan view:clear

# Laravel 12 预热视图缓存
php artisan view:cache

Laravel 12 视图缓存机制非常智能,当模板文件发生变化时,会自动重新编译,确保视图始终是最新的。在生产环境中使用视图缓存可以显著提升 Laravel 12 应用的性能,减少服务器负载,提高用户体验。

现在,我们已经了解了 Laravel 12 的视图系统,接下来我们将学习 Laravel 12 的数据库操作。

5. Laravel 12 数据库操作

Laravel 12 提供了多种数据库操作方式,包括数据库迁移、Eloquent ORM、查询构建器和原始 SQL 查询。Laravel 12 的数据库操作非常强大和灵活,支持多种数据库系统,如 MySQL、PostgreSQL、SQLite 和 SQL Server 等。

5.1 Laravel 12 数据库配置

Laravel 12 的数据库配置位于 config/database.php 文件中,我们可以在 .env 文件中设置数据库连接信息。Laravel 12 支持多种数据库系统,包括 MySQL、PostgreSQL、SQLite 和 SQL Server 等,配置简单直观。

Laravel 12 配置数据库连接

Laravel 12 支持多种数据库系统,我们可以在 .env 文件中配置数据库连接信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Laravel 12 MySQL 配置
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

# Laravel 12 PostgreSQL 配置
# DB_CONNECTION=pgsql
# DB_HOST=127.0.0.1
# DB_PORT=5432
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=

# Laravel 12 SQLite 配置
# DB_CONNECTION=sqlite
# DB_DATABASE=/path/to/database.sqlite

Laravel 12 的数据库配置非常灵活,我们可以根据项目需求选择不同的数据库系统,并在 .env 文件中设置相应的连接信息。

5.2 Laravel 12 数据库迁移

Laravel 12 数据库迁移是一种版本控制数据库结构的方法,允许我们定义和修改数据库表结构。Laravel 12 数据库迁移使用 PHP 代码来定义数据库结构,而不是 SQL 语句,使数据库结构管理更加灵活和可维护。

Laravel 12 创建迁移

我们可以使用 Laravel 12 Artisan 命令生成迁移,创建数据库表结构:

1
2
3
4
5
6
7
8
# Laravel 12 创建迁移
php artisan make:migration create_users_table

# Laravel 12 创建带表结构的迁移
php artisan make:migration create_users_table --create=users

# Laravel 12 创建修改表的迁移
php artisan make:migration add_email_to_users_table --table=users

Laravel 12 提供了便捷的 Artisan 命令来生成迁移文件,支持创建新表和修改现有表的迁移,使数据库结构管理更加高效和规范化。

Laravel 12 迁移结构

Laravel 12 迁移文件由一个包含 up()down() 方法的类组成,结构清晰,易于维护:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
/**
* 运行迁移
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}

/**
* 回滚迁移
*/
public function down()
{
Schema::dropIfExists('users');
}
}

Laravel 12 迁移结构设计合理,up() 方法用于创建或修改数据库表结构,down() 方法用于回滚这些更改,使数据库结构管理更加灵活和可维护。

Laravel 12 运行迁移

我们可以使用 Laravel 12 Artisan 命令运行和管理迁移,执行数据库结构变更:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Laravel 12 运行所有未运行的迁移
php artisan migrate

# Laravel 12 回滚最后一次迁移
php artisan migrate:rollback

# Laravel 12 回滚所有迁移
php artisan migrate:reset

# Laravel 12 回滚所有迁移并重新运行
php artisan migrate:fresh

# Laravel 12 回滚所有迁移并重新运行,同时运行种子
php artisan migrate:fresh --seed

Laravel 12 提供了完整的迁移管理命令,支持运行、回滚、重置和刷新迁移等操作,使数据库结构管理更加灵活和可控。

Laravel 12 迁移列类型

Laravel 12 提供了多种列类型,用于定义数据库表字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$table->id(); // Laravel 12 自增 ID
$table->string('name'); // Laravel 12 字符串
$table->text('description'); // Laravel 12 文本
$table->integer('age'); // Laravel 12 整数
$table->bigInteger('price'); // Laravel 12 大整数
$table->float('rate'); // Laravel 12 浮点数
$table->double('score'); // Laravel 12 双精度浮点数
$table->decimal('amount', 8, 2); // Laravel 12 小数
$table->boolean('active'); // Laravel 12 布尔值
$table->date('birthday'); // Laravel 12 日期
$table->time('time'); // Laravel 12 时间
$table->datetime('created_at'); // Laravel 12 日期时间
$table->timestamp('updated_at'); // Laravel 12 时间戳
$table->json('data'); // Laravel 12 JSON
$table->enum('status', ['active', 'inactive']); // Laravel 12 枚举
$table->foreignId('user_id'); // Laravel 12 外键

Laravel 12 提供了丰富的列类型,满足不同场景的数据库字段需求,使数据库结构定义更加灵活和精确。

Laravel 12 列修饰符

Laravel 12 提供了多种列修饰符,用于定义数据库字段的属性:

1
2
3
4
5
6
7
$table->string('name')->nullable(); // Laravel 12 可为空
$table->string('email')->unique(); // Laravel 12 唯一
$table->string('password')->default('secret'); // Laravel 12 默认值
$table->integer('age')->unsigned(); // Laravel 12 无符号
$table->string('name')->length(100); // Laravel 12 长度
$table->integer('order')->autoIncrement(); // Laravel 12 自增
$table->string('name')->comment('用户名称'); // Laravel 12 注释

Laravel 12 列修饰符非常强大,可以定义字段的各种属性,如可为空、唯一、默认值、长度、自增和注释等,使数据库字段定义更加精确和灵活。

Laravel 12 索引

Laravel 12 提供了多种索引类型,用于优化数据库查询性能:

1
2
3
4
5
6
7
$table->index('email'); // Laravel 12 普通索引
$table->unique('email'); // Laravel 12 唯一索引
$table->primary('id'); // Laravel 12 主键
$table->foreign('user_id')->references('id')->on('users'); // Laravel 12 外键

// Laravel 12 复合索引
$table->index(['first_name', 'last_name']);

Laravel 12 索引非常强大,可以定义普通索引、唯一索引、主键和外键等多种类型的索引,以及复合索引,大大提高数据库查询性能。

5.3 Laravel 12 数据库填充

Laravel 12 数据库填充用于向数据库中添加初始数据,如默认用户、配置数据等。Laravel 12 数据库填充使用填充器和模型工厂来生成和插入数据,使数据填充更加高效和灵活。

Laravel 12 创建填充器

我们可以使用 Laravel 12 Artisan 命令创建填充器和模型工厂,用于生成和插入初始数据:

1
2
3
4
5
# Laravel 12 创建填充器
php artisan make:seeder UserSeeder

# Laravel 12 创建模型工厂
php artisan make:factory UserFactory

Laravel 12 提供了便捷的 Artisan 命令来创建填充器和模型工厂,使数据填充更加高效和规范化。

Laravel 12 填充器结构

Laravel 12 填充器由一个包含 run() 方法的类组成,用于向数据库中插入初始数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class UserSeeder extends Seeder
{
/**
* 运行数据库填充
*/
public function run()
{
DB::table('users')->insert([
'name' => 'Admin',
'email' => 'admin@example.com',
'password' => bcrypt('password'),
]);
}
}

Laravel 12 填充器结构设计合理,通过 run() 方法执行数据填充操作,可以使用 DB 门面或模型工厂来插入数据,使数据填充更加灵活和可控。

Laravel 12 模型工厂

Laravel 12 模型工厂用于生成模型的测试数据,支持使用 Faker 库生成各种类型的假数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class UserFactory extends Factory
{
/**
* Laravel 12 模型关联
*/
protected $model = User::class;

/**
* 定义模型默认状态
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => bcrypt('password'),
'remember_token' => Str::random(10),
];
}
}

Laravel 12 模型工厂非常强大,支持生成各种类型的假数据,如姓名、邮箱、地址等,使数据填充更加高效和灵活。

Laravel 12 使用模型工厂

我们可以在 Laravel 12 填充器中使用模型工厂来生成和插入大量测试数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use App\Models\User;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
/**
* 运行数据库填充
*/
public function run()
{
// Laravel 12 创建 10 个用户
User::factory()->count(10)->create();

// Laravel 12 创建带特定属性的用户
User::factory()->count(5)->create([
'role' => 'admin',
]);
}
}

Laravel 12 模型工厂非常强大,可以快速生成大量测试数据,也可以指定特定属性,使数据填充更加灵活和可控。

Laravel 12 运行填充器

我们可以使用 Laravel 12 Artisan 命令运行填充器,向数据库中插入初始数据:

1
2
3
4
5
6
7
8
# Laravel 12 运行指定填充器
php artisan db:seed --class=UserSeeder

# Laravel 12 运行所有填充器
php artisan db:seed

# Laravel 12 重新迁移并运行填充器
php artisan migrate:fresh --seed

Laravel 12 提供了完整的填充器管理命令,支持运行指定填充器、运行所有填充器,以及重新迁移并运行填充器等操作,使数据填充更加灵活和可控。

5.4 Laravel 12 Eloquent ORM

Eloquent 是 Laravel 12 提供的 ORM(对象关系映射),允许我们使用 PHP 对象来操作数据库。Laravel 12 Eloquent ORM 非常强大,支持模型关联、查询作用域、访问器和修改器等多种功能,使数据库操作更加简洁和优雅。

Laravel 12 创建模型

我们可以使用 Laravel 12 Artisan 命令创建模型,定义数据库表结构的 PHP 表示:

1
2
3
4
5
6
7
8
# Laravel 12 创建模型
php artisan make:model User

# Laravel 12 创建模型和迁移
php artisan make:model User -m

# Laravel 12 创建模型、迁移和控制器
php artisan make:model User -mcr

Laravel 12 提供了便捷的 Artisan 命令来创建模型,支持创建带迁移和控制器的模型,使模型开发更加高效和规范化。

Laravel 12 模型结构

Laravel 12 模型由一个继承自 Model 类的 PHP 类组成,结构清晰,易于维护:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
use HasFactory;

/**
* Laravel 12 可批量赋值的属性
*/
protected $fillable = [
'name',
'email',
'password',
];

/**
* Laravel 12 隐藏的属性
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* Laravel 12 类型转换
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}

Laravel 12 模型结构设计合理,支持定义可批量赋值的属性、隐藏的属性和类型转换等,使模型操作更加安全和灵活。

Laravel 12 基本查询

Laravel 12 Eloquent ORM 提供了丰富的查询方法,用于从数据库中检索数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use App\Models\User;

// Laravel 12 获取所有记录
$users = User::all();

// Laravel 12 根据 ID 获取记录
$user = User::find(1);

// Laravel 12 根据条件获取记录
$user = User::where('email', 'admin@example.com')->first();

// Laravel 12 获取符合条件的所有记录
$users = User::where('age', '>', 18)->get();

// Laravel 12 排序
$users = User::orderBy('name', 'asc')->get();

// Laravel 12 分页
$users = User::paginate(10);

// Laravel 12 聚合函数
$count = User::count();
$max = User::max('age');
$min = User::min('age');
$avg = User::avg('age');
$sum = User::sum('score');

Laravel 12 基本查询非常强大,支持获取所有记录、根据 ID 获取记录、根据条件获取记录、排序、分页和聚合函数等多种操作,使数据库查询更加简洁和优雅。

Laravel 12 创建记录

Laravel 12 Eloquent ORM 提供了多种方法来创建数据库记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Laravel 12 使用 create 方法
$user = User::create([
'name' => 'John Doe',
'email' => 'john@example.com',
'password' => bcrypt('password'),
]);

// Laravel 12 使用 save 方法
$user = new User;
$user->name = 'John Doe';
$user->email = 'john@example.com';
$user->password = bcrypt('password');
$user->save();

Laravel 12 创建记录非常简单,支持使用 create 方法和 save 方法来创建数据库记录,使数据插入操作更加简洁和优雅。

Laravel 12 更新记录

Laravel 12 Eloquent ORM 提供了多种方法来更新数据库记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Laravel 12 使用 update 方法
$user = User::find(1);
$user->update([
'name' => 'Jane Doe',
]);

// Laravel 12 使用 save 方法
$user = User::find(1);
$user->name = 'Jane Doe';
$user->save();

// Laravel 12 批量更新
User::where('active', 1)->update(['status' => 'verified']);

Laravel 12 更新记录非常灵活,支持使用 update 方法、save 方法和批量更新来修改数据库记录,使数据更新操作更加简洁和优雅。

Laravel 12 删除记录

Laravel 12 Eloquent ORM 提供了多种方法来删除数据库记录:

1
2
3
4
5
6
7
8
9
10
// Laravel 12 使用 delete 方法
$user = User::find(1);
$user->delete();

// Laravel 12 使用 destroy 方法
User::destroy(1);
User::destroy([1, 2, 3]);

// Laravel 12 批量删除
User::where('active', 0)->delete();

Laravel 12 删除记录非常灵活,支持使用 delete 方法、destroy 方法和批量删除来移除数据库记录,使数据删除操作更加简洁和优雅。

Laravel 12 软删除

Laravel 12 Eloquent ORM 支持软删除,允许我们标记记录为已删除而不是真正从数据库中删除:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Laravel 12 在模型中启用软删除
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model
{
use HasFactory, SoftDeletes;
}

// Laravel 12 添加 deleted_at 字段到迁移
$table->softDeletes();

// Laravel 12 软删除记录
$user = User::find(1);
$user->delete();

// Laravel 12 查询包含软删除的记录
$users = User::withTrashed()->get();

// Laravel 12 只查询软删除的记录
$users = User::onlyTrashed()->get();

// Laravel 12 恢复软删除的记录
$user = User::withTrashed()->find(1);
$user->restore();

// Laravel 12 强制删除记录
$user = User::withTrashed()->find(1);
$user->forceDelete();

Laravel 12 软删除非常强大,支持标记记录为已删除、恢复软删除的记录、强制删除记录和查询软删除的记录等操作,使数据删除操作更加灵活和安全。

5.5 Laravel 12 关联关系

Laravel 12 Eloquent ORM 支持多种关联关系:一对一、一对多、多对多、多态关联等。Laravel 12 关联关系非常强大,允许我们轻松定义和查询模型之间的关系,使数据库操作更加简洁和优雅。

Laravel 12 一对一关联

Laravel 12 Eloquent ORM 支持一对一关联,允许我们定义两个模型之间的一对一关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Laravel 12 User 模型
public function profile()
{
return $this->hasOne(Profile::class);
}

// Laravel 12 Profile 模型
public function user()
{
return $this->belongsTo(User::class);
}

// Laravel 12 使用关联
$user = User::find(1);
$profile = $user->profile;

$profile = Profile::find(1);
$user = $profile->user;

Laravel 12 一对一关联非常强大,支持定义关联关系、使用关联和反向使用关联等操作,使模型之间的关系管理更加简洁和优雅。

Laravel 12 一对多关联

Laravel 12 Eloquent ORM 支持一对多关联,允许我们定义一个模型与多个其他模型之间的关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Laravel 12 Post 模型
public function comments()
{
return $this->hasMany(Comment::class);
}

// Laravel 12 Comment 模型
public function post()
{
return $this->belongsTo(Post::class);
}

// Laravel 12 使用关联
$post = Post::find(1);
$comments = $post->comments;

$comment = Comment::find(1);
$post = $comment->post;

Laravel 12 一对多关联非常强大,支持定义关联关系、使用关联和反向使用关联等操作,使模型之间的关系管理更加简洁和优雅。

Laravel 12 多对多关联

Laravel 12 Eloquent ORM 支持多对多关联,允许我们定义两个模型之间的多对多关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Laravel 12 User 模型
public function roles()
{
return $this->belongsToMany(Role::class);
}

// Laravel 12 Role 模型
public function users()
{
return $this->belongsToMany(User::class);
}

// Laravel 12 使用关联
$user = User::find(1);
$roles = $user->roles;

$role = Role::find(1);
$users = $role->users;

// Laravel 12 附加关联
$user->roles()->attach($roleId);

// Laravel 12 分离关联
$user->roles()->detach($roleId);

// Laravel 12 同步关联
$user->roles()->sync([1, 2, 3]);

Laravel 12 多对多关联非常强大,支持定义关联关系、使用关联、附加关联、分离关联和同步关联等操作,使模型之间的关系管理更加简洁和优雅。

Laravel 12 关联查询

Laravel 12 Eloquent ORM 提供了多种方法来查询关联数据,优化数据库查询性能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Laravel 12 预加载关联
$users = User::with('profile')->get();

// Laravel 12 嵌套预加载
$posts = Post::with('comments.user')->get();

// Laravel 12 延迟预加载
$users = User::all();
$users->load('profile');

// Laravel 12 条件预加载
$users = User::with(['profile' => function ($query) {
$query->where('active', 1);
}])->get();

Laravel 12 关联查询非常强大,支持预加载关联、嵌套预加载、延迟预加载和条件预加载等操作,大大提高了数据库查询性能,避免了 N+1 查询问题。

5.6 Laravel 12 查询构建器

Laravel 12 查询构建器提供了一种流畅的接口来构建 SQL 查询,支持各种数据库操作。Laravel 12 查询构建器非常强大,允许我们使用链式方法来构建复杂的 SQL 查询,而不需要直接编写 SQL 语句。

Laravel 12 基本查询

Laravel 12 查询构建器提供了丰富的方法来构建和执行 SQL 查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Illuminate\Support\Facades\DB;

// Laravel 12 选择
$users = DB::table('users')->get();

// Laravel 12 条件
$users = DB::table('users')->where('age', '>', 18)->get();

// Laravel 12 排序
$users = DB::table('users')->orderBy('name', 'asc')->get();

// Laravel 12 限制
$users = DB::table('users')->limit(10)->offset(5)->get();

// Laravel 12 聚合
$count = DB::table('users')->count();
$max = DB::table('users')->max('age');

Laravel 12 基本查询非常强大,支持选择、条件、排序、限制和聚合等操作,使数据库查询更加简洁和优雅。

Laravel 12 连接

Laravel 12 查询构建器支持多种类型的数据库连接,用于关联多个表的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Laravel 12 内连接
$users = DB::table('users')
->join('profiles', 'users.id', '=', 'profiles.user_id')
->select('users.*', 'profiles.bio')
->get();

// Laravel 12 左连接
$users = DB::table('users')
->leftJoin('profiles', 'users.id', '=', 'profiles.user_id')
->select('users.*', 'profiles.bio')
->get();

// Laravel 12 右连接
$users = DB::table('users')
->rightJoin('profiles', 'users.id', '=', 'profiles.user_id')
->select('users.*', 'profiles.bio')
->get();

// Laravel 12 交叉连接
$users = DB::table('users')
->crossJoin('roles')
->get();

Laravel 12 连接非常强大,支持内连接、左连接、右连接和交叉连接等多种类型的连接操作,使多表查询更加简洁和优雅。

Laravel 12 高级条件

Laravel 12 查询构建器支持多种高级条件查询,允许我们构建复杂的查询条件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Laravel 12 基本条件
$users = DB::table('users')->where('age', '>', 18)->get();

// Laravel 12 多个条件
$users = DB::table('users')
->where('age', '>', 18)
->where('active', 1)
->get();

// Laravel 12 或条件
$users = DB::table('users')
->where('age', '>', 18)
->orWhere('active', 1)
->get();

// Laravel 12 分组条件
$users = DB::table('users')
->where(function ($query) {
$query->where('age', '>', 18)
->orWhere('active', 1);
})
->where('verified', 1)
->get();

// Laravel 12 范围条件
$users = DB::table('users')
->whereBetween('age', [18, 30])
->get();

// Laravel 12 列表条件
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();

// Laravel 12 空值条件
$users = DB::table('users')
->whereNull('email_verified_at')
->get();

Laravel 12 高级条件非常强大,支持基本条件、多个条件、或条件、分组条件、范围条件、列表条件和空值条件等多种查询方式,使复杂查询的构建更加简洁和优雅。

Laravel 12 插入、更新和删除

Laravel 12 查询构建器支持插入、更新和删除操作,用于修改数据库中的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Laravel 12 插入
DB::table('users')->insert([
'name' => 'John Doe',
'email' => 'john@example.com',
]);

// Laravel 12 插入并返回 ID
$id = DB::table('users')->insertGetId([
'name' => 'John Doe',
'email' => 'john@example.com',
]);

// Laravel 12 批量插入
DB::table('users')->insert([
['name' => 'John Doe', 'email' => 'john@example.com'],
['name' => 'Jane Doe', 'email' => 'jane@example.com'],
]);

// Laravel 12 更新
DB::table('users')->where('id', 1)->update([
'name' => 'Jane Doe',
]);

// Laravel 12 自增
DB::table('users')->where('id', 1)->increment('age');

// Laravel 12 自减
DB::table('users')->where('id', 1)->decrement('age');

// Laravel 12 删除
DB::table('users')->where('id', 1)->delete();

// Laravel 12 截断表
DB::table('users')->truncate();

Laravel 12 插入、更新和删除操作非常强大,支持插入单条记录、插入并返回 ID、批量插入、更新记录、自增、自减、删除记录和截断表等操作,使数据修改更加简洁和优雅。

5.7 Laravel 12 原始 SQL 查询

在某些情况下,我们可能需要使用原始 SQL 查询。Laravel 12 支持执行原始 SQL 查询,允许我们直接编写和执行 SQL 语句,为复杂查询提供更大的灵活性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Laravel 12 原始选择
$users = DB::select('SELECT * FROM users WHERE active = ?', [1]);

// Laravel 12 原始插入
DB::insert('INSERT INTO users (name, email) VALUES (?, ?)', ['John Doe', 'john@example.com']);

// Laravel 12 原始更新
DB::update('UPDATE users SET active = ? WHERE id = ?', [1, 1]);

// Laravel 12 原始删除
DB::delete('DELETE FROM users WHERE id = ?', [1]);

// Laravel 12 原始语句
DB::statement('DROP TABLE IF EXISTS users');

// Laravel 12 事务中的原始查询
DB::transaction(function () {
DB::update('UPDATE users SET votes = votes + 1 WHERE id = ?', [1]);
DB::delete('DELETE FROM posts WHERE user_id = ?', [1]);
});

5.8 Laravel 12 事务

Laravel 12 事务用于确保一系列数据库操作要么全部成功,要么全部失败,保证数据的一致性和完整性。

Laravel 12 自动事务

1
2
3
4
5
6
7
use Illuminate\Support\Facades\DB;

DB::transaction(function () {
// Laravel 12 数据库操作
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});

Laravel 12 手动事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Illuminate\Support\Facades\DB;

// Laravel 12 开始事务
DB::beginTransaction();

try {
// Laravel 12 数据库操作
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();

// Laravel 12 提交事务
DB::commit();
} catch (\Exception $e) {
// Laravel 12 回滚事务
DB::rollBack();

// 处理异常
}

Laravel 12 事务嵌套

1
2
3
4
5
6
7
8
9
DB::transaction(function () {
// Laravel 12 数据库操作
DB::table('users')->update(['votes' => 1]);

DB::transaction(function () {
// Laravel 12 数据库操作
DB::table('posts')->delete();
}, 5); // 最多尝试 5 次
}, 3); // 最多尝试 3 次

Laravel 12 事务非常强大,支持自动事务、手动事务和事务嵌套等多种方式,并提供了事务重试机制,使数据库操作更加安全和可靠。

5.9 Laravel 12 实战示例

现在,让我们为之前创建的 Laravel 12 博客应用添加数据库功能:

  1. 创建帖子迁移

    1
    php artisan make:migration create_posts_table
  2. 编辑迁移文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;

    class CreatePostsTable extends Migration
    {
    public function up()
    {
    Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('content');
    $table->timestamps();
    });
    }

    public function down()
    {
    Schema::dropIfExists('posts');
    }
    }
  3. 运行迁移

    1
    php artisan migrate
  4. 创建帖子模型

    1
    php artisan make:model Post
  5. 编辑模型文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    namespace App\Models;

    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;

    class Post extends Model
    {
    use HasFactory;

    protected $fillable = [
    'title',
    'content',
    ];
    }
  6. 更新控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    namespace App\Http\Controllers;

    use App\Models\Post;
    use Illuminate\Http\Request;

    class PostController extends Controller
    {
    public function index()
    {
    $posts = Post::all();
    return view('posts.index', compact('posts'));
    }

    public function create()
    {
    return view('posts.create');
    }

    public function store(Request $request)
    {
    Post::create($request->all());
    return redirect()->route('posts.index');
    }

    public function show(Post $post)
    {
    return view('posts.show', compact('post'));
    }

    public function edit(Post $post)
    {
    return view('posts.edit', compact('post'));
    }

    public function update(Request $request, Post $post)
    {
    $post->update($request->all());
    return redirect()->route('posts.show', $post);
    }

    public function destroy(Post $post)
    {
    $post->delete();
    return redirect()->route('posts.index');
    }
    }
  7. 更新路由

    1
    2
    3
    use App\Http\Controllers\PostController;

    Route::resource('posts', PostController::class);
  8. 更新视图

    • 更新 posts/index.blade.php 以显示实际数据
    • 更新 posts/show.blade.php 以显示实际数据
    • 更新 posts/edit.blade.php 以显示实际数据
  9. 创建帖子填充器

    1
    php artisan make:seeder PostSeeder
  10. 编辑填充器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    use Illuminate\Database\Seeder;
    use App\Models\Post;

    class PostSeeder extends Seeder
    {
    public function run()
    {
    Post::create([
    'title' => 'First Post',
    'content' => 'This is the first post content.',
    ]);

    Post::create([
    'title' => 'Second Post',
    'content' => 'This is the second post content.',
    ]);
    }
    }
  11. 运行填充器

    1
    php artisan db:seed --class=PostSeeder

现在,我们的博客应用已经具备了完整的数据库功能,可以创建、查看、编辑和删除帖子。

5.10 Laravel 12 数据库优化

Laravel 12 提供了多种数据库优化技术,帮助我们提高应用的性能和可靠性。

Laravel 12 索引优化

  • 为经常查询的列添加索引
  • 为外键添加索引
  • 避免过多的索引(会影响插入和更新性能)
  • 使用复合索引优化多列查询
  • 在 Laravel 12 迁移中使用 $table->index() 方法添加索引

Laravel 12 查询优化

  • 使用预加载减少 N+1 查询问题:Post::with('comments')->get();
  • 只选择需要的列:User::select('id', 'name')->get();
  • 使用分页避免一次性获取过多数据:Post::paginate(10);
  • 避免在循环中执行数据库操作
  • 使用缓存减少数据库查询:Cache::remember('users', 60, function () { return User::all(); });

Laravel 12 连接池优化

  • 在生产环境中配置合适的数据库连接池大小
  • 关闭不需要的连接
  • 使用连接池监控工具
  • 在 Laravel 12 中通过 config/database.php 配置连接池参数

通过这些 Laravel 12 数据库优化技术,你可以显著提高应用的性能和响应速度,为用户提供更好的体验。

现在,我们已经了解了 Laravel 的数据库操作,接下来我们将学习 Laravel 的表单处理。

6. Laravel 12 表单处理

Laravel 12 表单处理是 Web 应用中的常见任务,Laravel 12 提供了强大的表单处理功能,包括表单验证、CSRF 保护等。

6.1 Laravel 12 基本表单处理

Laravel 12 创建表单

在 Laravel 12 中,我们可以使用 HTML 表单或 Laravel 12 提供的表单助手来创建表单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 基本 HTML 表单 -->
<form action="{{ route('posts.store') }}" method="POST">
@csrf

<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" required>
</div>

<div class="mb-3">
<label for="content" class="form-label">Content</label>
<textarea class="form-control" id="content" name="content" rows="3" required></textarea>
</div>

<button type="submit" class="btn btn-primary">Submit</button>
</form>

Laravel 12 处理表单提交

在 Laravel 12 控制器中,我们可以使用 Request 对象来获取表单数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
use Illuminate\Http\Request;

/**
* Store a newly created Laravel 12 resource in storage.
*/
public function store(Request $request)
{
// Laravel 12 获取单个字段
$title = $request->input('title');
$content = $request->input('content');

// Laravel 12 获取所有字段
$data = $request->all();

// Laravel 12 获取部分字段
$data = $request->only(['title', 'content']);

// Laravel 12 排除某些字段
$data = $request->except(['_token']);

// Laravel 12 检查字段是否存在
if ($request->has('title')) {
// 字段存在
}

// Laravel 12 检查多个字段是否存在
if ($request->has(['title', 'content'])) {
// 所有字段都存在
}

// Laravel 12 检查字段是否有值
if ($request->filled('title')) {
// 字段有值
}

// Laravel 12 检查字段是否为空
if ($request->missing('title')) {
// 字段不存在
}

// Laravel 12 存储数据
Post::create($data);

// Laravel 12 重定向
return redirect()->route('posts.index');
}

6.2 Laravel 12 表单验证

Laravel 12 提供了多种表单验证方法,包括控制器验证、请求类验证等,帮助我们确保用户输入的数据符合要求。

Laravel 12 控制器验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Validator;

/**
* Store a newly created Laravel 12 resource in storage.
*/
public function store(Request $request)
{
// Laravel 12 验证规则
$rules = [
'title' => 'required|min:3|max:255',
'content' => 'required|min:10',
];

// Laravel 12 验证消息
$messages = [
'title.required' => 'Title is required',
'title.min' => 'Title must be at least 3 characters',
'content.required' => 'Content is required',
'content.min' => 'Content must be at least 10 characters',
];

// Laravel 12 验证属性名称
$attributes = [
'title' => 'Post Title',
'content' => 'Post Content',
];

// Laravel 12 执行验证
$request->validate($rules, $messages, $attributes);

// 或者使用 Laravel 12 Validator 门面
/*
$validator = Validator::make($request->all(), $rules, $messages, $attributes);

if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
*/

// Laravel 12 验证通过,处理数据
Post::create($request->all());

return redirect()->route('posts.index');
}

Laravel 12 请求类验证

Laravel 12 请求类验证是一种更优雅的验证方式,它将验证逻辑从控制器中分离出来,使代码更加清晰和可维护。

1
2
# Laravel 12 创建请求类
php artisan make:request StorePostRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Laravel 12 请求类 - app/Http/Requests/StorePostRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
/**
* Laravel 12 - 确定用户是否有权限提交此请求
*/
public function authorize()
{
return true; // Laravel 12 默认返回 false,需要改为 true
}

/**
* Laravel 12 - 获取应用于此请求的验证规则
*/
public function rules()
{
return [
'title' => 'required|min:3|max:255',
'content' => 'required|min:10',
];
}

/**
* Laravel 12 - 获取验证错误的自定义消息
*/
public function messages()
{
return [
'title.required' => 'Title is required',
'title.min' => 'Title must be at least 3 characters',
'content.required' => 'Content is required',
'content.min' => 'Content must be at least 10 characters',
];
}

/**
* Laravel 12 - 获取自定义验证属性名称
*/
public function attributes()
{
return [
'title' => 'Post Title',
'content' => 'Post Content',
];
}
}

Laravel 12 在控制器中使用请求类:

1
2
3
4
5
6
7
8
9
10
11
12
13
use App\Http\Requests\StorePostRequest;

/**
* Store a newly created Laravel 12 resource in storage.
*/
public function store(StorePostRequest $request)
{
// Laravel 12 验证通过,直接处理数据
Post::create($request->validated());

// Laravel 12 重定向
return redirect()->route('posts.index');
}

Laravel 12 验证规则

Laravel 12 提供了丰富的验证规则,帮助我们确保用户输入的数据符合要求:

规则描述
required字段必须存在且不为空
min字符串长度或数值最小值
max字符串长度或数值最大值
email必须是有效的电子邮件地址
unique必须在指定表中是唯一的
exists必须在指定表中存在
regex必须匹配指定的正则表达式
confirmed必须与同名的 _confirmed 字段值匹配
nullable字段可以为空
date必须是有效的日期
boolean必须是布尔值
numeric必须是数值
integer必须是整数
alpha必须只包含字母
alpha_dash必须只包含字母、数字、破折号和下划线
alpha_num必须只包含字母和数字
url必须是有效的 URL
ip必须是有效的 IP 地址
json必须是有效的 JSON 字符串

Laravel 12 验证规则非常强大,可以组合使用多个规则来满足复杂的验证需求。例如:

1
2
3
4
5
// Laravel 12 组合验证规则
'title' => 'required|min:3|max:255|unique:posts',
'email' => 'required|email|unique:users',
'password' => 'required|min:8|confirmed',
'age' => 'required|integer|min:18|max:100',

Laravel 12 显示验证错误

在 Laravel 12 视图中,我们可以使用 $errors 变量来显示验证错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<form action="{{ route('posts.store') }}" method="POST">
@csrf

<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" value="{{ old('title') }}" required>
@error('title')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>

<div class="mb-3">
<label for="content" class="form-label">Content</label>
<textarea class="form-control @error('content') is-invalid @enderror" id="content" name="content" rows="3" required>{{ old('content') }}</textarea>
@error('content')
<div class="invalid-feedback">
{{ $message }}
</div>
@enderror
</div>

<button type="submit" class="btn btn-primary">Submit</button>
</form>

Laravel 12 提供了以下用于显示验证错误的方法:

  • @error 指令:用于检查特定字段的错误
  • $errors->any():检查是否有任何错误
  • $errors->all():获取所有错误消息
  • $errors->get('field'):获取特定字段的错误消息
  • old('field'):获取之前输入的值,用于表单回显
1
2
3
4
5
6
7
8

#### Laravel 12 自定义验证规则

Laravel 12 允许我们创建自定义验证规则,以满足特定的验证需求:

```bash
# Laravel 12 创建验证规则
php artisan make:rule Uppercase
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Laravel 12 自定义验证规则 - app/Rules/Uppercase.php
namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Uppercase implements Rule
{
/**
* Laravel 12 - 确定验证规则是否通过
*/
public function passes($attribute, $value)
{
return strtoupper($value) === $value;
}

/**
* Laravel 12 - 获取验证错误消息
*/
public function message()
{
return 'The :attribute must be uppercase.';
}
}

Laravel 12 使用自定义验证规则:

1
2
3
4
5
6
7
8
9
10
11
use App\Rules\Uppercase;

/**
* Laravel 12 - 获取应用于此请求的验证规则
*/
public function rules()
{
return [
'title' => ['required', new Uppercase],
];
}

Laravel 12 自定义验证规则非常灵活,可以根据具体的业务需求创建各种复杂的验证规则,提高应用的安全性和可靠性。

6.3 Laravel 12 CSRF 保护

CSRF(Cross-Site Request Forgery)是一种常见的 Web 攻击方式,Laravel 12 提供了内置的 CSRF 保护,帮助我们防止恶意网站伪造请求。

Laravel 12 添加 CSRF 令牌

在 Laravel 12 表单中,我们需要添加 CSRF 令牌:

1
2
3
4
5
<form action="{{ route('posts.store') }}" method="POST">
@csrf

<!-- 表单字段 -->
</form>

Laravel 12 AJAX 请求中的 CSRF 保护

对于 Laravel 12 AJAX 请求,我们可以在请求头中添加 CSRF 令牌:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Laravel 12 在 HTML 中添加元标签
<meta name="csrf-token" content="{{ csrf_token() }}">

// Laravel 12 在 JavaScript 中设置请求头
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});

// 或者在单个 Laravel 12 请求中设置
$.ajax({
url: '/posts',
type: 'POST',
data: {
title: 'Test',
content: 'Test content'
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
console.log(response);
}
});

Laravel 12 排除路由的 CSRF 保护

在某些情况下,我们可能需要排除某些路由的 CSRF 保护,例如 API 路由:

1
2
3
4
5
// Laravel 12 CSRF 中间件配置 - app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
'api/*',
'webhook/*',
];

6.4 请求类

请求类不仅可以用于验证,还可以用于处理请求数据的转换和准备。

自定义请求类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// app/Http/Requests/StorePostRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
/**
* 确定用户是否有权限提交此请求
*/
public function authorize()
{
return true;
}

/**
* 获取应用于此请求的验证规则
*/
public function rules()
{
return [
'title' => 'required|min:3|max:255',
'content' => 'required|min:10',
];
}

/**
* 准备要验证的数据
*/
protected function prepareForValidation()
{
$this->merge([
'title' => trim($this->title),
'content' => trim($this->content),
]);
}

/**
* 获取经过转换的输入数据
*/
public function validated()
{
return array_merge(parent::validated(), [
'slug' => str_slug($this->title),
]);
}
}

6.5 表单数据持久化

当表单验证失败时,我们通常希望保持用户已经输入的数据,Laravel 提供了 old() 辅助函数来实现这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<input type="text" class="form-control" id="title" name="title" value="{{ old('title') }}" required>

<textarea class="form-control" id="content" name="content" rows="3" required>{{ old('content') }}</textarea>

<select class="form-select" name="category" required>
<option value="">Select Category</option>
<option value="1" {{ old('category') == 1 ? 'selected' : '' }}>Category 1</option>
<option value="2" {{ old('category') == 2 ? 'selected' : '' }}>Category 2</option>
</select>

<input type="radio" id="status-active" name="status" value="active" {{ old('status') == 'active' ? 'checked' : '' }}>
<label for="status-active">Active</label>

<input type="radio" id="status-inactive" name="status" value="inactive" {{ old('status') == 'inactive' ? 'checked' : '' }}>
<label for="status-inactive">Inactive</label>

<input type="checkbox" id="featured" name="featured" {{ old('featured') ? 'checked' : '' }}>
<label for="featured">Featured</label>

6.6 实战示例

现在,让我们为之前创建的博客应用添加表单验证:

  1. 创建请求类

    1
    2
    php artisan make:request StorePostRequest
    php artisan make:request UpdatePostRequest
  2. 编辑 StorePostRequest

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    namespace App\Http\Requests;

    use Illuminate\Foundation\Http\FormRequest;

    class StorePostRequest extends FormRequest
    {
    public function authorize()
    {
    return true;
    }

    public function rules()
    {
    return [
    'title' => 'required|min:3|max:255',
    'content' => 'required|min:10',
    ];
    }
    }
  3. 编辑 UpdatePostRequest

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    namespace App\Http\Requests;

    use Illuminate\Foundation\Http\FormRequest;

    class UpdatePostRequest extends FormRequest
    {
    public function authorize()
    {
    return true;
    }

    public function rules()
    {
    return [
    'title' => 'required|min:3|max:255',
    'content' => 'required|min:10',
    ];
    }
    }
  4. 更新控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    use App\Http\Requests\StorePostRequest;
    use App\Http\Requests\UpdatePostRequest;

    public function store(StorePostRequest $request)
    {
    Post::create($request->validated());
    return redirect()->route('posts.index');
    }

    public function update(UpdatePostRequest $request, Post $post)
    {
    $post->update($request->validated());
    return redirect()->route('posts.show', $post);
    }
  5. 更新视图

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <!-- resources/views/posts/create.blade.php -->
    <form action="{{ route('posts.store') }}" method="POST">
    @csrf

    <div class="mb-3">
    <label for="title" class="form-label">Title</label>
    <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" value="{{ old('title') }}" required>
    @error('title')
    <div class="invalid-feedback">
    {{ $message }}
    </div>
    @enderror
    </div>

    <div class="mb-3">
    <label for="content" class="form-label">Content</label>
    <textarea class="form-control @error('content') is-invalid @enderror" id="content" name="content" rows="3" required>{{ old('content') }}</textarea>
    @error('content')
    <div class="invalid-feedback">
    {{ $message }}
    </div>
    @enderror
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
    </form>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <!-- resources/views/posts/edit.blade.php -->
    <form action="{{ route('posts.update', $post) }}" method="POST">
    @csrf
    @method('PUT')

    <div class="mb-3">
    <label for="title" class="form-label">Title</label>
    <input type="text" class="form-control @error('title') is-invalid @enderror" id="title" name="title" value="{{ old('title', $post->title) }}" required>
    @error('title')
    <div class="invalid-feedback">
    {{ $message }}
    </div>
    @enderror
    </div>

    <div class="mb-3">
    <label for="content" class="form-label">Content</label>
    <textarea class="form-control @error('content') is-invalid @enderror" id="content" name="content" rows="3" required>{{ old('content', $post->content) }}</textarea>
    @error('content')
    <div class="invalid-feedback">
    {{ $message }}
    </div>
    @enderror
    </div>

    <button type="submit" class="btn btn-primary">Update</button>
    <a href="{{ route('posts.show', $post) }}" class="btn btn-secondary">Cancel</a>
    </form>

现在,我们的博客应用已经具备了完整的表单处理功能,包括表单验证和 CSRF 保护。

6.7 高级表单处理

复杂表单

对于复杂的表单,我们可以使用嵌套字段和数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- 嵌套字段 -->
<form action="{{ route('users.store') }}" method="POST">
@csrf

<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>

<div class="mb-3">
<label class="form-label">Address</label>
<div class="row">
<div class="col">
<input type="text" class="form-control" name="address[street]" placeholder="Street">
</div>
<div class="col">
<input type="text" class="form-control" name="address[city]" placeholder="City">
</div>
<div class="col">
<input type="text" class="form-control" name="address[zip]" placeholder="Zip Code">
</div>
</div>
</div>

<button type="submit" class="btn btn-primary">Submit</button>
</form>

在控制器中获取嵌套字段:

1
2
3
4
5
6
7
8
9
10
public function store(Request $request)
{
$name = $request->input('name');
$address = $request->input('address');
$street = $request->input('address.street');
$city = $request->input('address.city');
$zip = $request->input('address.zip');

// 处理数据
}

动态表单

对于动态表单,我们可以使用 JavaScript 来添加和删除表单字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<form action="{{ route('products.store') }}" method="POST">
@csrf

<div class="mb-3">
<label for="name" class="form-label">Product Name</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>

<div class="mb-3">
<label class="form-label">Variations</label>
<div id="variations">
<div class="variation row mb-2">
<div class="col">
<input type="text" class="form-control" name="variations[0][name]" placeholder="Variation Name">
</div>
<div class="col">
<input type="number" class="form-control" name="variations[0][price]" placeholder="Price">
</div>
<div class="col-auto">
<button type="button" class="btn btn-danger remove-variation">Remove</button>
</div>
</div>
</div>
<button type="button" class="btn btn-primary mt-2" id="add-variation">Add Variation</button>
</div>

<button type="submit" class="btn btn-primary">Submit</button>
</form>

<script>
document.addEventListener('DOMContentLoaded', function() {
let variationIndex = 1;

// 添加变体
document.getElementById('add-variation').addEventListener('click', function() {
const variationsContainer = document.getElementById('variations');
const variationDiv = document.createElement('div');
variationDiv.className = 'variation row mb-2';
variationDiv.innerHTML = `
<div class="col">
<input type="text" class="form-control" name="variations[${variationIndex}][name]" placeholder="Variation Name">
</div>
<div class="col">
<input type="number" class="form-control" name="variations[${variationIndex}][price]" placeholder="Price">
</div>
<div class="col-auto">
<button type="button" class="btn btn-danger remove-variation">Remove</button>
</div>
`;
variationsContainer.appendChild(variationDiv);

// 添加删除事件
variationDiv.querySelector('.remove-variation').addEventListener('click', function() {
variationDiv.remove();
});

variationIndex++;
});

// 删除变体
document.querySelectorAll('.remove-variation').forEach(button => {
button.addEventListener('click', function() {
this.closest('.variation').remove();
});
});
});
</script>

在控制器中处理动态表单数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function store(Request $request)
{
$name = $request->input('name');
$variations = $request->input('variations');

foreach ($variations as $variation) {
$variationName = $variation['name'];
$variationPrice = $variation['price'];

// 处理变体数据
}

// 处理其他数据
}

现在,我们已经了解了 Laravel 的表单处理,接下来我们将学习 Laravel 的认证系统。

7. 认证系统

认证系统是 Web 应用中的重要组成部分,Laravel 提供了强大的内置认证功能,包括用户注册、登录、密码重置等。

7.1 认证系统基础

Laravel 的认证系统基于以下组件:

  • 认证控制器:处理用户注册、登录、密码重置等请求
  • 认证中间件:保护需要认证的路由
  • 认证视图:提供用户界面
  • 用户模型:存储用户信息
  • 密码哈希:安全存储密码

7.2 快速开始

Laravel 提供了 auth 命令来快速生成认证系统:

1
2
3
4
5
6
7
8
9
10
11
# 生成认证系统
php artisan make:auth

# 在 Laravel 8+ 中,使用 jetstream
composer require laravel/jetstream
php artisan jetstream:install livewire
# 或使用 inertia
php artisan jetstream:install inertia

# 运行迁移
php artisan migrate

7.3 手动实现认证

如果我们需要更灵活的认证系统,可以手动实现认证功能。

1. 用户模型

Laravel 已经默认包含了 User 模型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// app/Models/User.php
namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
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 $casts = [
'email_verified_at' => 'datetime',
];
}

2. 认证路由

我们可以在 routes/web.php 中定义认证路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 认证路由
Route::get('/register', [AuthController::class, 'showRegistrationForm'])->name('register');
Route::post('/register', [AuthController::class, 'register']);
Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
Route::post('/logout', [AuthController::class, 'logout'])->name('logout');

// 密码重置路由
Route::get('/password/reset', [ForgotPasswordController::class, 'showLinkRequestForm'])->name('password.request');
Route::post('/password/email', [ForgotPasswordController::class, 'sendResetLinkEmail'])->name('password.email');
Route::get('/password/reset/{token}', [ResetPasswordController::class, 'showResetForm'])->name('password.reset');
Route::post('/password/reset', [ResetPasswordController::class, 'reset'])->name('password.update');

// 需要认证的路由
Route::middleware('auth')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
});

3. 认证控制器

我们可以创建认证控制器:

1
2
3
4
# 创建认证控制器
php artisan make:controller AuthController
php artisan make:controller ForgotPasswordController
php artisan make:controller ResetPasswordController
认证控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// app/Http/Controllers/AuthController.php
namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;

class AuthController extends Controller
{
/**
* 显示注册表单
*/
public function showRegistrationForm()
{
return view('auth.register');
}

/**
* 处理注册请求
*/
public function register(Request $request)
{
// 验证请求
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
]);

// 创建用户
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);

// 登录用户
Auth::login($user);

// 重定向到 dashboard
return redirect()->route('dashboard');
}

/**
* 显示登录表单
*/
public function showLoginForm()
{
return view('auth.login');
}

/**
* 处理登录请求
*/
public function login(Request $request)
{
// 验证请求
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
]);

// 尝试登录
if (Auth::attempt(['email' => $request->email, 'password' => $request->password])) {
// 登录成功,重定向到 dashboard
return redirect()->intended('dashboard');
}

// 登录失败,重定向回登录页面
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
]);
}

/**
* 处理登出请求
*/
public function logout(Request $request)
{
Auth::logout();

$request->session()->invalidate();
$request->session()->regenerateToken();

return redirect('/');
}
}
密码重置控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// app/Http/Controllers/ForgotPasswordController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

class ForgotPasswordController extends Controller
{
/**
* 显示密码重置链接请求表单
*/
public function showLinkRequestForm()
{
return view('auth.forgot-password');
}

/**
* 发送密码重置链接
*/
public function sendResetLinkEmail(Request $request)
{
$request->validate(['email' => 'required|email']);

$status = Password::sendResetLink(
$request->only('email')
);

return $status === Password::RESET_LINK_SENT
? back()->with(['status' => __($status)])
: back()->withErrors(['email' => __($status)]);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// app/Http/Controllers/ResetPasswordController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

class ResetPasswordController extends Controller
{
/**
* 显示密码重置表单
*/
public function showResetForm(Request $request, $token = null)
{
return view('auth.reset-password')->with(
['token' => $token, 'email' => $request->email]
);
}

/**
* 重置密码
*/
public function reset(Request $request)
{
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|min:8|confirmed',
]);

$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user, $password) {
$user->forceFill([
'password' => Hash::make($password)
])->save();
}
);

return $status === Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withErrors(['email' => [__($status)]]);
}
}

4. 认证视图

我们需要创建认证视图:

注册视图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<!-- resources/views/auth/register.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Register') }}</div>

<div class="card-body">
<form method="POST" action="{{ route('register') }}">
@csrf

<div class="row mb-3">
<label for="name" class="col-md-4 col-form-label text-md-end">{{ __('Name') }}</label>

<div class="col-md-6">
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-3">
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>

<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-3">
<label for="password-confirm" class="col-md-4 col-form-label text-md-end">{{ __('Confirm Password') }}</label>

<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>

<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
登录视图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!-- resources/views/auth/login.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Login') }}</div>

<div class="card-body">
<form method="POST" action="{{ route('login') }}">
@csrf

<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-3">
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>

<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">

@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-3">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
</div>
</div>

<div class="row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>

@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ route('password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
密码重置视图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!-- resources/views/auth/forgot-password.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Forgot Your Password?') }}</div>

<div class="card-body">
<form method="POST" action="{{ route('password.email') }}">
@csrf

<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Send Password Reset Link') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!-- resources/views/auth/reset-password.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>

<div class="card-body">
<form method="POST" action="{{ route('password.update') }}">
@csrf

<input type="hidden" name="token" value="{{ $token }}">

<div class="row mb-3">
<label for="email" class="col-md-4 col-form-label text-md-end">{{ __('Email Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>

@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-3">
<label for="password" class="col-md-4 col-form-label text-md-end">{{ __('Password') }}</label>

<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="row mb-3">
<label for="password-confirm" class="col-md-4 col-form-label text-md-end">{{ __('Confirm Password') }}</label>

<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>

<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

5. 仪表板控制器

我们需要创建一个仪表板控制器来显示用户登录后的页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// app/Http/Controllers/DashboardController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class DashboardController extends Controller
{
/**
* 显示仪表板
*/
public function index()
{
return view('dashboard');
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- resources/views/dashboard.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Dashboard') }}</div>

<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif

{{ __('You are logged in!') }}
</div>
</div>
</div>
</div>
</div>
@endsection

7.4 认证中间件

Laravel 提供了 auth 中间件来保护需要认证的路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 使用中间件保护路由
Route::get('/dashboard', [DashboardController::class, 'index'])->middleware('auth');

// 使用中间件组
Route::middleware('auth')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/profile', [ProfileController::class, 'index']);
});

// 在控制器中使用中间件
class DashboardController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
}

7.5 认证辅助函数

Laravel 提供了多个认证辅助函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 检查用户是否已认证
if (auth()->check()) {
// 用户已认证
}

// 检查用户是否为访客
if (auth()->guest()) {
// 用户未认证
}

// 获取当前用户
$user = auth()->user();

// 获取当前用户 ID
$userId = auth()->id();

// 登录用户
auth()->login($user);

// 登出用户
auth()->logout();

// 尝试登录
auth()->attempt(['email' => $email, 'password' => $password]);

// 验证用户密码
if (Hash::check($password, $user->password)) {
// 密码正确
}

// 哈希密码
$hashedPassword = Hash::make($password);

7.6 自定义认证

自定义认证 guard

我们可以创建自定义的认证 guard 来使用不同的认证方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],

'api' => [
'driver' => 'token',
'provider' => 'users',
],

'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],

'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],

'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],

使用自定义 guard:

1
2
3
4
5
6
7
8
9
10
// 登录 admin
auth('admin')->attempt(['email' => $email, 'password' => $password]);

// 获取当前 admin
$admin = auth('admin')->user();

// 保护路由
Route::middleware('auth:admin')->group(function () {
// 管理员路由
});

自定义认证字段

我们可以修改认证逻辑来使用不同的字段进行认证:

1
2
3
4
5
6
7
8
// 使用用户名认证
auth()->attempt(['username' => $username, 'password' => $password]);

// 在 LoginController 中修改
public function username()
{
return 'username';
}

7.7 邮箱验证

Laravel 提供了内置的邮箱验证功能:

1. 更新用户模型

1
2
3
4
5
// app/Models/User.php
class User extends Authenticatable implements MustVerifyEmail
{
// ...
}

2. 注册路由

1
2
3
4
// routes/web.php
Route::get('/email/verify', [VerificationController::class, 'show'])->name('verification.notice');
Route::get('/email/verify/{id}/{hash}', [VerificationController::class, 'verify'])->name('verification.verify');
Route::post('/email/resend', [VerificationController::class, 'resend'])->name('verification.resend');

3. 创建验证控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// app/Http/Controllers/VerificationController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\EmailVerificationRequest;

class VerificationController extends Controller
{
/**
* 显示邮箱验证通知
*/
public function show()
{
return view('auth.verify-email');
}

/**
* 验证邮箱
*/
public function verify(EmailVerificationRequest $request)
{
$request->fulfill();

return redirect()->route('dashboard');
}

/**
* 重新发送验证邮件
*/
public function resend(Request $request)
{
$request->user()->sendEmailVerificationNotification();

return back()->with('message', 'Verification link sent!');
}
}

4. 创建验证视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!-- resources/views/auth/verify-email.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Verify Your Email Address') }}</div>

<div class="card-body">
@if (session('message'))
<div class="alert alert-success" role="alert">
{{ session('message') }}
</div>
@endif

{{ __('Before proceeding, please check your email for a verification link.') }}
{{ __('If you did not receive the email') }},
<form class="d-inline" method="POST" action="{{ route('verification.resend') }}">
@csrf
<button type="submit" class="btn btn-link p-0 m-0 align-baseline">{{ __('click here to request another') }}</button>.
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

5. 保护需要验证的路由

1
2
3
4
// 使用 verified 中间件
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});

7.8 实战示例

现在,让我们为之前创建的博客应用添加认证功能:

  1. 创建认证控制器

    1
    2
    php artisan make:controller AuthController
    php artisan make:controller DashboardController
  2. 编辑认证控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    namespace App\Http\Controllers;

    use App\Models\User;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Support\Facades\Hash;

    class AuthController extends Controller
    {
    public function showRegistrationForm()
    {
    return view('auth.register');
    }

    public function register(Request $request)
    {
    $request->validate([
    'name' => 'required|string|max:255',
    'email' => 'required|string|email|max:255|unique:users',
    'password' => 'required|string|min:8|confirmed',
    ]);

    $user = User::create([
    'name' => $request->name,
    'email' => $request->email,
    'password' => Hash::make($request->password),
    ]);

    Auth::login($user);

    return redirect()->route('dashboard');
    }

    public function showLoginForm()
    {
    return view('auth.login');
    }

    public function login(Request $request)
    {
    $request->validate([
    'email' => 'required|string|email',
    'password' => 'required|string',
    ]);

    if (Auth::attempt(['email' => $request->email, 'password' => $request->password])) {
    return redirect()->intended('dashboard');
    }

    return back()->withErrors([
    'email' => 'The provided credentials do not match our records.',
    ]);
    }

    public function logout(Request $request)
    {
    Auth::logout();

    $request->session()->invalidate();
    $request->session()->regenerateToken();

    return redirect('/');
    }
    }
  3. 编辑仪表板控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    namespace App\Http\Controllers;

    use Illuminate\Http\Request;

    class DashboardController extends Controller
    {
    public function __construct()
    {
    $this->middleware('auth');
    }

    public function index()
    {
    return view('dashboard');
    }
    }
  4. 创建认证视图

    • 创建 resources/views/auth/register.blade.php
    • 创建 resources/views/auth/login.blade.php
    • 创建 resources/views/dashboard.blade.php
  5. 定义路由

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 认证路由
    Route::get('/register', [AuthController::class, 'showRegistrationForm'])->name('register');
    Route::post('/register', [AuthController::class, 'register']);
    Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login');
    Route::post('/login', [AuthController::class, 'login']);
    Route::post('/logout', [AuthController::class, 'logout'])->name('logout');

    // 仪表板路由
    Route::middleware('auth')->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
    });
  6. 更新布局文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    <!-- resources/views/layouts/app.blade.php -->
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container">
    <a class="navbar-brand" href="{{ route('posts.index') }}">Blog</a>
    <div class="collapse navbar-collapse">
    <ul class="navbar-nav mr-auto">
    <li class="nav-item">
    <a class="nav-link" href="{{ route('posts.index') }}">Home</a>
    </li>
    @auth
    <li class="nav-item">
    <a class="nav-link" href="{{ route('posts.create') }}">Create Post</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" href="{{ route('dashboard') }}">Dashboard</a>
    </li>
    @endauth
    </ul>
    <ul class="navbar-nav ml-auto">
    @guest
    <li class="nav-item">
    <a class="nav-link" href="{{ route('login') }}">Login</a>
    </li>
    <li class="nav-item">
    <a class="nav-link" href="{{ route('register') }}">Register</a>
    </li>
    @else
    <li class="nav-item dropdown">
    <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    {{ Auth::user()->name }}
    </a>
    <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
    <a class="dropdown-item" href="{{ route('dashboard') }}">Dashboard</a>
    <form method="POST" action="{{ route('logout') }}">
    @csrf
    <button type="submit" class="dropdown-item">Logout</button>
    </form>
    </div>
    </li>
    @endguest
    </ul>
    </div>
    </div>
    </nav>
  7. 运行迁移

    1
    php artisan migrate

现在,我们的博客应用已经具备了完整的认证功能,包括用户注册、登录和注销。

7.9 安全建议

在实现认证系统时,我们应该遵循以下安全建议:

  1. 使用密码哈希:永远不要明文存储密码,使用 Laravel 提供的 Hash 门面来哈希密码
  2. 使用 HTTPS:在生产环境中使用 HTTPS 来保护用户数据
  3. 实现 CSRF 保护:使用 Laravel 的 CSRF 保护来防止跨站请求伪造攻击
  4. 限制登录尝试:实现登录尝试限制,防止暴力破解
  5. 使用安全的会话管理:使用 Laravel 的会话管理功能
  6. 实现邮箱验证:验证用户邮箱,防止垃圾注册
  7. 使用强密码策略:要求用户使用强密码
  8. 定期更新密码:鼓励用户定期更新密码
  9. 实现双因素认证:对于敏感操作,实现双因素认证
  10. 安全存储令牌:安全存储重置密码令牌等临时令牌

现在,我们已经了解了 Laravel 的认证系统,接下来我们将学习 Laravel 的文件上传和存储功能。

8. 文件上传和存储

文件上传和存储是 Web 应用中常见的功能,Laravel 提供了强大的文件处理功能,支持本地存储和云存储。

8.1 文件上传基础

1. 表单设置

要上传文件,我们需要在表单中添加 enctype="multipart/form-data" 属性:

1
2
3
4
5
6
7
8
<form method="POST" action="{{ route('upload') }}" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="file" class="form-label">Upload File</label>
<input type="file" class="form-control" id="file" name="file">
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>

2. 处理上传

在控制器中,我们可以使用 $request->file() 方法来获取上传的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// app/Http/Controllers/UploadController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UploadController extends Controller
{
/**
* 处理文件上传
*/
public function upload(Request $request)
{
// 验证文件
$request->validate([
'file' => 'required|file|max:1024', // 1MB 限制
]);

// 获取上传的文件
$file = $request->file('file');

// 检查文件是否上传成功
if ($file->isValid()) {
// 存储文件
$path = $file->store('uploads');
// 或使用自定义文件名
// $path = $file->storeAs('uploads', 'custom-name.jpg');

// 返回成功信息
return back()->with('success', 'File uploaded successfully!')->with('path', $path);
}

// 返回错误信息
return back()->with('error', 'File upload failed!');
}
}

3. 路由定义

1
2
3
// routes/web.php
Route::get('/upload', [UploadController::class, 'showForm'])->name('upload.form');
Route::post('/upload', [UploadController::class, 'upload'])->name('upload');

8.2 本地存储

Laravel 的本地存储使用 storage/app 目录作为根目录。我们可以通过配置文件 config/filesystems.php 来修改存储设置。

1. 存储磁盘

Laravel 支持多种存储磁盘,默认包括:

  • local:本地存储,使用 storage/app 目录
  • public:公共存储,使用 storage/app/public 目录
  • s3:Amazon S3 存储

2. 公共存储

对于需要公开访问的文件,我们可以使用公共存储:

1
2
3
4
5
// 存储到公共磁盘
$path = $file->store('images', 'public');

// 创建符号链接(首次使用时需要)
php artisan storage:link

创建符号链接后,我们可以通过以下 URL 访问文件:

1
<img src="{{ asset('storage/' . $path) }}" alt="Image">

3. 存储路径

Laravel 提供了多个辅助函数来获取存储路径:

1
2
3
4
5
6
7
8
9
10
11
// 获取存储根路径
$root = storage_path();

// 获取 app 目录路径
$appPath = storage_path('app');

// 获取 public 目录路径
$publicPath = storage_path('app/public');

// 获取 uploads 目录路径
$uploadsPath = storage_path('app/uploads');

8.3 云存储

Laravel 支持多种云存储服务,包括 Amazon S3、Google Cloud Storage、Azure Blob Storage 等。

1. Amazon S3

安装依赖

1
composer require league/flysystem-aws-s3-v3

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// config/filesystems.php
'disks' => [
// ...
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
],
],

使用

1
2
3
4
5
// 存储到 S3
$path = $file->store('images', 's3');

// 获取 S3 文件 URL
$url = Storage::disk('s3')->url($path);

2. Google Cloud Storage

安装依赖

1
composer require league/flysystem-google-cloud-storage

配置

1
2
3
4
5
6
7
8
9
10
11
12
// config/filesystems.php
'disks' => [
// ...
'gcs' => [
'driver' => 'gcs',
'project_id' => env('GOOGLE_CLOUD_PROJECT_ID'),
'key_file' => env('GOOGLE_CLOUD_KEY_FILE'), // 可选
'bucket' => env('GOOGLE_CLOUD_STORAGE_BUCKET'),
'path_prefix' => env('GOOGLE_CLOUD_STORAGE_PATH_PREFIX'), // 可选
'storage_api_uri' => env('GOOGLE_CLOUD_STORAGE_API_URI'), // 可选
],
],

使用

1
2
3
4
5
// 存储到 Google Cloud Storage
$path = $file->store('images', 'gcs');

// 获取文件 URL
$url = Storage::disk('gcs')->url($path);

8.4 文件验证

在上传文件时,我们应该验证文件的类型、大小等属性:

1. 基本验证规则

1
2
3
4
5
6
7
8
9
10
$request->validate([
// 验证文件存在且是有效文件
'file' => 'required|file',
// 验证文件大小(1MB)
'file' => 'required|file|max:1024',
// 验证文件类型
'file' => 'required|file|mimes:jpg,jpeg,png,gif',
// 验证文件类型和大小
'file' => 'required|file|mimes:jpg,jpeg,png|max:2048',
]);

2. 自定义验证规则

我们可以创建自定义验证规则来验证文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// app/Rules/FileExtension.php
namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class FileExtension implements Rule
{
/**
* 允许的扩展名
*/
protected $extensions;

/**
* 创建新的验证规则实例
*/
public function __construct($extensions)
{
$this->extensions = $extensions;
}

/**
* 验证规则
*/
public function passes($attribute, $value)
{
$extension = $value->getClientOriginalExtension();
return in_array(strtolower($extension), $this->extensions);
}

/**
* 获取验证失败的错误消息
*/
public function message()
{
return 'The :attribute must be a file of type: ' . implode(', ', $this->extensions);
}
}

使用自定义规则

1
2
3
4
5
use App\Rules\FileExtension;

$request->validate([
'file' => ['required', 'file', new FileExtension(['jpg', 'jpeg', 'png'])],
]);

3. 验证图片尺寸

我们可以使用 dimensions 规则来验证图片尺寸:

1
2
3
4
5
6
7
8
9
10
$request->validate([
// 验证图片最小尺寸
'image' => 'required|image|dimensions:min_width=100,min_height=100',
// 验证图片最大尺寸
'image' => 'required|image|dimensions:max_width=1000,max_height=1000',
// 验证图片尺寸范围
'image' => 'required|image|dimensions:min_width=100,min_height=100,max_width=1000,max_height=1000',
// 验证图片比例
'image' => 'required|image|dimensions:ratio=16/9',
]);

8.5 文件管理

Laravel 提供了 Storage 门面来管理文件:

1. 存储文件

1
2
3
4
5
6
7
8
9
10
11
12
13
use Illuminate\Support\Facades\Storage;

// 存储文件
Storage::put('file.txt', 'Contents');

// 存储文件(指定磁盘)
Storage::disk('public')->put('file.txt', 'Contents');

// 存储上传的文件
Storage::putFile('photos', $request->file('photo'));

// 存储上传的文件(指定磁盘)
Storage::disk('s3')->putFile('photos', $request->file('photo'));

2. 读取文件

1
2
3
4
5
6
7
8
9
10
11
12
13
// 读取文件内容
$contents = Storage::get('file.txt');

// 检查文件是否存在
if (Storage::exists('file.txt')) {
// 文件存在
}

// 获取文件大小
$size = Storage::size('file.txt');

// 获取文件修改时间
$time = Storage::lastModified('file.txt');

3. 下载文件

1
2
3
4
5
6
7
8
9
10
// 下载文件
return Storage::download('file.txt');

// 下载文件(自定义文件名)
return Storage::download('file.txt', 'custom-name.txt');

// 下载文件(自定义头信息)
return Storage::download('file.txt', 'custom-name.txt', [
'Content-Type' => 'text/plain',
]);

4. 删除文件

1
2
3
4
5
6
7
8
// 删除文件
Storage::delete('file.txt');

// 删除多个文件
Storage::delete(['file1.txt', 'file2.txt']);

// 清空目录
Storage::deleteDirectory('photos');

5. 目录操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建目录
Storage::makeDirectory('photos');

// 删除目录
Storage::deleteDirectory('photos');

// 列出目录中的文件
$files = Storage::files('photos');

// 列出目录中的所有文件(包括子目录)
$files = Storage::allFiles('photos');

// 列出目录
$directories = Storage::directories('photos');

// 列出所有目录(包括子目录)
$directories = Storage::allDirectories('photos');

8.6 实战示例

现在,让我们为之前创建的博客应用添加图片上传功能:

1. 更新帖子迁移

1
2
3
4
5
6
7
8
9
10
11
// database/migrations/xxxx_xx_xx_create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->string('image')->nullable(); // 添加图片字段
$table->timestamps();
});
}

2. 更新帖子模型

1
2
3
4
5
6
// app/Models/Post.php
protected $fillable = [
'title',
'content',
'image', // 添加图片字段
];

3. 更新帖子表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!-- resources/views/posts/create.blade.php -->
<form method="POST" action="{{ route('posts.store') }}" enctype="multipart/form-data">
@csrf

<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control @error('title') is-invalid @enderror"
id="title" name="title" value="{{ old('title') }}" required>
@error('title')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>

<div class="mb-3">
<label for="content" class="form-label">Content</label>
<textarea class="form-control @error('content') is-invalid @enderror"
id="content" name="content" rows="3" required>{{ old('content') }}</textarea>
@error('content')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>

<div class="mb-3">
<label for="image" class="form-label">Image</label>
<input type="file" class="form-control @error('image') is-invalid @enderror"
id="image" name="image">
@error('image')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>

<button type="submit" class="btn btn-primary">Submit</button>
</form>

4. 更新帖子控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// app/Http/Controllers/PostController.php
use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller
{
// ...

/**
* 存储新帖子
*/
public function store(Request $request)
{
// 验证请求
$request->validate([
'title' => 'required|min:3|max:255',
'content' => 'required|min:10',
'image' => 'nullable|image|max:2048', // 验证图片
]);

// 处理图片上传
$imagePath = null;
if ($request->hasFile('image')) {
$imagePath = $request->file('image')->store('posts', 'public');
}

// 创建帖子
$post = Post::create([
'title' => $request->title,
'content' => $request->content,
'image' => $imagePath, // 存储图片路径
]);

// 重定向到帖子详情页
return redirect()->route('posts.show', $post->id)
->with('success', 'Post created successfully!');
}

/**
* 更新帖子
*/
public function update(Request $request, Post $post)
{
// 验证请求
$request->validate([
'title' => 'required|min:3|max:255',
'content' => 'required|min:10',
'image' => 'nullable|image|max:2048', // 验证图片
]);

// 处理图片上传
if ($request->hasFile('image')) {
// 删除旧图片
if ($post->image) {
Storage::disk('public')->delete($post->image);
}
// 存储新图片
$imagePath = $request->file('image')->store('posts', 'public');
} else {
// 保持旧图片
$imagePath = $post->image;
}

// 更新帖子
$post->update([
'title' => $request->title,
'content' => $request->content,
'image' => $imagePath, // 更新图片路径
]);

// 重定向到帖子详情页
return redirect()->route('posts.show', $post->id)
->with('success', 'Post updated successfully!');
}

/**
* 删除帖子
*/
public function destroy(Post $post)
{
// 删除图片
if ($post->image) {
Storage::disk('public')->delete($post->image);
}

// 删除帖子
$post->delete();

// 重定向到帖子列表页
return redirect()->route('posts.index')
->with('success', 'Post deleted successfully!');
}
}

5. 更新帖子视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!-- resources/views/posts/show.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<h1>{{ $post->title }}</h1>
@if ($post->image)
<img src="{{ asset('storage/' . $post->image) }}" alt="{{ $post->title }}" class="img-fluid mb-4">
@endif
<div class="card">
<div class="card-body">
{{ $post->content }}
</div>
</div>
<div class="mt-4">
<a href="{{ route('posts.edit', $post->id) }}" class="btn btn-primary">Edit</a>
<form action="{{ route('posts.destroy', $post->id) }}" method="POST" class="d-inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure?');">Delete</button>
</form>
</div>
</div>
</div>
</div>
@endsection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- resources/views/posts/index.blade.php -->
@extends('layouts.app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<h1>Posts</h1>
@auth
<a href="{{ route('posts.create') }}" class="btn btn-primary mb-4">Create Post</a>
@endauth
@foreach ($posts as $post)
<div class="card mb-4">
@if ($post->image)
<img src="{{ asset('storage/' . $post->image) }}" alt="{{ $post->title }}" class="card-img-top">
@endif
<div class="card-body">
<h2 class="card-title">{{ $post->title }}</h2>
<p class="card-text">{{ Str::limit($post->content, 100) }}</p>
<a href="{{ route('posts.show', $post->id) }}" class="btn btn-primary">Read More</a>
</div>
</div>
@endforeach
</div>
</div>
</div>
@endsection

6. 创建符号链接

1
php artisan storage:link

现在,我们的博客应用已经具备了图片上传功能,用户可以在创建和编辑帖子时上传图片。

8.7 安全建议

在实现文件上传功能时,我们应该遵循以下安全建议:

  1. 验证文件类型:使用 mimesimage 规则验证文件类型
  2. 限制文件大小:使用 max 规则限制文件大小,防止上传过大的文件
  3. 重命名文件:使用 storeAs 方法重命名上传的文件,避免文件名冲突和安全问题
  4. 使用安全的存储位置:对于敏感文件,使用本地存储而不是公共存储
  5. 扫描上传的文件:使用第三方库扫描上传的文件,防止恶意文件
  6. 设置适当的文件权限:确保存储目录有适当的文件权限
  7. 使用 HTTPS:在生产环境中使用 HTTPS 传输文件
  8. 实现文件上传速率限制:防止恶意用户上传大量文件
  9. 使用内容安全策略:限制可以从哪些来源加载文件
  10. 定期清理未使用的文件:定期清理未使用的上传文件,节省存储空间

8.8 高级技巧

1. 图片处理

我们可以使用 intervention/image 库来处理图片:

安装依赖

1
composer require intervention/image

配置

1
2
3
4
5
6
7
8
9
10
// config/app.php
'providers' => [
// ...
Intervention\Image\ImageServiceProvider::class,
],

'aliases' => [
// ...
'Image' => Intervention\Image\Facades\Image::class,
],

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Intervention\Image\Facades\Image;

// 处理上传的图片
if ($request->hasFile('image')) {
$image = $request->file('image');

// 生成唯一文件名
$filename = time() . '.' . $image->getClientOriginalExtension();

// 调整图片大小
Image::make($image)->resize(800, 600, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
})->save(public_path('storage/posts/' . $filename));

// 存储图片路径
$imagePath = 'posts/' . $filename;
}

2. 多文件上传

我们可以使用数组形式的文件输入来上传多个文件:

1
2
3
4
5
6
7
8
<form method="POST" action="{{ route('upload.multiple') }}" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="files" class="form-label">Upload Files</label>
<input type="file" class="form-control" id="files" name="files[]" multiple>
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>

处理多文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function uploadMultiple(Request $request)
{
// 验证文件
$request->validate([
'files.*' => 'required|file|max:1024',
]);

// 存储文件
$paths = [];
foreach ($request->file('files') as $file) {
$paths[] = $file->store('uploads', 'public');
}

// 返回成功信息
return back()->with('success', 'Files uploaded successfully!')->with('paths', $paths);
}

3. 远程文件上传

我们可以使用 Storage 门面来上传远程文件:

1
2
3
4
5
6
7
8
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Http;

// 下载远程文件
$response = Http::get('https://example.com/image.jpg');

// 存储远程文件
Storage::put('remote-image.jpg', $response->body());

现在,我们已经了解了 Laravel 的文件上传和存储功能,接下来我们将学习 Laravel 的部署方法。

9. 部署

部署是将 Laravel 应用从开发环境转移到生产环境的过程。在本章节中,我们将学习如何部署 Laravel 应用到不同的环境。

9.1 本地服务器

在开发过程中,我们可以使用 Laravel 内置的开发服务器来测试应用:

1
2
3
4
5
6
7
8
# 启动开发服务器
php artisan serve

# 指定端口
php artisan serve --port=8080

# 指定主机和端口
php artisan serve --host=0.0.0.0 --port=8080

开发服务器默认运行在 http://localhost:8000

9.2 Laravel Valet

Laravel Valet 是为 macOS 设计的轻量级开发环境,提供了快速的本地开发体验:

1. 安装 Valet

1
2
3
4
5
6
7
8
9
10
11
12
13
# 安装 Valet
composer global require laravel/valet

# 安装 Valet 服务
valet install

# park 当前目录
cd ~/Sites
valet park

# 或 link 特定目录
cd ~/Sites/laravel-app
valet link

2. 使用 Valet

1
2
3
4
5
6
7
8
9
10
11
# 查看所有站点
valet sites

# 重启 Valet
valet restart

# 停止 Valet
valet stop

# 卸载 Valet
valet uninstall

9.3 部署前准备

在部署 Laravel 应用之前,我们需要进行一些准备工作:

1. 环境变量

确保在 .env 文件中设置了正确的环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 应用配置
APP_NAME="Laravel"
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=https://example.com

# 数据库配置
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

# 邮件配置
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

2. 生成应用密钥

1
2
# 生成应用密钥
php artisan key:generate

3. 运行迁移

1
2
3
4
5
# 运行迁移
php artisan migrate --force

# 运行种子
php artisan db:seed --force

4. 优化应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 缓存配置
php artisan config:cache

# 缓存路由
php artisan route:cache

# 缓存视图
php artisan view:cache

# 清除缓存
php artisan cache:clear

# 清除已编译的类文件
php artisan clear-compiled

# 优化自动加载
composer dump-autoload --optimize

9.4 生产环境部署

1. 使用 Git

我们可以使用 Git 来部署 Laravel 应用:

步骤 1:在服务器上初始化 Git 仓库

1
2
3
4
5
6
# 在服务器上创建目录
mkdir -p /var/www/laravel-app
cd /var/www/laravel-app

# 初始化 Git 仓库
git init --bare

步骤 2:创建 post-receive 钩子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 创建钩子目录
mkdir -p /var/www/laravel-app/hooks

# 创建 post-receive 钩子
cat > /var/www/laravel-app/hooks/post-receive << 'EOF'
#!/bin/bash

# 设置目标目录
TARGET_DIR="/var/www/html/laravel-app"

# 确保目标目录存在
mkdir -p "$TARGET_DIR"

# 切换到目标目录
cd "$TARGET_DIR"

# 从裸仓库检出代码
GIT_WORK_TREE="$TARGET_DIR" git checkout -f

# 安装依赖
composer install --optimize-autoloader --no-dev

# 生成应用密钥
php artisan key:generate --force

# 运行迁移
php artisan migrate --force

# 优化应用
php artisan config:cache
php artisan route:cache
php artisan view:cache

# 设置权限
chown -R www-data:www-data "$TARGET_DIR"
chmod -R 755 "$TARGET_DIR/storage"
chmod -R 755 "$TARGET_DIR/bootstrap/cache"

# 重启 PHP-FPM
systemctl restart php8.1-fpm
EOF

# 设置执行权限
chmod +x /var/www/laravel-app/hooks/post-receive

步骤 3:在本地添加远程仓库

1
2
3
4
5
# 添加远程仓库
git remote add production ssh://user@server:/var/www/laravel-app

# 推送代码
git push production master

2. 使用 Laravel Envoyer

Laravel Envoyer 是一个自动化部署服务,可以轻松部署 Laravel 应用:

步骤 1:创建 Envoyer 项目

  1. 登录 Laravel Envoyer
  2. 创建新项目
  3. 连接到 GitHub、GitLab 或 Bitbucket 仓库

步骤 2:配置服务器

  1. 添加服务器
  2. 设置部署路径
  3. 配置 SSH 密钥

步骤 3:配置部署钩子

  1. 设置部署前钩子
  2. 设置部署后钩子
  3. 配置通知

步骤 4:部署应用

  1. 触发部署
  2. 监控部署过程
  3. 查看部署日志

3. 使用 Laravel Forge

Laravel Forge 是一个服务器管理和部署服务,可以轻松创建和管理服务器:

步骤 1:创建 Forge 账户

  1. 登录 Laravel Forge
  2. 连接到服务器提供商(DigitalOcean、AWS、Linode 等)

步骤 2:创建服务器

  1. 选择服务器提供商
  2. 配置服务器规格
  3. 部署服务器

步骤 3:创建站点

  1. 添加新站点
  2. 配置域名
  3. 连接到 Git 仓库

步骤 4:部署应用

  1. 触发部署
  2. 配置环境变量
  3. 运行迁移

9.5 服务器配置

1. Nginx 配置

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
server {
listen 80;
server_name example.com;
root /var/www/html/laravel-app/public;

add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";

index index.php;

charset utf-8;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location = /favicon.ico {
access_log off;
log_not_found off;
}

location = /robots.txt {
access_log off;
log_not_found off;
}

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}

location ~ /\.(?!well-known).* {
deny all;
}
}

使用 HTTPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl http2;
server_name example.com;
root /var/www/html/laravel-app/public;

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

index index.php;

charset utf-8;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location = /favicon.ico {
access_log off;
log_not_found off;
}

location = /robots.txt {
access_log off;
log_not_found off;
}

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}

location ~ /\.(?!well-known).* {
deny all;
}
}

2. Apache 配置

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html/laravel-app/public

<Directory /var/www/html/laravel-app/public>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/laravel-app-error.log
CustomLog ${APACHE_LOG_DIR}/laravel-app-access.log combined
</VirtualHost>

使用 HTTPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
ServerName example.com
DocumentRoot /var/www/html/laravel-app/public

SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

<Directory /var/www/html/laravel-app/public>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/laravel-app-error.log
CustomLog ${APACHE_LOG_DIR}/laravel-app-access.log combined
</VirtualHost>

9.5 数据库配置

1. MySQL

安装 MySQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安装 MySQL
apt update
apt install mysql-server

# 配置 MySQL
mysql_secure_installation

# 创建数据库和用户
mysql -u root -p

CREATE DATABASE laravel_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON laravel_app.* TO 'laravel_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

配置 Laravel

1
2
3
4
5
6
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_app
DB_USERNAME=laravel_user
DB_PASSWORD=password

2. PostgreSQL

安装 PostgreSQL

1
2
3
4
5
6
7
8
9
10
11
12
13
# 安装 PostgreSQL
apt update
apt install postgresql postgresql-contrib

# 登录 PostgreSQL
sudo -u postgres psql

# 创建数据库和用户
CREATE DATABASE laravel_app;
CREATE USER laravel_user WITH PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE laravel_app TO laravel_user;
ALTER USER laravel_user WITH SUPERUSER;
\q

配置 Laravel

1
2
3
4
5
6
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=laravel_app
DB_USERNAME=laravel_user
DB_PASSWORD=password

9.6 环境变量配置

在生产环境中,我们应该使用 .env 文件来存储敏感信息:

1. 创建 .env 文件

1
2
3
4
5
# 复制 .env.example 文件
cp .env.example .env

# 编辑 .env 文件
nano .env

2. 环境变量最佳实践

  • 不要提交 .env 文件:将 .env 文件添加到 .gitignore
  • 使用不同的环境变量:为开发、测试和生产环境使用不同的 .env 文件
  • 使用环境变量管理服务:如 Laravel Envoyer、AWS Parameter Store 或 HashiCorp Vault
  • 设置适当的权限:确保 .env 文件的权限为 600

9.7 优化策略

1. 缓存优化

1
2
3
4
5
6
7
8
9
10
11
# 缓存配置
php artisan config:cache

# 缓存路由
php artisan route:cache

# 缓存视图
php artisan view:cache

# 清除缓存
php artisan cache:clear

2. 数据库优化

  • 使用索引:为经常查询的列添加索引
  • 使用查询构建器:使用 Laravel 的查询构建器来优化查询
  • 使用 Eager Loading:避免 N+1 查询问题
  • 使用数据库连接池:在高流量应用中使用连接池

3. 前端优化

  • 压缩资源:使用 Laravel Mix 或 Vite 来压缩 CSS 和 JavaScript
  • 使用 CDN:使用内容分发网络来加速静态资源
  • 启用浏览器缓存:设置适当的缓存头
  • 使用 HTTP/2:启用 HTTP/2 来加速资源加载

4. 服务器优化

  • 使用 OPcache:启用 PHP OPcache 来提高性能
  • 使用 Redis:使用 Redis 作为缓存和会话存储
  • 使用队列:将耗时任务放入队列
  • 使用负载均衡:在高流量应用中使用负载均衡

9.8 常见问题解决

1. 权限问题

问题storage 目录权限不足

解决

1
2
3
4
# 设置权限
chown -R www-data:www-data /var/www/html/laravel-app
chmod -R 755 /var/www/html/laravel-app/storage
chmod -R 755 /var/www/html/laravel-app/bootstrap/cache

2. 500 错误

问题:服务器返回 500 错误

解决

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看日志
cat /var/log/nginx/error.log
cat /var/log/php8.1-fpm.log

# 检查 .env 文件
cat .env

# 生成应用密钥
php artisan key:generate

# 清除缓存
php artisan cache:clear
php artisan config:cache

3. 数据库连接问题

问题:无法连接到数据库

解决

1
2
3
4
5
6
7
8
# 检查数据库服务状态
systemctl status mysql

# 测试数据库连接
mysql -u laravel_user -p laravel_app

# 检查 .env 文件中的数据库配置
cat .env

4. 路由问题

问题:路由返回 404 错误

解决

1
2
3
4
5
6
7
8
9
10
11
12
# 清除路由缓存
php artisan route:clear
php artisan route:cache

# 查看路由
php artisan route:list

# 检查 .htaccess 文件(Apache)
cat public/.htaccess

# 检查 Nginx 配置
cat /etc/nginx/sites-available/laravel-app

9.9 云服务部署

1. AWS

使用 AWS Elastic Beanstalk

  1. 安装 EB CLI

    1
    pip install awsebcli
  2. 初始化 EB 环境

    1
    2
    cd laravel-app
    eb init
  3. 创建环境

    1
    eb create production-env
  4. 部署应用

    1
    eb deploy

使用 AWS EC2

  1. 创建 EC2 实例
  2. 安装 LAMP/LEMP 堆栈
  3. 部署 Laravel 应用
  4. 配置安全组

2. DigitalOcean

使用 DigitalOcean Droplets

  1. 创建 Droplet
  2. 选择 LAMP/LEMP 一键应用
  3. 部署 Laravel 应用
  4. 配置域名和 SSL

使用 DigitalOcean App Platform

  1. 连接 GitHub 仓库
  2. 选择 Laravel 应用
  3. 配置环境变量
  4. 部署应用

3. Vercel

使用 Vercel

  1. 安装 Vercel CLI

    1
    npm install -g vercel
  2. 部署应用

    1
    2
    cd laravel-app
    vercel
  3. 配置环境变量

    1
    vercel env add

4. Heroku

使用 Heroku

  1. 安装 Heroku CLI

    1
    npm install -g heroku
  2. 登录 Heroku

    1
    heroku login
  3. 创建 Heroku 应用

    1
    heroku create laravel-app
  4. 部署应用

    1
    git push heroku master
  5. 配置环境变量

    1
    2
    3
    4
    heroku config:set APP_KEY=$(php artisan key:generate --show)
    heroku config:set APP_ENV=production
    heroku config:set APP_DEBUG=false
    heroku config:set APP_URL=$(heroku apps:info -s | grep web_url | cut -d= -f2)

9.10 容器化部署

1. 使用 Docker

步骤 1:创建 Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 使用官方 PHP 镜像
FROM php:8.1-fpm

# 设置工作目录
WORKDIR /var/www/html

# 安装依赖
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip \
nginx \
supervisor

# 清理缓存
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# 安装 PHP 扩展
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# 安装 Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# 复制配置文件
COPY nginx.conf /etc/nginx/nginx.conf
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

# 复制应用代码
COPY . /var/www/html

# 安装依赖
RUN composer install --optimize-autoloader --no-dev

# 生成应用密钥
RUN php artisan key:generate

# 设置权限
RUN chown -R www-data:www-data /var/www/html
RUN chmod -R 755 /var/www/html/storage
RUN chmod -R 755 /var/www/html/bootstrap/cache

# 暴露端口
EXPOSE 80

# 启动服务
CMD ["/usr/bin/supervisord"]

步骤 2:创建 docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: '3'
services:
app:
build: .
ports:
- "8000:80"
volumes:
- .:/var/www/html
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: laravel_app
MYSQL_USER: laravel_user
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:

步骤 3:构建和运行

1
2
3
4
5
6
7
8
9
10
11
# 构建镜像
docker-compose build

# 运行容器
docker-compose up -d

# 查看日志
docker-compose logs

# 进入容器
docker-compose exec app bash

2. 使用 Docker Hub

  1. 构建镜像

    1
    docker build -t username/laravel-app .
  2. 推送镜像

    1
    docker push username/laravel-app
  3. 拉取和运行镜像

    1
    2
    docker pull username/laravel-app
    docker run -p 8000:80 username/laravel-app

9.11 监控和维护

1. 日志监控

  • Laravel 日志storage/logs/laravel.log
  • 服务器日志/var/log/nginx/error.log/var/log/php8.1-fpm.log
  • 使用监控服务:如 Papertrail、Logentries 或 AWS CloudWatch

2. 性能监控

  • 使用 Laravel Telescope:在开发环境中监控应用
  • 使用 New Relic:监控生产环境性能
  • 使用 Datadog:监控服务器和应用性能
  • 使用 Blackfire:分析应用性能

3. 定期维护

  • 备份数据库:定期备份数据库
  • 更新依赖:定期更新 Composer 依赖
  • 更新 Laravel:定期更新 Laravel 版本
  • 清理日志:定期清理日志文件
  • 清理缓存:定期清理缓存

9.12 实战示例

现在,让我们部署之前创建的博客应用:

1. 准备部署

1
2
3
4
5
6
7
8
9
10
11
# 进入项目目录
cd laravel-app

# 确保所有更改已提交
git status
git add .
git commit -m "Prepare for deployment"

# 创建 .env 文件
cp .env.example .env
nano .env

2. 配置服务器

安装必要的软件

1
2
3
4
5
6
7
8
9
# 更新系统
apt update && apt upgrade -y

# 安装必要的软件
apt install -y nginx php8.1 php8.1-fpm php8.1-mysql php8.1-cli php8.1-mbstring php8.1-xml php8.1-zip php8.1-gd git composer mysql-server

# 启动服务
systemctl start nginx php8.1-fpm mysql
systemctl enable nginx php8.1-fpm mysql

配置数据库

1
2
3
4
5
6
7
8
9
# 登录 MySQL
mysql -u root -p

# 创建数据库和用户
CREATE DATABASE blog CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'blog_user'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON blog.* TO 'blog_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

配置 Nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 创建 Nginx 配置文件
cat > /etc/nginx/sites-available/blog << 'EOF'
server {
listen 80;
server_name example.com;
root /var/www/html/blog/public;

add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";

index index.php;

charset utf-8;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location = /favicon.ico {
access_log off;
log_not_found off;
}

location = /robots.txt {
access_log off;
log_not_found off;
}

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}

location ~ /\.(?!well-known).* {
deny all;
}
}
EOF

# 启用站点
ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/

# 测试配置
nginx -t

# 重启 Nginx
systemctl restart nginx

3. 部署应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 创建项目目录
mkdir -p /var/www/html/blog
cd /var/www/html/blog

# 克隆代码
git clone https://github.com/username/blog.git .

# 安装依赖
composer install --optimize-autoloader --no-dev

# 配置 .env 文件
cp .env.example .env
nano .env

# 生成应用密钥
php artisan key:generate

# 运行迁移
php artisan migrate --force

# 生成存储链接
php artisan storage:link

# 优化应用
php artisan config:cache
php artisan route:cache
php artisan view:cache

# 设置权限
chown -R www-data:www-data /var/www/html/blog
chmod -R 755 /var/www/html/blog/storage
chmod -R 755 /var/www/html/blog/bootstrap/cache

4. 测试应用

现在,我们可以通过浏览器访问 http://example.com 来测试我们的博客应用。

9.13 部署最佳实践

  1. 使用版本控制:使用 Git 来管理代码
  2. 使用 CI/CD:使用持续集成和持续部署
  3. 使用环境变量:使用环境变量来存储敏感信息
  4. 使用容器化:使用 Docker 来容器化应用
  5. 使用负载均衡:在高流量应用中使用负载均衡
  6. 使用 CDN:使用内容分发网络来加速静态资源
  7. 使用缓存:使用 Redis 或 Memcached 来缓存数据
  8. 使用队列:将耗时任务放入队列
  9. 使用监控:监控应用性能和错误
  10. 使用备份:定期备份数据库和文件

10. 结语

恭喜你完成了《Laravel 教程 - Web 开发实战入门》的学习!在本教程中,我们学习了:

  1. Laravel 基础:Laravel 的历史、特点和优势
  2. 环境搭建:PHP、Composer 和 Laravel 的安装
  3. 项目初始化:Laravel 项目的创建和目录结构
  4. 路由和控制器:Laravel 的路由系统和控制器
  5. 视图:Blade 模板引擎和视图组件
  6. 数据库操作:迁移、模型、查询构建器和 Eloquent ORM
  7. 表单处理:表单验证、CSRF 保护和请求类
  8. 认证系统:用户注册、登录、密码重置和邮箱验证
  9. 文件上传和存储:本地存储、云存储和文件管理
  10. 部署:本地服务器、生产环境部署和优化策略

Laravel 是一个功能强大、优雅的 PHP 框架,它提供了许多工具和功能来帮助我们快速开发 Web 应用。通过本教程的学习,你应该已经掌握了 Laravel 的核心概念和基本用法,可以开始开发自己的 Laravel 应用了。

后续学习建议

  1. 深入学习 Laravel 核心:阅读 Laravel 官方文档,深入学习 Laravel 的核心概念和高级功能
  2. 学习 Laravel 生态系统:学习 Laravel 生态系统中的其他组件,如 Laravel Nova、Laravel Horizon、Laravel Echo 等
  3. 学习前端框架:学习 Vue.js、React 或 Angular 等前端框架,与 Laravel 结合使用
  4. 学习 API 开发:学习使用 Laravel 开发 RESTful API
  5. 学习测试:学习使用 PHPUnit 和 Laravel Dusk 进行测试
  6. 参与开源项目:参与 Laravel 或其他开源项目,提高自己的编程技能
  7. 构建实际项目:构建实际项目,将所学知识应用到实践中

资源推荐

祝你在 Laravel 开发之旅中取得成功!