十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

使用 Yii 2 构建表单:模型、校验与 ActiveForm 完整实战指南

使用 Yii 2 构建表单:模型、校验与 ActiveForm 完整实战指南 使用 Yii 2 构建表单模型、校验与 ActiveForm 完整实战指南【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2本篇文章基于 Yii 2 官方指南中的“表单处理”章节对应仓库 docs/guide-pl/start-forms.md 及其英文原版 docs/guide/start-forms.md完整演示如何从零创建一个用于收集用户数据的表单页面页面包含name与email两个输入字段提交后把用户输入的值回显确认。你将掌握三件事创建承载表单数据的 Model 类并声明校验规则、在控制器中编写处理表单提交的 Action、以及用ActiveForm组件在视图中渲染带标签与错误提示的 HTML 表单。文章还深入框架源码framework/base/Model.php、framework/widgets/ActiveForm.php解释验证的底层执行流程与客户端/服务端双重校验机制。前置说明本文以 Yii 2 基础应用模板为背景即通过 start-installation.md 安装好的项目结构示例代码中出现的app\models、app\controllers命名空间与views/site/目录均来自该模板约定。若尚未完成入门流程建议先阅读 start-hello.md 了解 Action 与视图的创建方式以及 concept-autoloading.md 了解类文件命名与自动加载约定。整体思路MVC 三要素协同要构建一个可用的表单页面除了创建 action动作和两个 views视图之外还需要一个 model模型。三者各司其职Model用类来表示用户通过表单提交的数据并声明对这些数据的校验规则Action接收 HTTP 请求把请求数据填充进模型、执行校验然后根据校验结果决定渲染哪个视图View负责输出 HTML 表单数据采集页以及提交成功后的确认回显页。本教程将带你逐步完成以下三件事创建一个 Model 类代表用户通过表单输入的数据在 Model 中声明用于检查输入数据的校验规则rules在 View 中构建 HTML 表单。第一步创建模型Model需要向用户采集的数据由EntryForm模型类表示保存在models/EntryForm.php文件中。类文件与类名的命名约定遵循 Yii 的自动加载机制详见 概念类自动加载。?php namespace app\models; use Yii; use yii\base\Model; class EntryForm extends Model { public $name; public $email; public function rules() { return [ [[name, email], required], [email, email], ]; } }为什么继承yii\base\ModelEntryForm继承自 [[yii\base\Model]]这是 Yii 提供的基础类通常用于表示表单数据。在 framework/base/Model.php 的类注释中官方明确了它的定位与内置能力属性声明attribute declaration默认情况下每个 public 成员都会被当作模型属性attributes()通过反射ReflectionClass收集类中所有非静态的 public 属性属性标签attribute labels每个属性可关联一个用于展示的标签批量赋值massive attribute assignment支持一次性把数组数据批量填充到模型属性基于场景的校验scenario-based validation按场景执行校验规则。InfoModel是不关联数据库表的模型类的父类而yii\db\ActiveRecord才是关联数据库表的模型类的父类。本文示例属于前者。两个 public 属性name与email两个 public 属性用于存放用户输入的数据。正因为它们是 publicModel才能通过反射机制把它们识别为可批量赋值的属性——这是后续load()能自动填充数据的前提。声明校验规则rules()模型中的rules()方法返回一组校验规则上面的规则表达了两个约束name和email两个字段的值都是必填的required校验器email字段的值必须是语法上合法的 email 地址email校验器。关于规则的写法framework/base/Model.php 的文档注释给出了完整约定每条规则是一个数组第一个元素是属性列表单个属性可直接传字符串第二个元素是校验器类型可以是内置校验器别名、模型类方法名、匿名函数或校验器类名还可以通过on指定适用场景、通过额外的键值对初始化校验器属性例如[username, string, min 3, max 12]。Yii 内置了丰富的校验器集合完整清单可参考 tutorial-core-validators.md。触发校验validate()与错误读取当EntryForm对象被填充了用户数据后可以调用它的 [[yii\base\Model::validate()|validate()]] 方法触发数据校验例程。校验失败时[[yii\base\Model::hasErrors|hasErrors]] 属性会变为true并可通过 [[yii\base\Model::getErrors()|getErrors()]] 查看具体发生了哪些错误。?php $model new EntryForm(); $model-name Qiang; $model-email bad; if ($model-validate()) { // 校验通过 } else { // 校验失败 // 使用 $model-getErrors() 查看错误详情 }从源码看validate()的实际执行流程framework/base/Model.php为先调用clearErrors()清空旧错误 → 触发beforeValidate事件可通过 EVENT_BEFORE_VALIDATE 拦截并终止校验→ 依据当前场景获取活跃属性与活跃校验器 → 逐个执行Validator::validateAttributes()→ 触发afterValidate事件 → 最终返回!$this-hasErrors()。本例中email bad明显不是合法邮箱因此validate()会返回false且getErrors()中会包含 email 属性的错误信息。第二步创建动作Action接下来需要在site控制器中创建一个名为entry的动作来使用新模型。动作的创建与使用流程已在 你好世界 一节中介绍过。?php namespace app\controllers; use Yii; use yii\web\Controller; use app\models\EntryForm; class SiteController extends Controller { // ...现有代码... public function actionEntry() { $model new EntryForm(); if ($model-load(Yii::$app-request-post()) $model-validate()) { // 已接收到合法数据并填充进 $model // 在此对 $model 做有意义的事情…… return $this-render(entry-confirm, [model $model]); } else { // 要么是首次打开页面要么是校验出现错误 return $this-render(entry, [model $model]); } } }动作的完整工作流该动作的工作流程可以拆解为四步实例化模型new EntryForm()创建空模型对象填充数据$model-load(Yii::$app-request-post())尝试把$_POST数据填充进模型。load()的实现位于 framework/base/Model.php它按照模型的formName()默认取类名从提交数据中取出对应分组并批量赋值。Yii 通过 [[yii\web\Request::post()|post()]] 安全地访问$_POST数据执行校验若load()成功说明用户确实提交了 HTML 表单则调用validate()确保输入值合法分流渲染一切正常时渲染entry-confirm视图向用户确认数据提交成功若没有任何提交或数据包含错误则渲染entry视图在该视图中展示 HTML 表单并附带校验错误消息。Info表达式Yii::$app表示 应用application 实例它是全局可访问的单例。同时它也是一个 服务定位器service locator提供request、response、db等组件以支撑特定功能。上面的代码正是通过应用实例的request组件来访问$_POST数据。Note在这个简单示例中数据校验通过后我们只是直接渲染确认页。实际项目中建议使用 [[yii\web\Controller::refresh()|refresh()]] 或 [[yii\web\Controller::redirect()|redirect()]] 进行页面跳转以避免表单重复提交Post/Redirect/Get 模式带来的问题。第三步创建视图View最后创建两个视图文件entry-confirm和entry它们由entry动作按上述逻辑分别渲染。确认视图entry-confirmentry-confirm视图只是简单地展示name与email数据保存在views/site/entry-confirm.php?php use yii\helpers\Html; ? p您输入了以下信息/p ul lilabel名称/label: ? Html::encode($model-name) ?/li lilabel邮箱/label: ? Html::encode($model-email) ?/li /ul注意这里使用Html::encode()对输出进行 HTML 转义这是 Yii 安全最佳实践的核心要求——防止用户输入被当作 HTML 执行XSS 攻击。关于更多安全实践可参考 security-best-practices.md。表单视图entryentry视图负责输出 HTML 表单保存在views/site/entry.php?php use yii\helpers\Html; use yii\widgets\ActiveForm; ? ?php $form ActiveForm::begin(); ? ? $form-field($model, name) ? ? $form-field($model, email) ? div classform-group ? Html::submitButton(提交, [class btn btn-primary]) ? /div ?php ActiveForm::end(); ?ActiveForm 是如何工作的该视图使用了功能强大的 widget小组件 [[yii\widgets\ActiveForm|ActiveForm]] 来构建 HTML 表单源码位于 framework/widgets/ActiveForm.phpbegin()与end()方法分别渲染表单的开标签与闭标签两个方法调用之间通过field()方法创建输入字段ActiveForm::field() 内部会基于fieldConfig与传入的模型、属性创建一个 ActiveField 对象第一个字段用于name数据第二个用于email数据。每个字段自动包含三部分label 标签、输入控件、错误提示区字段之后调用 [[yii\helpers\Html::submitButton()|submitButton()]] 生成提交按钮。动手验证运行表单页在浏览器中访问以下地址来查看效果https://hostname/index.php?rsite%2Fentry你会看到一个包含两个输入字段的页面每个字段前都有描述其含义的标签。如果未输入任何内容就点击“提交”按钮或输入的邮箱地址不合法每个出问题的输入框旁都会显示对应的错误消息见文首第一张截图。在输入合法的名称与邮箱地址并点击提交后会跳转到新页面显示你刚刚输入的数据见文首第二张截图。揭秘“魔法”客户端与服务端双重校验你可能会好奇这个 HTML 表单为什么“看起来像魔法一样”——不用刷新页面就能为每个字段显示标签、在输入错误时立刻提示错误消息。答案在于双层校验机制客户端校验数据校验首先在浏览器端通过 JavaScript 完成。ActiveForm足够智能能把你声明在EntryForm中的校验规则提取出来转换成可执行的 JavaScript 代码并注册到页面见ActiveForm::registerClientScript()位于 framework/widgets/ActiveForm.php然后用这些 JS 代码在提交前后进行即时校验服务端校验即使你在浏览器中禁用了 JavaScript校验仍会在服务端照常执行正如actionEntry()中演示的那样。这保证了任何情况下数据都是有效的。Warning客户端校验只是提升用户体验的便捷手段服务端校验始终是必须的——无论客户端校验是否开启服务端都必须校验数据。因为客户端校验可以被绕过服务端才是数据安全的最后防线。ActiveForm 的客户端校验配置项从源码看客户端校验行为由 ActiveForm 的多个 public 属性 控制默认值如下配置项默认值作用enableClientValidationtrue是否启用客户端数据校验ActiveField级设置可覆盖enableAjaxValidationfalse是否启用基于 AJAX 的数据校验enableClientScripttrue是否挂载yii.activeFormJavaScript 插件为false时表单不生成任何 JSvalidateOnSubmittrue是否在表单提交时执行校验validateOnChangetrue是否在输入框值改变时执行校验validateOnBlurtrue是否在输入框失去焦点时执行校验validateOnTypefalse是否在用户输入过程中实时校验validationDelay500validateOnType为true时输入校验的延迟毫秒数scrollToErrortrue校验失败后是否滚动到第一个错误处这些开关可以在视图中通过配置ActiveForm::begin()的参数统一控制也可以针对单个字段通过field()返回的ActiveField对象单独控制非常适合按需优化表单交互体验。标签从哪来表单中每个字段的标签由field()方法根据模型的属性名自动生成。例如name属性会生成Name标签email属性会生成Email标签。其底层逻辑可参考 Model::generateAttributeLabel()把camelCase属性名转换为适合展示的单词形式你也可以重写 Model::attributeLabels() 显式指定更友好的标签。你可以在视图中使用如下代码自定义标签? $form-field($model, name)-label(您的姓名) ? ? $form-field($model, email)-label(您的邮箱) ?InfoYii 提供了大量类似的 widget 帮助开发者快速构建复杂、动态的视图。后续你还会学到编写一个新 widget 也非常容易——你可以把大量视图代码提炼成可复用的 widget简化未来视图的开发。扩展批量校验与 AJAX 校验除了常规流程ActiveForm还提供了两个静态校验辅助方法framework/widgets/ActiveForm.php专门用于简化 AJAX 校验场景ActiveForm::validate($model1, $model2, ...)校验一个或多个模型返回以“属性 HTML id”为索引的错误消息数组ActiveForm::validateMultiple($models)校验模型数组适用于表格输入tabular input场景错误消息索引形如[0]name、[1]email。典型的用法是在控制器动作里配合 AJAX 请求返回 JSON 错误$model new EntryForm(); $model-load(Yii::$app-request-post()); if (Yii::$app-request-isAjax) { Yii::$app-response-format Response::FORMAT_JSON; return ActiveForm::validate($model); } // ……处理非 AJAX 请求……小结在这一节指南中你已经接触到了 MVC 架构模式的每一个部分学会了创建模型类来表示用户数据并校验这些数据学会了如何从用户处获取数据、以及如何在浏览器中把数据展示回来。这类任务在开发应用时往往非常耗时但 Yii 提供了强大的 widget 让这一切变得异常简单。下一节将学习几乎每个应用都需要的数据库操作对应指南文档为 start-databases.md。【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址: https://gitcode.com/gh_mirrors/yi/yii2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表