Yii2系列教程二:MVC,Forms 和 Layouts

JellyBool

JellyBool

上一篇文章我们简单地实现了Yii2框架安装和Hello World,而在这一篇文章当中,我们会带着好奇之心去探索一下在Yii2中的几个重要的元素组成:
MVCFormsLayouts

本文的目标是创建一个小小的表单应用,就是实现一个简单的类似发微博的功能,但是我还不想牵扯到数据库那一块,因为其实数据库和表在Yii2框架之中其实还是有很多东西可以讲的,打算在下一篇的文章中会详细讲到。

MVC

替代文字

模型(Model)对于我个人的简单理解就是一个概念集合,在这个集合里面包含该概念集合的多种数据,比如一个User会有姓名,性别等多个属性,这个概念集合通常就是对于数据库的一张表(如果还没有对应的数据表,则可以看作是一个集合的属性);而每一个具体的实例概念就对应一条数据记录。比如在这一篇文章之中我们会创建一个Status模型,代表状态(来源于生活:发一条状态),这个Status会有两个重要的属性,textpermissionstext就是状态本身,permissions是状态的权限。

视图(Views)通过控制器想模型请求数据,并将数据以某种特定的版式展示给用户。

控制器(Controller)可以向ModelViews发送不同的指令,一般是向Model取数据,然后读取视图文件来渲染输出数据。

在Yii2的应用中,一般是这样的:某个URL指向某个控制器的特定action,然后控制器负责向特定的模型取数据,然后将数据分配给视图渲染输出。

在这里说一下我个人的观点,我觉得其实在MVC当中,可能应该做事最多的应该是Model,与之相迎合的是,ControllerViews则相对要轻一些,Controller负责协调ModelViews,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自带的表单验证规则,比如这里就是textpermissions这两个表单输入框都不能为空,至于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.phpcreate.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就是Yii2内置的用来帮助我们生成表单的小组件,这里需要注意的是dropDownList这个输入框式怎么实现的,它直接使用了getPermissions(),这个方法正好返回了一个我们需要的数组。

这时候访问:http://localhost:8999/status/create 就可以看到上面创建的表单了:

替代文字

至于为什么就自动排版好了,不用我们写css,那是因为Yii2默认会给我们加载Bootstrap的css文件,所以我们在使用的时候直接指定类名就OK了。而且很明显地,我们可以看到,一旦输入框在失去焦点的时候,如果里面没有输入任何内容,每个输入框就会有相应的错误提示,用户体验很不错。这个其实是得益于我们在Status模型中声明的rules()方法,Yii2会根据指定的规则通过js在前端给出相应的验证。

然后我们尝试填入一些内容,你就会看到输入框的变化了:

替代文字

点击Submit 按钮,表单会提交到StatusControlleractionCreate()方法,一旦有post数据传过来,就会渲染view.php视图:

替代文字

到这里,其实我们就走通整个MVC的过程,并且在这个过程中,我们顺带说了一下Forms的知识点。

Layouts

为什么要说Layouts呢?因为Layouts在Yii中其实可以看作是视图中经常重复用到的部分,比如一个HTML文件的headernavigation barfooter等,这些都是几乎是在每一个视图文件中都会用到,所以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的功能,这个其实就是使用Bootstrapdropdown menu来实现的。

替代文字

嗯,这篇文章貌似讲得差不多了,至少我不知道还改讲些什么了,接下来的文章我会尝试讲讲Yii2的数据库相关的内容,先睡觉。

源码会放在 Github:https://github.com/JellyBool/helloYii

Happy Hacking

本文由 JellyBool 创作, 转载和引用遵循 署名-非商业性使用 2.5 中国大陆 进行许可。

共有 13 条评论

Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
Anonymous
修改的评论也不能少于六个字哦!
frozen47
修改的评论也不能少于六个字哦!
JellyBool 回复 frozen47
修改的评论也不能少于六个字哦!
zhangda
修改的评论也不能少于六个字哦!
Flourishing
修改的评论也不能少于六个字哦!