企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
> 原文出处:https://jellybool.com/post/programming-with-yii2-exploring-mvc-forms-and-layouts 上一篇文章我们简单地实现了`Yii2`框架安装和`Hello World`,而在这一篇文章当中,我们会带着好奇之心去探索一下在Yii2中的几个重要的元素组成:`MVC`,`Forms`和`Layouts`。 本文的目标是创建一个小小的表单应用,就是实现一个简单的类似发微博的功能,但是我还不想牵扯到数据库那一块,因为其实数据库和表在Yii2框架之中其实还是有很多东西可以讲的,打算在下一篇的文章中会详细讲到。 ## MVC ![替代文字](https://box.kancloud.cn/2015-08-15_55cf2c8014f7c.png) 模型`(Model)`对于我个人的简单理解就是一个概念集合,在这个集合里面包含该概念集合的多种数据,比如一个`User`会有姓名,性别等多个属性,这个概念集合通常就是对于数据库的一张表(如果还没有对应的数据表,则可以看作是一个集合的属性);而每一个具体的实例概念就对应一条数据记录。比如在这一篇文章之中我们会创建一个`Status`模型,代表状态(来源于生活:发一条状态),这个Status会有两个重要的属性,`text`和`permissions`,`text`就是状态本身,`permissions`是状态的权限。 视图`(Views)`通过控制器想模型请求数据,并将数据以某种特定的版式展示给用户。 控制器`(Controller)`可以向`Model`和`Views`发送不同的指令,一般是向Model取数据,然后读取视图文件来渲染输出数据。 在Yii2的应用中,一般是这样的:某个URL指向某个控制器的特定`action`,然后控制器负责向特定的模型取数据,然后将数据分配给视图渲染输出。 在这里说一下我个人的观点,我觉得其实在`MVC`当中,可能应该做事最多的应该是`Model`,与之相迎合的是,`Controller`和`Views`则相对要轻一些,`Controller`负责协调`Model`和`Views`,Views负责展示数据。 在Yii2的项目当中,我们将`models`文件放在`/models/`目录之下,所以我们在这个文件夹之下创建`Status.php`: ~~~ <?php namespace app\models; use yii\base\Model; class Status extends Model { const PERMISSIONS_PRIVATE = 10; const PERMISSIONS_PUBLIC = 20; public $text; public $permissions; public function rules() { return [ [['text','permissions'], 'required'], ]; } public function getPermissions() { return array (self::PERMISSIONS_PRIVATE=>'Private',self::PERMISSIONS_PUBLIC=>'Public'); } public function getPermissionsLabel($permissions) { if ($permissions==self::PERMISSIONS_PUBLIC) { return 'Public'; } else { return 'Private'; } } } ~~~ 这里需要注意的是`rules()`这个方法,它会触发Yii自带的表单验证规则,比如这里就是`text`和`permissions`这两个表单输入框都不能为空,至于`getPermissions()`这个方法是为了在使用`dropdown`输入框的时候使用的。 `Status`模型创建好之后,我们就可以接着创建对应的控制器和方法。在平时的开发中我习惯是为每一个模型都创建一个对应的控制器,里面一般都是包含几个最常见的方法:`index`, `create`, `store`, `update`, `delete`等。这里我创建一个`StatusController.php`,这个文件应该是位于`/controllers/`文件夹当中,而我们希望实现一个发表状态的功能,我们必须需要一个`create`操作方法,比如我们的目的是:在用户访问`http://localhost:8999/status/create`的时候,我们可以展示创建一条状态的页面给用户。 ~~~ <?php namespace app\controllers; use Yii; use yii\web\Controller; use app\models\Status; class StatusController extends Controller { public function actionCreate() { $model = new Status; if ($model->load(Yii::$app->request->post()) && $model->validate()) { // $model 有post数据时直接展示 return $this->render('view', ['model' => $model]); } else { // 没有数据的时候,直接渲染create视图 return $this->render('create', ['model' => $model]); } } } ~~~ 首先,根据URL的规则,我们创建了一个`actionCreate()`方法,在这个方法里,我们通过条件判断来确定展示某个特定的视图。 创建好控制器和方法之后,我们就可以走到下一步了:创建视图。在Yii2中,视图文件的存放位置跟控制器的名字是息息相关的,比如上面我们创建了一个`StatusController`,我们现在首先需要在`views/`创建一个`status/`文件夹,然后在这个文件夹里创建各个跟`StatusController`相关的视图文件,比如上面`actionCreate()`中`return $this->render()`两个视图:`view.php`和`create.php` ## Forms 首先,我们需要一个`Create`视图来展示我们创建`Status`的表单`(create.php)`: ~~~ <?php use yii\helpers\Html; use yii\widgets\ActiveForm; use app\models\Status; ?> <?php $form = ActiveForm::begin();?> <?= $form->field($model, 'text')->textArea(['rows' => '4'])->label('Status Update'); ?> <?= $form->field($model, 'permissions')->dropDownList($model->getPermissions(), ['prompt'=>'- Choose Your Permissions -']) ?> <div class="form-group"> <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?> </div> <?php ActiveForm::end(); ?> ~~~ 在我们平时开发web应用的时候,表单几乎总是每时每刻都得存在,只要是需要收集信息的地方就需要表单。而Yii2在对表单支持这方面做得非常不错,就如你看到的一样,上面的[Yii2 ActiveForm](http://www.yiiframework.com/doc-2.0/yii-widgets-activeform.html)就是Yii2内置的用来帮助我们生成表单的小组件,这里需要注意的是`dropDownList`这个输入框式怎么实现的,它直接使用了`getPermissions()`,这个方法正好返回了一个我们需要的数组。 这时候访问:`http://localhost:8999/status/create` 就可以看到上面创建的表单了: ![替代文字](https://box.kancloud.cn/2015-08-15_55cf2c80743e1.png) 至于为什么就自动排版好了,不用我们写css,那是因为Yii2默认会给我们加载Bootstrap的css文件,所以我们在使用的时候直接指定类名就OK了。而且很明显地,我们可以看到,一旦输入框在失去焦点的时候,如果里面没有输入任何内容,每个输入框就会有相应的错误提示,用户体验很不错。这个其实是得益于我们在Status模型中声明的`rules()`方法,Yii2会根据指定的规则通过js在前端给出相应的验证。 然后我们尝试填入一些内容,你就会看到输入框的变化了: ![替代文字](https://box.kancloud.cn/2015-08-15_55cf2c80c1d87.png) 点击`Submit` 按钮,表单会提交到`StatusController`的`actionCreate()`方法,一旦有`post`数据传过来,就会渲染`view.php`视图: ![替代文字](https://box.kancloud.cn/2015-08-15_55cf2c811848f.png)到这里,其实我们就走通整个MVC的过程,并且在这个过程中,我们顺带说了一下Forms的知识点。 ## Layouts 为什么要说Layouts呢?因为Layouts在Yii中其实可以看作是视图中经常重复用到的部分,比如一个HTML文件的`header`,`navigation bar` 和`footer`等,这些都是几乎是在每一个视图文件中都会用到,所以Yii采取了一种一劳永逸的方法来管理这些共用的部分:Layouts就应运而生。这样你就不用在每一个`view`文件中重复不必要的代码了,而且又特别好管理。 Yii允许你创建多个Layouts,不过我貌似还没遇到那样的使用场景,所以还是无法给出有实证的说法,不管怎么说,一个Layouts就基本够用了。 最后,我们借着Layouts的东风来看看我们怎么修改一下Yii2的默认导航栏:添加一个新的导航。 在上一节我就提到过`views\layouts\main.php`这个文件,里面的具体结构你可以直打开来看看,我们这里改动的是`Nav::widget`这部分: ~~~ echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'items' => [ ['label' => 'Home', 'url' => ['/site/index']], [ 'label' => 'Status', 'items' => [ ['label' => 'Create', 'url' => ['/status/create']], ], ], ['label' => 'About', 'url' => ['/site/about']], ['label' => 'Contact', 'url' => ['/site/contact']], Yii::$app->user->isGuest ? ['label' => 'Login', 'url' => ['/site/login']] : ['label' => 'Logout (' . Yii::$app->user->identity->username . ')', 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post']], ], ]); ~~~ 我们在本来的基础之上添加了下面这个内容: ~~~ [ 'label' => 'Status', 'items' => [ ['label' => 'Create', 'url' => ['/status/create']], ], ], ~~~ 这样之后,刷新一下页面,你就可以看到我们的导航变化了。而且很神奇的是:这里还实现了`dropdown menu`的功能,这个其实就是使用`Bootstrap`的`dropdown menu`来实现的。 ![替代文字](https://box.kancloud.cn/2015-08-15_55cf2c8161adb.png) 嗯,这篇文章貌似讲得差不多了,至少我不知道还改讲些什么了,接下来的文章我会尝试讲讲Yii2的数据库相关的内容,先睡觉。