摘要 Laravel 12 作为 PHP 生态系统中最成熟的企业级框架,通过其优雅的架构设计、强大的服务容器和完善的生态系统,为现代 Web 应用开发提供了全方位的解决方案。本教程深入剖析 Laravel 12 的核心技术栈,从服务容器的依赖注入机制、中间件的执行流程、事件系统的异步处理到队列系统的任务调度,全面覆盖企业级应用开发的关键技术点。通过详细的架构设计指南、性能优化策略和实战案例,帮助开发者构建高性能、可扩展、易维护的 Laravel 12 应用,实现从初级开发者到架构师的技术进阶。
Laravel 12 高级实战教程 - 从架构设计到性能优化 前言 欢迎阅读《Laravel 12 高级实战教程》!本教程基于最新的 Laravel 12 版本,旨在帮助开发者深入理解 Laravel 的核心架构设计和高级技术特性,掌握企业级应用开发的最佳实践。Laravel 12 作为 PHP 生态中最成熟的企业级框架,通过其精心设计的服务容器、中间件系统、事件驱动架构和完善的生态系统,为现代 Web 应用开发提供了全方位的解决方案。本教程将从架构设计的角度出发,深入剖析 Laravel 12 的核心技术,帮助开发者构建高性能、可扩展、易维护的企业级应用。
为什么选择 Laravel 12? Laravel 12 作为 PHP 生态系统中最成熟的企业级框架,通过其精心设计的架构和丰富的企业级特性,为现代 Web 应用开发提供了全方位的解决方案。选择 Laravel 12 的核心优势包括:
优雅的架构设计 :基于服务容器和依赖注入的模块化架构,实现了高度的代码组织和复用强大的服务容器 :提供了灵活的依赖注入机制,支持自动解析、绑定上下文和服务提供者完善的中间件系统 :支持请求生命周期的精细控制,实现认证、授权、日志等横切关注点事件驱动架构 :通过事件和监听器实现组件间的解耦,提高系统的可维护性和可扩展性高性能队列系统 :支持多种队列驱动,实现异步任务处理,提高系统响应速度和可靠性现代化的前端工具链 :集成 Vite 构建工具,支持 React、Vue 等现代前端框架企业级认证授权 :提供完整的认证系统、角色权限管理和 API 认证方案强大的数据库工具 :Eloquent ORM、查询构建器、迁移系统和种子器,简化数据库操作完善的测试工具 :集成 PHPUnit 和 Pest,支持单元测试、功能测试和浏览器测试丰富的生态系统 :Laravel Cashier、Passport、 Sanctum 等官方包,覆盖企业应用的各种需求持续的性能优化 :Laravel 12 在路由解析、服务容器、数据库查询等方面进行了深度优化优秀的可观测性 :集成日志、监控和追踪工具,提供全面的系统运行状态 visibility完善的文档和社区 :详尽的官方文档和活跃的全球社区,确保问题快速解决本教程的目标 通过本教程的学习,您将能够:
掌握 Laravel 12 核心架构 :深入理解服务容器、中间件、事件系统等核心组件的工作原理设计企业级应用架构 :运用领域驱动设计思想,构建模块化、可扩展的应用架构实现高性能 Laravel 应用 :掌握数据库优化、缓存策略、队列使用等性能优化技术构建安全可靠的系统 :实现企业级认证授权、数据验证、CSRF 保护等安全措施开发 RESTful API :设计符合 REST 规范的 API 接口,实现 API 版本控制和文档化集成现代前端框架 :使用 Vite 构建工具,集成 React、Vue 等前端框架实现持续集成与部署 :配置 CI/CD 流水线,实现自动化测试和部署监控与维护生产系统 :搭建日志系统、监控告警,确保系统稳定运行解决复杂业务场景 :运用 Laravel 生态系统,解决企业应用中的复杂业务需求成为 Laravel 架构师 :具备 Laravel 应用架构设计和技术选型的能力前置知识 本教程面向有一定开发经验的 PHP 开发者,适合具有以下技术背景的读者:
扎实的 PHP 编程基础 :熟悉 PHP 8.2+ 语法特性,如类型声明、箭头函数、命名空间等深入的面向对象编程 :理解类、接口、抽象类、 traits 等 OOP 概念数据库设计经验 :熟悉关系型数据库原理,掌握 SQL 查询优化技巧Web 开发基础知识 :了解 HTTP 协议、RESTful API 设计、前端基础技术现代开发工具链 :熟悉 Composer、Git、Docker 等开发工具系统架构概念 :了解 MVC 模式、依赖注入、中间件等架构概念如果您是 Laravel 初学者,建议先完成官方文档的基础教程,掌握 Laravel 的基本使用方法后再开始本教程的学习。
教程结构 本教程采用模块化的结构设计,从核心架构到企业级应用,逐步深入 Laravel 12 的高级特性:
核心架构解析 :深入理解服务容器、中间件、事件系统等核心组件的工作原理服务容器与依赖注入 :掌握服务容器的高级用法,实现灵活的依赖管理中间件系统 :深入理解中间件的执行流程,实现自定义中间件和中间件组事件驱动架构 :设计和实现事件系统,实现组件间的解耦路由系统 :掌握路由的高级用法,实现路由模型绑定、速率限制等功能数据库优化 :深入理解 Eloquent ORM,掌握查询优化、索引设计等技术缓存策略 :实现多级缓存,提高系统性能和响应速度队列系统 :设计和实现异步任务处理,提高系统可靠性和响应速度认证与授权 :实现企业级认证授权系统,包括角色权限管理和 API 认证API 开发 :设计和实现 RESTful API,包括版本控制、文档化等前端集成 :集成现代前端框架,实现前后端分离架构性能优化 :掌握 Laravel 应用的性能优化策略,包括数据库、缓存、队列等部署与监控 :实现 CI/CD 流水线,搭建监控告警系统企业级应用实战 :通过完整的项目案例,综合运用所学知识现在,让我们开始 Laravel 12 的高级学习之旅吧!
1. Laravel 12 企业级环境搭建 搭建一个稳定、高效的企业级 Laravel 12 开发环境是项目成功的基础。Laravel 12 对环境有严格的要求,同时为了满足企业级应用的性能和可靠性需求,我们需要对环境进行精细化配置。
1.1 系统要求 Laravel 12 需要以下软件和扩展:
PHP 8.2+ :推荐使用 PHP 8.3 以获得最佳性能Composer 2.5+ :PHP 依赖管理工具数据库 :MySQL 8.0+、PostgreSQL 14+、SQLite 3.36+ 或 SQL Server 2019+Web 服务器 :Nginx 1.20+ 或 Apache 2.4+缓存系统 :Redis 7.0+ 或 Memcached 1.6+队列系统 :Redis、Beanstalkd、Amazon SQS 或数据库1.2 PHP 扩展要求 Laravel 12 需要启用以下 PHP 扩展:
BCMath Ctype Fileinfo JSON Mbstring OpenSSL PDO Tokenizer XML CURL GD ZIP OPcache Redis(可选,用于缓存和队列) 1.3 环境搭建方案 企业级开发环境推荐使用以下方案:
方案一:Docker 容器化环境 Docker 提供了一致的开发环境,避免了环境差异导致的问题,是企业级开发的首选方案:
1 2 3 4 5 6 7 composer create-project laravel/laravel:^12.0 project-name cd project-name./vendor/bin/sail up
方案二:本地开发环境 对于需要在本地直接运行的开发者,可以使用以下工具:
Windows :Laragon、WAMP 或 XAMPPmacOS :Homebrew + PHP、MAMP 或 Laravel ValetLinux :直接安装 PHP、Nginx/Apache 和数据库1.4 环境配置最佳实践 PHP 配置优化 1 2 3 4 5 6 7 8 9 10 11 12 memory_limit = 512 Mmax_execution_time = 60 upload_max_filesize = 10 Mpost_max_size = 10 Mopcache.enable = 1 opcache.memory_consumption = 256 opcache.max_accelerated_files = 32531 opcache.validate_timestamps = 0 opcache.revalidate_freq = 0 opcache.jit_buffer_size = 128 Mopcache.jit = 1255
开发环境与生产环境分离 开发环境 :启用调试模式,详细错误信息,自动代码重载生产环境 :禁用调试模式,日志记录,启用 OPcache,优化数据库配置1.5 环境验证 搭建完成后,使用以下命令验证环境:
1 2 3 4 5 6 7 8 9 10 11 12 13 php -v php -m composer --version composer create-project laravel/laravel:^12.0 test-project cd test-projectphp artisan serve
1.6 企业级环境管理 环境变量管理 :使用 .env 文件和环境变量管理不同环境的配置依赖版本控制 :使用 composer.lock 确保依赖版本的一致性自动化环境搭建 :使用脚本或配置管理工具(如 Ansible)自动化环境搭建容器编排 :生产环境使用 Kubernetes 等容器编排工具管理容器现在,我们已经搭建了一个企业级的 Laravel 12 开发环境,接下来我们将学习 Laravel 12 的核心架构设计。
Windows 系统 使用 XAMPP
访问 XAMPP 官网 下载最新版本的 XAMPP 运行安装程序,选择安装 PHP 8.2 或更高版本 安装完成后,启动 XAMPP 控制面板,启动 Apache 服务 使用 WAMP
访问 WAMP 官网 下载最新版本的 WAMP 运行安装程序,选择安装 PHP 8.2 或更高版本 安装完成后,启动 WAMP 服务 macOS 系统 使用 Homebrew
1 2 3 4 5 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh) " brew install php
使用 MAMP
访问 MAMP 官网 下载最新版本的 MAMP 运行安装程序,选择安装 PHP 8.2 或更高版本 安装完成后,启动 MAMP 服务 Linux 系统 Ubuntu/Debian
1 2 3 4 5 sudo apt updatesudo 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
CentOS/RHEL
1 2 3 4 5 6 7 8 9 10 11 sudo yum install epel-releasesudo yum install https://rpms.remirepo.net/enterprise/remi-release-8.rpmsudo dnf module enable php:remi-8.2sudo 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 系统 访问 Composer 官网 下载 Composer-Setup.exe 运行安装程序,按照提示完成安装 安装完成后,打开命令提示符,运行 composer --version 验证安装成功 macOS/Linux 系统 1 2 3 4 5 6 7 8 curl -sS https://getcomposer.org/installer | php sudo mv composer.phar /usr/local/bin/composercomposer --version
安装完成后,Composer 将成为 Laravel 12 项目管理的重要工具,用于安装依赖、创建项目和更新框架。
1.3 Laravel 12 安装 Laravel 12 提供了多种安装方式,我们推荐使用 Composer 或 Laravel Installer。
使用 Composer 创建 Laravel 12 项目 1 2 3 4 5 composer create-project laravel/laravel:^12.0 project-name cd project-name
使用 Laravel Installer 安装 Laravel 12 安装 Laravel Installer
1 composer global require laravel/installer
添加 Composer 全局目录到 PATH
Windows:将 %APPDATA%\Composer\vendor\bin 添加到系统环境变量 PATH macOS/Linux:将 ~/.composer/vendor/bin 添加到 ~/.bashrc 或 ~/.zshrc 文件中 创建 Laravel 12 项目
1 2 3 4 laravel new project-name cd project-name
Laravel 12 安装完成后,您就可以开始构建现代化的 Web 应用了。
1.4 Laravel 12 验证安装 安装完成后,我们可以通过以下命令验证 Laravel 12 项目是否创建成功:
然后在浏览器中访问 http://localhost:8000,如果看到 Laravel 12 的欢迎页面,则说明安装成功。Laravel 12 的欢迎页面通常会显示当前 Laravel 版本信息和一些快速开始的链接。
1.5 Laravel 12 数据库配置 Laravel 12 默认使用 MySQL 作为数据库,但也支持 PostgreSQL、SQLite 等其他数据库。我们需要配置数据库连接以确保 Laravel 12 应用能够正常访问数据库。
创建数据库
使用 MySQL 命令行或 phpMyAdmin 创建一个新的数据库 配置 Laravel 12 数据库连接
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 composer create-project laravel/laravel:^12.0 project-name cd project-name
使用 Laravel Installer 创建 Laravel 12 项目 1 2 3 4 5 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 命令 生成 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 迁移 生成 Laravel 12 数据填充 1 php artisan make:seeder SeederName
运行 Laravel 12 数据填充 启动 Laravel 12 开发服务器 Laravel 12 Artisan 命令行工具提供了丰富的命令,大大提高了开发效率,是 Laravel 12 开发中不可或缺的工具。
2.7 Laravel 12 项目初始化示例 现在,让我们创建一个简单的 Laravel 12 项目,来熟悉一下整个流程:
创建 Laravel 12 项目
1 2 composer create-project laravel/laravel:^12.0 blog cd blog
启动 Laravel 12 开发服务器
访问 Laravel 12 应用 在浏览器中访问 http://localhost:8000,你应该能看到 Laravel 12 的欢迎页面。
查看 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.php 和 api.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 ;Route ::get ('/' , function () { return view ('welcome' ); }); Route ::post ('/submit' , function () { }); Route ::put ('/update/{id}' , function ($id ) { }); 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 Route ::get ('/user/{id}' , function ($id ) { return 'User ' . $id ; }); Route ::get ('/user/{name?}' , function ($name = 'Guest' ) { return 'Hello ' . $name ; }); Route ::get ('/user/{id}' , function ($id ) { return 'User ' . $id ; })->where ('id' , '[0-9]+' );
Laravel 12 的路由参数系统非常灵活,支持必选参数、可选参数和带正则表达式约束的参数,满足各种复杂场景的需求。
Laravel 12 命名路由 我们可以为 Laravel 12 路由指定一个名称,这样在生成 URL 或重定向时可以使用这个名称,提高代码的可维护性:
1 2 3 4 5 6 7 8 9 10 Route ::get ('/user/{id}' , function ($id ) { return 'User ' . $id ; })->name ('user.show' ); $url = route ('user.show' , ['id' => 1 ]);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 Route ::prefix ('admin' )->group (function () { Route ::get ('/users' , function () { return 'Admin Users' ; }); Route ::get ('/posts' , function () { return 'Admin Posts' ; }); }); Route ::namespace ('Admin' )->group (function () { Route ::get ('/admin/users' , 'UserController@index' ); }); 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 php artisan make:controller UserController php artisan make:controller PostController --resource 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 ( ) { } public function show ($id ) { } public function create ( ) { } public function store (Request $request ) { } public function edit ($id ) { } public function update (Request $request , $id ) { } public function destroy ($id ) { } }
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 { 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 = Post ::create ($request ->all ()); return redirect ()->route ('posts.show' , $post ->id); } 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 ->id); } 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 ;Route ::get ('/users' , [UserController ::class , 'index' ]);Route ::get ('/users/{id}' , [UserController ::class , 'show' ]);Route ::resource ('posts' , 'PostController' );Route ::resource ('posts' , 'PostController' )->only ([ 'index' , 'show' ]); Route ::resource ('posts' , 'PostController' )->except ([ 'create' , 'store' , 'update' , 'destroy' ]); Route ::apiResource ('products' , 'ProductController' );
Laravel 12 的路由与控制器结合使用,使得代码结构更加清晰,职责更加分明,提高了代码的可维护性和可读性。
3.4 Laravel 12 路由模型绑定 Laravel 12 路由模型绑定允许我们自动将路由参数绑定到对应的模型实例,减少重复代码,提高开发效率:
Laravel 12 隐式路由模型绑定 1 2 3 4 5 6 7 8 9 Route ::get ('/posts/{post}' , [PostController ::class , 'show' ]);public function show (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 public function boot ( ) { parent ::boot (); Route ::model ('user' , App\Models\User ::class ); } 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 Route ::get ('/dashboard' , function () { return view ('dashboard' ); })->middleware ('auth' ); Route ::middleware (['auth' , 'admin' ])->group (function () { Route ::get ('/admin/dashboard' , function () { return view ('admin.dashboard' ); }); }); class UserController extends Controller { public function __construct ( ) { $this ->middleware ('auth' ); $this ->middleware ('admin' )->only ('index' ); $this ->middleware ('guest' )->except ('index' ); } }
Laravel 12 中间件系统非常灵活,可以应用于单个路由、路由组或整个控制器,也可以通过 only 和 except 方法指定中间件应用于控制器的哪些方法。
3.6 Laravel 12 路由和控制器实战示例 现在,让我们创建一个简单的 Laravel 12 博客应用,来演示路由和控制器的使用:
创建 Laravel 12 控制器
1 php artisan make:controller PostController --resource
定义 Laravel 12 资源路由 在 routes/web.php 文件中:
1 2 3 use App \Http \Controllers \PostController ;Route ::resource ('posts' , PostController ::class );
实现 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 ) { 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 ) { return redirect ()->route ('posts.show' , $id ); } public function destroy ($id ) { return redirect ()->route ('posts.index' ); } }
创建 Laravel 12 视图文件 我们将在后面的章节中创建视图文件。
通过这个 Laravel 12 路由和控制器实战示例,你可以了解如何在实际项目中使用 Laravel 12 的路由和控制器,为后续的学习打下基础。
3.7 Laravel 12 路由缓存 对于 Laravel 12 生产环境,我们可以缓存路由以提高性能,减少路由解析时间:
1 2 3 4 5 php artisan route:cache php artisan route:clear
Laravel 12 路由缓存功能可以显著提高应用的性能,特别是在路由数量较多的情况下。但需要注意的是,每次修改路由后都需要重新生成路由缓存。
3.8 Laravel 12 路由列表 我们可以使用 Laravel 12 Artisan 命令查看应用的所有路由,了解路由的定义和映射关系:
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 resources/views/welcome.blade.php 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 return view ('welcome' );return view ('posts.index' );return view ('welcome' , ['name' => 'John' ]);$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 public function boot ( ) { Blade ::directive ('datetime' , function ($expression ) { return "<?php echo ($expression )->format('m/d/Y H:i'); ?>" ; }); } @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 提供了两种类型的组件实现方式,每种都有其特定的使用场景和优势:
类组件 :基于 PHP 类的组件实现,支持完整的逻辑处理和生命周期钩子匿名组件 :纯 Blade 模板实现的组件,适用于简单的展示型组件Laravel 12 创建组件 我们可以使用 Laravel 12 Artisan 命令生成组件,创建可重用的视图片段:
1 2 3 4 5 6 7 8 php artisan make:component Alert php artisan make:component Forms/Input
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 提供了便捷的 Artisan 命令来生成组件,支持基本组件和嵌套组件,使组件开发更加高效和规范化。 #### Laravel 12 组件结构与高级特性 Laravel 12 组件系统采用了现代化的组件架构,由组件类和组件视图两部分组成,支持完整的属性类型声明、默认值设置、插槽系统和生命周期钩子。 ##### 1. 组件视图结构 ```php {{-- Laravel 12 组件视图: resources/views/components/alert.blade.php --}} <div class="alert alert-{{ $type }}" role="alert"> @if (isset($icon)) <i class="{{ $icon }}"></i> @endif <div class="alert-content"> @if (isset($title)) <h4 class="alert-title">{{ $title }}</h4> @endif <div class="alert-message">{{ $slot }}</div> </div> @if (isset($dismissible) && $dismissible) <button type="button" class="close" data-dismiss="alert" aria-label="Close"> <span aria-hidden="true">×</span> </button> @endif </div>
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 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 namespace App \View \Components ;use Illuminate \View \Component ;class Alert extends Component { public string $type ; public bool $dismissible ; public ?string $icon ; public ?string $title ; public function __construct ( string $type = 'info' , bool $dismissible = false , ?string $icon = null , ?string $title = null ) { $this ->type = $type ; $this ->dismissible = $dismissible ; $this ->icon = $icon ; $this ->title = $title ; } public function render ( ) { return view ('components.alert' ); } }
3. 组件高级特性 Laravel 12 组件系统还支持以下高级特性:
动态组件 :根据运行时数据动态渲染不同的组件组件组合 :将多个组件组合成更复杂的组件组件缓存 :缓存组件渲染结果提高性能组件事件 :通过事件系统实现组件间通信Laravel 12 组件结构设计合理,支持传递属性、插槽和复杂逻辑,使组件更加灵活和可重用,是构建现代化前端界面的强大工具。
Laravel 12 组件使用与最佳实践 Laravel 12 组件的使用方式非常灵活,支持多种传递属性和内容的方式,同时提供了丰富的最佳实践来确保组件的可维护性和可扩展性。
1. 组件基本使用 1 2 3 4 5 6 7 8 9 10 11 12 {{-- Laravel 12 组件基本使用 - 使用属性传递数据 --}} <x-alert type="success" title="操作成功" icon="fas fa-check-circle" > 操作已成功完成! </x-alert> {{-- Laravel 12 组件使用 - 布尔属性简写 --}} <x-alert type="warning" dismissible> 此操作需要注意! </x-alert> {{-- Laravel 12 组件使用 - 数组属性 --}} <x-form-input name="user" :options="['name' => '用户名', 'email' => '邮箱']" />
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 {{-- Laravel 12 组件使用 - 具名插槽 --}} <x-card> <x-slot name="header" > <div class ="flex justify -between items -center "> <h3 >用户信息</h3 > <button class ="btn btn -sm btn -outline -secondary ">编辑</button > </div > </x -slot > <x -slot name ="body "> <div class ="user -profile "> <img src =" {{ $user ->avatar }}" alt=" 用户头像" class=" avatar"> <div class=" user-details"> <p><strong>姓名:</strong>{{ $user ->name }}</p> <p><strong>邮箱:</strong>{{ $user ->email }}</p> </div> </div> </x-slot> <x-slot name=" footer"> <div class=" flex justify-end"> <button class=" btn btn-primary mr-2 ">保存</button> <button class=" btn btn-outline-secondary">取消</button> </div> </x-slot> </x-card>
3. 组件使用最佳实践 组件命名规范 :使用小写字母和连字符命名组件,如 alert, form-input组件职责单一 :每个组件只负责一个特定的功能,保持组件的简洁性组件参数验证 :在组件类中使用类型声明和默认值,确保组件参数的正确性组件文档 :为复杂组件添加文档注释,说明组件的用途和参数组件测试 :为重要组件编写测试用例,确保组件的可靠性组件版本控制 :为组件添加版本标识,便于后续的维护和升级Laravel 12 组件使用方式简洁直观,通过 <x-组件名> 标签来使用组件,支持传递属性、使用插槽和复杂逻辑,使视图开发更加模块化和可维护。合理使用组件可以大大提高开发效率,减少代码重复,是构建现代化 Laravel 应用的重要手段。
Laravel 12 组件类高级特性 Laravel 12 组件类提供了丰富的高级特性,支持复杂的逻辑处理、数据转换和生命周期管理,使组件具备更强大的功能和灵活性。
1. 组件类高级结构 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 94 95 96 97 98 99 100 namespace App \View \Components ;use Illuminate \View \Component ;use Illuminate \Support \Str ;class Alert extends Component { public string $type ; public bool $dismissible ; public ?string $icon ; public ?string $title ; public string $id ; public function __construct ( string $type = 'info' , bool $dismissible = false , ?string $icon = null , ?string $title = null ) { $this ->type = $type ; $this ->dismissible = $dismissible ; $this ->icon = $icon ?? $this ->getDefaultIcon ($type ); $this ->title = $title ; $this ->id = 'alert-' . Str ::random (8 ); } protected function getDefaultIcon (string $type ): string { $icons = [ 'success' => 'fas fa-check-circle' , 'error' => 'fas fa-exclamation-circle' , 'warning' => 'fas fa-exclamation-triangle' , 'info' => 'fas fa-info-circle' , ]; return $icons [$type ] ?? $icons ['info' ]; } public function data ( ): array { return [ 'alertClasses' => $this ->getAlertClasses (), 'hasIcon' => !empty ($this ->icon), ]; } protected function getAlertClasses ( ): string { $classes = [ 'alert' , 'alert-' . $this ->type, ]; if ($this ->dismissible) { $classes [] = 'alert-dismissible' ; } return implode (' ' , $classes ); } public function render ( ) { return view ('components.alert' ); } }
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 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 namespace App \View \Components ;use Illuminate \View \Component ;use Illuminate \Support \Facades \Cache ;class DataTable extends Component { public array $data ; public array $config ; public function __construct (array $data , array $config = [] ) { $this ->data = $data ; $this ->config = array_merge ($this ->getDefaultConfig (), $config ); } protected function getDefaultConfig ( ): array { return [ 'pagination' => true , 'search' => true , 'sorting' => true , 'perPage' => 10 , ]; } public function mount ( ) { $this ->initializeData (); } protected function initializeData ( ) { $this ->data = $this ->processData ($this ->data); } protected function processData (array $data ): array { return array_map (function ($item ) { return $item ; }, $data ); } public function render ( ) { return view ('components.data-table' ); } }
3. 组件类最佳实践 类型声明 :使用 PHP 类型声明确保组件参数的类型安全默认值设置 :为可选参数提供合理的默认值数据转换 :在构造函数中执行数据转换和预处理辅助方法 :将复杂逻辑拆分为多个小的辅助方法数据传递 :使用 data() 方法传递额外的视图数据生命周期管理 :合理使用生命周期钩子执行初始化和清理操作依赖注入 :在组件类中使用依赖注入获取服务Laravel 12 组件类是组件系统的核心,通过提供强大的逻辑处理能力和灵活的配置选项,使组件能够处理复杂的业务场景,同时保持代码的清晰和可维护性。
4.5 Laravel 12 视图助手函数系统 Laravel 12 提供了丰富的视图助手函数,涵盖 URL 生成、表单处理、认证授权、缓存操作、国际化等多个领域,大大简化了视图开发,提高了代码的可读性和可维护性。
1. URL 助手函数 Laravel 12 的 URL 助手函数提供了全面的 URL 生成和管理功能,支持各种复杂场景的 URL 构建需求。
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 生成应用基础 URL --}} {{ url ('/' ) }} {{-- Laravel 12 生成安全 HTTPS URL --}} {{ secure_url ('/dashboard' ) }} {{-- Laravel 12 生成资源文件 URL(带版本控制) --}} {{ asset ('css/app.css' ) }} {{-- Laravel 12 生成带自定义协议的 URL --}} {{ url ('/api' , [], true ) }} {{-- 强制 HTTPS --}} {{-- Laravel 12 生成命名路由 URL --}} {{ route ('posts.show' , ['id' => 1 ]) }} {{-- Laravel 12 生成带查询参数的路由 URL --}} {{ route ('posts.index' , ['category' => 'tech' , 'page' => 2 ]) }} {{-- Laravel 12 生成控制器动作 URL --}} {{ action ([PostController ::class , 'show' ], ['id' => 1 ]) }} {{-- Laravel 12 生成邮件可点击链接 --}} {{ url ()->signedRoute ('invitations.accept' , ['invitation' => $invitation ->id]) }} {{-- Laravel 12 生成临时签名 URL(带过期时间) --}} {{ URL::temporarySignedRoute ('files.download' , now ()->addHour (), ['file' => $file ->id]) }}
URL 助手最佳实践 :
使用命名路由生成 URL,提高代码可维护性 对于资源文件,使用 asset() 函数自动处理版本缓存 对于需要安全验证的链接,使用签名路由 避免硬编码 URL,使用助手函数动态生成 2. 表单助手函数 Laravel 12 的表单助手函数简化了表单开发,特别是在 CSRF 保护、方法伪造和表单验证等方面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {{-- Laravel 12 CSRF 令牌字段(现代语法) --}} @csrf {{-- Laravel 12 HTTP 方法伪造字段 --}} @method ('PUT' ) {{-- Laravel 12 旧输入值获取 --}} <input type="text" name="name" value="{{ old('name', $user ->name ?? '') }}" > {{-- Laravel 12 表单错误信息 --}} @error ('email' ) <div class ="alert alert -danger "> {{ $message }}</div> @enderror {{-- Laravel 12 表单验证状态 --}} <input type="text" name="email" class ="form -control @error ('email ') is -invalid @enderror ">
表单助手最佳实践 :
始终使用 @csrf 保护表单提交 对于 PUT/PATCH/DELETE 请求,使用 @method 指令 使用 old() 函数保留表单提交失败时的输入值 结合 Blade 错误指令显示验证错误信息 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 检查用户是否已认证 --}} @auth <div class ="user -menu ">欢迎, {{ auth ()->user ()->name }}</div> @endauth {{-- Laravel 12 检查用户是否为访客 --}} @guest <a href="{{ route('login') }}" >登录</a> @endguest {{-- Laravel 12 检查用户是否具有特定角色 --}} @role ('admin' ) <a href="{{ route('admin.dashboard') }}" >管理后台</a> @endrole {{-- Laravel 12 检查用户是否具有特定权限 --}} @can ('edit' , $post ) <a href="{{ route('posts.edit', $post ->id) }}" >编辑</a> @endcan {{-- Laravel 12 检查用户是否为模型所有者 --}} @owner ($post ) <a href="{{ route('posts.delete', $post ->id) }}" >删除</a> @endowner
认证助手最佳实践 :
使用 Blade 指令 @auth 和 @guest 替代 auth()->check() 对于权限检查,使用 @can 指令替代手动权限判断 结合 Gates 和 Policies 使用授权指令,实现细粒度权限控制 4. 缓存助手函数 Laravel 12 提供了缓存助手函数,支持在视图中直接进行缓存操作,提高页面渲染性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 {{-- Laravel 12 缓存视图片段(5 分钟) --}} @cache ('sidebar' , 300 ) <div class ="sidebar "> <!-- 复杂的侧边栏内容 --> </div > @endcache {{-- Laravel 12 带标签的缓存 --}}@cache ('user-profile-' .$user ->id, 60 , ['users' , 'profiles' ]) <div class ="user -profile "> <!-- 用户资料内容 --> </div > @endcache {{-- Laravel 12 获取缓存值 --}}{{ cache ('site_settings' )['copyright' ] }}
缓存助手最佳实践 :
对渲染成本高的视图片段使用缓存 为缓存项添加合适的过期时间 使用缓存标签便于批量失效 避免在视图中进行复杂的缓存逻辑 5. 国际化助手函数 Laravel 12 的国际化助手函数支持多语言应用的开发,提供了简洁的翻译和本地化功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 {{-- Laravel 12 基本翻译 --}} {{ __ ('Welcome to our application' ) }} {{-- Laravel 12 带参数的翻译 --}} {{ __ ('Hello, :name' , ['name' => $user ->name]) }} {{-- Laravel 12 复数形式翻译 --}} {{ trans_choice ('There is :count product|There are :count products' , $count ) }} {{-- Laravel 12 日期本地化 --}} {{ $post ->created_at->translatedFormat ('l, d F Y' ) }} {{-- Laravel 12 数字本地化 --}} {{ number_format ($price , 2 , ',' , '.' ) }}
国际化助手最佳实践 :
将所有用户可见文本放入翻译文件 使用参数化翻译提高灵活性 为不同语言提供适当的复数形式 结合 Carbon 实例使用日期本地化 6. 其他实用助手函数 Laravel 12 还提供了许多其他实用的视图助手函数,覆盖了各种常见的开发需求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 {{-- Laravel 12 生成随机字符串 --}} {{ Str ::random (16 ) }} {{-- Laravel 12 格式化文件大小 --}} {{ number_format ($fileSize / 1024 , 2 ) }} KB {{-- Laravel 12 检查环境 --}} @env ('local' ) <div class ="debug -info ">Local Environment </div > @endenv {{-- Laravel 12 检查配置值 --}}@if (config ('app.debug' )) <div class ="debug -mode ">Debug Mode Enabled </div > @endif {{-- Laravel 12 显示环境变量 --}}{{ env ('APP_NAME' ) }}
综合最佳实践 :
合理使用助手函数简化视图代码 避免在视图中进行复杂的业务逻辑处理 结合 Blade 指令和助手函数提高代码可读性 遵循 Laravel 编码规范,保持代码风格一致 Laravel 12 的视图助手函数系统是一个强大的工具集,通过合理使用这些助手函数,可以大大提高视图开发效率,减少重复代码,同时保持代码的清晰和可维护性。
4.6 Laravel 12 视图实战示例 现在,让我们为之前创建的 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 {{-- 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:</body> </html>
创建 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
创建 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
创建 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
创建 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 php artisan view:clear 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 php artisan make:migration create_users_table php artisan make:migration create_users_table --create=users 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 php artisan migrate php artisan migrate:rollback php artisan migrate:reset php artisan migrate:fresh 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 (); $table ->string ('name' ); $table ->text ('description' ); $table ->integer ('age' ); $table ->bigInteger ('price' ); $table ->float ('rate' ); $table ->double ('score' ); $table ->decimal ('amount' , 8 , 2 ); $table ->boolean ('active' ); $table ->date ('birthday' ); $table ->time ('time' ); $table ->datetime ('created_at' ); $table ->timestamp ('updated_at' ); $table ->json ('data' ); $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 (); $table ->string ('email' )->unique (); $table ->string ('password' )->default ('secret' ); $table ->integer ('age' )->unsigned (); $table ->string ('name' )->length (100 ); $table ->integer ('order' )->autoIncrement (); $table ->string ('name' )->comment ('用户名称' );
Laravel 12 列修饰符非常强大,可以定义字段的各种属性,如可为空、唯一、默认值、长度、自增和注释等,使数据库字段定义更加精确和灵活。
Laravel 12 索引 Laravel 12 提供了多种索引类型,用于优化数据库查询性能:
1 2 3 4 5 6 7 $table ->index ('email' ); $table ->unique ('email' ); $table ->primary ('id' ); $table ->foreign ('user_id' )->references ('id' )->on ('users' ); $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 php artisan make:seeder UserSeeder 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 { 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 ( ) { User ::factory ()->count (10 )->create (); User ::factory ()->count (5 )->create ([ 'role' => 'admin' , ]); } }
Laravel 12 模型工厂非常强大,可以快速生成大量测试数据,也可以指定特定属性,使数据填充更加灵活和可控。
Laravel 12 运行填充器 我们可以使用 Laravel 12 Artisan 命令运行填充器,向数据库中插入初始数据:
1 2 3 4 5 6 7 8 php artisan db:seed --class=UserSeeder php artisan db:seed 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 php artisan make:model User php artisan make:model User -m 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 ; protected $fillable = [ 'name' , 'email' , 'password' , ]; protected $hidden = [ 'password' , 'remember_token' , ]; 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 ;$users = User ::all ();$user = User ::find (1 );$user = User ::where ('email' , 'admin@example.com' )->first ();$users = User ::where ('age' , '>' , 18 )->get ();$users = User ::orderBy ('name' , 'asc' )->get ();$users = User ::paginate (10 );$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 $user = User ::create ([ 'name' => 'John Doe' , 'email' => 'john@example.com' , 'password' => bcrypt ('password' ), ]); $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 $user = User ::find (1 );$user ->update ([ 'name' => 'Jane Doe' , ]); $user = User ::find (1 );$user ->name = 'Jane Doe' ;$user ->save ();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 $user = User ::find (1 );$user ->delete ();User ::destroy (1 );User ::destroy ([1 , 2 , 3 ]);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 use Illuminate \Database \Eloquent \SoftDeletes ;class User extends Model { use HasFactory , SoftDeletes ; } $table ->softDeletes ();$user = User ::find (1 );$user ->delete ();$users = User ::withTrashed ()->get ();$users = User ::onlyTrashed ()->get ();$user = User ::withTrashed ()->find (1 );$user ->restore ();$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 public function profile ( ) { return $this ->hasOne (Profile ::class ); } public function user ( ) { return $this ->belongsTo (User ::class ); } $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 public function comments ( ) { return $this ->hasMany (Comment ::class ); } public function post ( ) { return $this ->belongsTo (Post ::class ); } $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 public function roles ( ) { return $this ->belongsToMany (Role ::class ); } public function users ( ) { return $this ->belongsToMany (User ::class ); } $user = User ::find (1 );$roles = $user ->roles;$role = Role ::find (1 );$users = $role ->users;$user ->roles ()->attach ($roleId );$user ->roles ()->detach ($roleId );$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 $users = User ::with ('profile' )->get ();$posts = Post ::with ('comments.user' )->get ();$users = User ::all ();$users ->load ('profile' );$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 ;$users = DB::table ('users' )->get ();$users = DB::table ('users' )->where ('age' , '>' , 18 )->get ();$users = DB::table ('users' )->orderBy ('name' , 'asc' )->get ();$users = DB::table ('users' )->limit (10 )->offset (5 )->get ();$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 $users = DB::table ('users' ) ->join ('profiles' , 'users.id' , '=' , 'profiles.user_id' ) ->select ('users.*' , 'profiles.bio' ) ->get (); $users = DB::table ('users' ) ->leftJoin ('profiles' , 'users.id' , '=' , 'profiles.user_id' ) ->select ('users.*' , 'profiles.bio' ) ->get (); $users = DB::table ('users' ) ->rightJoin ('profiles' , 'users.id' , '=' , 'profiles.user_id' ) ->select ('users.*' , 'profiles.bio' ) ->get (); $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 $users = DB::table ('users' )->where ('age' , '>' , 18 )->get ();$users = DB::table ('users' ) ->where ('age' , '>' , 18 ) ->where ('active' , 1 ) ->get (); $users = DB::table ('users' ) ->where ('age' , '>' , 18 ) ->orWhere ('active' , 1 ) ->get (); $users = DB::table ('users' ) ->where (function ($query ) { $query ->where ('age' , '>' , 18 ) ->orWhere ('active' , 1 ); }) ->where ('verified' , 1 ) ->get (); $users = DB::table ('users' ) ->whereBetween ('age' , [18 , 30 ]) ->get (); $users = DB::table ('users' ) ->whereIn ('id' , [1 , 2 , 3 ]) ->get (); $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 DB::table ('users' )->insert ([ 'name' => 'John Doe' , 'email' => 'john@example.com' , ]); $id = DB::table ('users' )->insertGetId ([ 'name' => 'John Doe' , 'email' => 'john@example.com' , ]); DB::table ('users' )->insert ([ ['name' => 'John Doe' , 'email' => 'john@example.com' ], ['name' => 'Jane Doe' , 'email' => 'jane@example.com' ], ]); DB::table ('users' )->where ('id' , 1 )->update ([ 'name' => 'Jane Doe' , ]); DB::table ('users' )->where ('id' , 1 )->increment ('age' ); DB::table ('users' )->where ('id' , 1 )->decrement ('age' ); DB::table ('users' )->where ('id' , 1 )->delete (); 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 $users = DB::select ('SELECT * FROM users WHERE active = ?' , [1 ]);DB::insert ('INSERT INTO users (name, email) VALUES (?, ?)' , ['John Doe' , 'john@example.com' ]); DB::update ('UPDATE users SET active = ? WHERE id = ?' , [1 , 1 ]); DB::delete ('DELETE FROM users WHERE id = ?' , [1 ]); DB::statement ('DROP TABLE IF EXISTS users' ); 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 () { 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 ;DB::beginTransaction (); try { DB::table ('users' )->update (['votes' => 1 ]); DB::table ('posts' )->delete (); DB::commit (); } catch (\Exception $e ) { DB::rollBack (); }
Laravel 12 事务嵌套 1 2 3 4 5 6 7 8 9 DB::transaction (function () { DB::table ('users' )->update (['votes' => 1 ]); DB::transaction (function () { DB::table ('posts' )->delete (); }, 5 ); }, 3 );
Laravel 12 事务非常强大,支持自动事务、手动事务和事务嵌套等多种方式,并提供了事务重试机制,使数据库操作更加安全和可靠。
5.9 Laravel 12 实战示例 现在,让我们为之前创建的 Laravel 12 博客应用添加数据库功能:
创建帖子迁移
1 php artisan make:migration create_posts_table
编辑迁移文件
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' ); } }
运行迁移
创建帖子模型
1 php artisan make:model Post
编辑模型文件
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' , ]; }
更新控制器
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' ); } }
更新路由
1 2 3 use App \Http \Controllers \PostController ;Route ::resource ('posts' , PostController ::class );
更新视图
更新 posts/index.blade.php 以显示实际数据 更新 posts/show.blade.php 以显示实际数据 更新 posts/edit.blade.php 以显示实际数据 创建帖子填充器
1 php artisan make:seeder PostSeeder
编辑填充器
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.' , ]); } }
运行填充器
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 <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 ;public function store (Request $request ) { $title = $request ->input ('title' ); $content = $request ->input ('content' ); $data = $request ->all (); $data = $request ->only (['title' , 'content' ]); $data = $request ->except (['_token' ]); if ($request ->has ('title' )) { } if ($request ->has (['title' , 'content' ])) { } if ($request ->filled ('title' )) { } if ($request ->missing ('title' )) { } Post ::create ($data ); 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 ;public function store (Request $request ) { $rules = [ 'title' => 'required|min:3|max:255' , 'content' => 'required|min:10' , ]; $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' , ]; $attributes = [ 'title' => 'Post Title' , 'content' => 'Post Content' , ]; $request ->validate ($rules , $messages , $attributes ); Post ::create ($request ->all ()); return redirect ()->route ('posts.index' ); }
Laravel 12 请求类验证 Laravel 12 请求类验证是一种更优雅的验证方式,它将验证逻辑从控制器中分离出来,使代码更加清晰和可维护。
1 2 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 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' , ]; } 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' , ]; } 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 ;public function store (StorePostRequest $request ) { Post ::create ($request ->validated ()); 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 '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 namespace App \Rules ;use Illuminate \Contracts \Validation \Rule ;class Uppercase implements Rule { public function passes ($attribute , $value ) { return strtoupper ($value ) === $value ; } 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 ;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 <meta name="csrf-token" content="{{ csrf_token() }}" > $.ajaxSetup ({ headers : { 'X-CSRF-TOKEN' : $('meta[name="csrf-token"]' ).attr ('content' ) } }); $.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 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 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 2 php artisan make:request StorePostRequest php artisan make:request UpdatePostRequest
编辑 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' , ]; } }
编辑 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' , ]; } }
更新控制器
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 ); }
更新视图
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('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 <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 composer require laravel/jetstream php artisan jetstream:install livewire 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 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 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 ('/' ); } }
密码重置控制器 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 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 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 @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 @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 @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 @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 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 @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 ();$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 '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 auth ('admin' )->attempt (['email' => $email , 'password' => $password ]);$admin = auth ('admin' )->user ();Route ::middleware ('auth:admin' )->group (function () { });
自定义认证字段 我们可以修改认证逻辑来使用不同的字段进行认证:
1 2 3 4 5 6 7 8 auth ()->attempt (['username' => $username , 'password' => $password ]);public function username ( ) { return 'username' ; }
7.7 邮箱验证 Laravel 提供了内置的邮箱验证功能:
1. 更新用户模型 1 2 3 4 5 class User extends Authenticatable implements MustVerifyEmail { }
2. 注册路由 1 2 3 4 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 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 @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 Route ::middleware (['auth' , 'verified' ])->group (function () { Route ::get ('/dashboard' , [DashboardController ::class , 'index' ]); });
7.8 实战示例 现在,让我们为之前创建的博客应用添加认证功能:
创建认证控制器
1 2 php artisan make:controller AuthController php artisan make:controller DashboardController
编辑认证控制器
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 ('/' ); } }
编辑仪表板控制器
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' ); } }
创建认证视图
创建 resources/views/auth/register.blade.php 创建 resources/views/auth/login.blade.php 创建 resources/views/dashboard.blade.php 定义路由
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' ); });
更新布局文件
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 <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.9 安全建议 在实现认证系统时,我们应该遵循以下安全建议:
使用密码哈希 :永远不要明文存储密码,使用 Laravel 提供的 Hash 门面来哈希密码使用 HTTPS :在生产环境中使用 HTTPS 来保护用户数据实现 CSRF 保护 :使用 Laravel 的 CSRF 保护来防止跨站请求伪造攻击限制登录尝试 :实现登录尝试限制,防止暴力破解使用安全的会话管理 :使用 Laravel 的会话管理功能实现邮箱验证 :验证用户邮箱,防止垃圾注册使用强密码策略 :要求用户使用强密码定期更新密码 :鼓励用户定期更新密码实现双因素认证 :对于敏感操作,实现双因素认证安全存储令牌 :安全存储重置密码令牌等临时令牌现在,我们已经了解了 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 namespace App \Http \Controllers ;use Illuminate \Http \Request ;class UploadController extends Controller { public function upload (Request $request ) { $request ->validate ([ 'file' => 'required|file|max:1024' , // 1 MB 限制 ]); $file = $request ->file ('file' ); if ($file ->isValid ()) { $path = $file ->store ('uploads' ); return back ()->with ('success' , 'File uploaded successfully!' )->with ('path' , $path ); } return back ()->with ('error' , 'File upload failed!' ); } }
3. 路由定义 1 2 3 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 ();$appPath = storage_path ('app' );$publicPath = storage_path ('app/public' );$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 '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 $path = $file ->store ('images' , 's3' );$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 '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 $path = $file ->store ('images' , 'gcs' );$url = Storage ::disk ('gcs' )->url ($path );
8.4 文件验证 在上传文件时,我们应该验证文件的类型、大小等属性:
1. 基本验证规则 1 2 3 4 5 6 7 8 9 10 $request ->validate ([ // 验证文件存在且是有效文件 'file' => 'required|file' , // 验证文件大小(1 MB) '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 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 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 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 <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 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 @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 @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 安全建议 在实现文件上传功能时,我们应该遵循以下安全建议:
验证文件类型 :使用 mimes 或 image 规则验证文件类型限制文件大小 :使用 max 规则限制文件大小,防止上传过大的文件重命名文件 :使用 storeAs 方法重命名上传的文件,避免文件名冲突和安全问题使用安全的存储位置 :对于敏感文件,使用本地存储而不是公共存储扫描上传的文件 :使用第三方库扫描上传的文件,防止恶意文件设置适当的文件权限 :确保存储目录有适当的文件权限使用 HTTPS :在生产环境中使用 HTTPS 传输文件实现文件上传速率限制 :防止恶意用户上传大量文件使用内容安全策略 :限制可以从哪些来源加载文件定期清理未使用的文件 :定期清理未使用的上传文件,节省存储空间8.8 高级技巧 1. 图片处理 我们可以使用 intervention/image 库来处理图片:
安装依赖 :
1 composer require intervention/image
配置 :
1 2 3 4 5 6 7 8 9 10 '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 composer global require laravel/valet valet install cd ~/Sitesvalet park cd ~/Sites/laravel-appvalet link
2. 使用 Valet 1 2 3 4 5 6 7 8 9 10 11 valet sites valet restart valet stop 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-appcd /var/www/laravel-appgit 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/hookscat > /var/www/laravel-app/hooks/post-receive << 'EOF' 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" 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 项目
登录 Laravel Envoyer 创建新项目 连接到 GitHub、GitLab 或 Bitbucket 仓库 步骤 2:配置服务器
添加服务器 设置部署路径 配置 SSH 密钥 步骤 3:配置部署钩子
设置部署前钩子 设置部署后钩子 配置通知 步骤 4:部署应用
触发部署 监控部署过程 查看部署日志 3. 使用 Laravel Forge Laravel Forge 是一个服务器管理和部署服务,可以轻松创建和管理服务器:
步骤 1:创建 Forge 账户
登录 Laravel Forge 连接到服务器提供商(DigitalOcean、AWS、Linode 等) 步骤 2:创建服务器
选择服务器提供商 配置服务器规格 部署服务器 步骤 3:创建站点
添加新站点 配置域名 连接到 Git 仓库 步骤 4:部署应用
触发部署 配置环境变量 运行迁移 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 apt update apt install mysql-server 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 apt update apt install postgresql postgresql-contrib sudo -u postgres psqlCREATE 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 cp .env.example .env nano .env
2. 环境变量最佳实践 不要提交 .env 文件 :将 .env 文件添加到 .gitignore使用不同的环境变量 :为开发、测试和生产环境使用不同的 .env 文件使用环境变量管理服务 :如 Laravel Envoyer、AWS Parameter Store 或 HashiCorp Vault设置适当的权限 :确保 .env 文件的权限为 6009.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-appchmod -R 755 /var/www/html/laravel-app/storagechmod -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.logcat /var/log/php8.1-fpm.logcat .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 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 cat public/.htaccesscat /etc/nginx/sites-available/laravel-app
9.9 云服务部署 1. AWS 使用 AWS Elastic Beanstalk :
安装 EB CLI
初始化 EB 环境
创建环境
1 eb create production-env
部署应用
使用 AWS EC2 :
创建 EC2 实例 安装 LAMP/LEMP 堆栈 部署 Laravel 应用 配置安全组 2. DigitalOcean 使用 DigitalOcean Droplets :
创建 Droplet 选择 LAMP/LEMP 一键应用 部署 Laravel 应用 配置域名和 SSL 使用 DigitalOcean App Platform :
连接 GitHub 仓库 选择 Laravel 应用 配置环境变量 部署应用 3. Vercel 使用 Vercel :
安装 Vercel CLI
部署应用
配置环境变量
4. Heroku 使用 Heroku :
安装 Heroku CLI
登录 Heroku
创建 Heroku 应用
1 heroku create laravel-app
部署应用
配置环境变量
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 FROM php:8.1 -fpmWORKDIR /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/* RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd 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 docker build -t username/laravel-app .
推送镜像
1 docker push username/laravel-app
拉取和运行镜像
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 CloudWatch2. 性能监控 使用 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-appgit status git add . git commit -m "Prepare for deployment" 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 -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 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 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/blogcd /var/www/html/bloggit clone https://github.com/username/blog.git . composer install --optimize-autoloader --no-dev 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/blogchmod -R 755 /var/www/html/blog/storagechmod -R 755 /var/www/html/blog/bootstrap/cache
4. 测试应用 现在,我们可以通过浏览器访问 http://example.com 来测试我们的博客应用。
9.13 部署最佳实践 使用版本控制 :使用 Git 来管理代码使用 CI/CD :使用持续集成和持续部署使用环境变量 :使用环境变量来存储敏感信息使用容器化 :使用 Docker 来容器化应用使用负载均衡 :在高流量应用中使用负载均衡使用 CDN :使用内容分发网络来加速静态资源使用缓存 :使用 Redis 或 Memcached 来缓存数据使用队列 :将耗时任务放入队列使用监控 :监控应用性能和错误使用备份 :定期备份数据库和文件10. 结语 恭喜你完成了《Laravel 教程 - Web 开发实战入门》的学习!在本教程中,我们学习了:
Laravel 基础 :Laravel 的历史、特点和优势环境搭建 :PHP、Composer 和 Laravel 的安装项目初始化 :Laravel 项目的创建和目录结构路由和控制器 :Laravel 的路由系统和控制器视图 :Blade 模板引擎和视图组件数据库操作 :迁移、模型、查询构建器和 Eloquent ORM表单处理 :表单验证、CSRF 保护和请求类认证系统 :用户注册、登录、密码重置和邮箱验证文件上传和存储 :本地存储、云存储和文件管理部署 :本地服务器、生产环境部署和优化策略Laravel 是一个功能强大、优雅的 PHP 框架,它提供了许多工具和功能来帮助我们快速开发 Web 应用。通过本教程的学习,你应该已经掌握了 Laravel 的核心概念和基本用法,可以开始开发自己的 Laravel 应用了。
后续学习建议 深入学习 Laravel 核心 :阅读 Laravel 官方文档,深入学习 Laravel 的核心概念和高级功能学习 Laravel 生态系统 :学习 Laravel 生态系统中的其他组件,如 Laravel Nova、Laravel Horizon、Laravel Echo 等学习前端框架 :学习 Vue.js、React 或 Angular 等前端框架,与 Laravel 结合使用学习 API 开发 :学习使用 Laravel 开发 RESTful API学习测试 :学习使用 PHPUnit 和 Laravel Dusk 进行测试参与开源项目 :参与 Laravel 或其他开源项目,提高自己的编程技能构建实际项目 :构建实际项目,将所学知识应用到实践中资源推荐 祝你在 Laravel 开发之旅中取得成功!