二:MVC,Forms和Layouts

2018-02-24 15:58 更新

原文出處:https://jellybool.com/post/programming-with-yii2-exploring-mvc-forms-and-layouts

上一篇文章我們簡單地實(shí)現(xiàn)了Yii2框架安裝和Hello World,而在這一篇文章當(dāng)中,我們會帶著好奇之心去探索一下在Yii2中的幾個(gè)重要的元素組成:MVC,FormsLayouts。

本文的目標(biāo)是創(chuàng)建一個(gè)小小的表單應(yīng)用,就是實(shí)現(xiàn)一個(gè)簡單的類似發(fā)微博的功能,但是我還不想牽扯到數(shù)據(jù)庫那一塊,因?yàn)槠鋵?shí)數(shù)據(jù)庫和表在Yii2框架之中其實(shí)還是有很多東西可以講的,打算在下一篇的文章中會詳細(xì)講到。

MVC

替代文字

模型(Model)對于我個(gè)人的簡單理解就是一個(gè)概念集合,在這個(gè)集合里面包含該概念集合的多種數(shù)據(jù),比如一個(gè)User會有姓名,性別等多個(gè)屬性,這個(gè)概念集合通常就是對于數(shù)據(jù)庫的一張表(如果還沒有對應(yīng)的數(shù)據(jù)表,則可以看作是一個(gè)集合的屬性);而每一個(gè)具體的實(shí)例概念就對應(yīng)一條數(shù)據(jù)記錄。比如在這一篇文章之中我們會創(chuàng)建一個(gè)Status模型,代表狀態(tài)(來源于生活:發(fā)一條狀態(tài)),這個(gè)Status會有兩個(gè)重要的屬性,textpermissionstext就是狀態(tài)本身,permissions是狀態(tài)的權(quán)限。

視圖(Views)通過控制器想模型請求數(shù)據(jù),并將數(shù)據(jù)以某種特定的版式展示給用戶。

控制器(Controller)可以向ModelViews發(fā)送不同的指令,一般是向Model取數(shù)據(jù),然后讀取視圖文件來渲染輸出數(shù)據(jù)。

在Yii2的應(yīng)用中,一般是這樣的:某個(gè)URL指向某個(gè)控制器的特定action,然后控制器負(fù)責(zé)向特定的模型取數(shù)據(jù),然后將數(shù)據(jù)分配給視圖渲染輸出。

在這里說一下我個(gè)人的觀點(diǎn),我覺得其實(shí)在MVC當(dāng)中,可能應(yīng)該做事最多的應(yīng)該是Model,與之相迎合的是,ControllerViews則相對要輕一些,Controller負(fù)責(zé)協(xié)調(diào)ModelViews,Views負(fù)責(zé)展示數(shù)據(jù)。

在Yii2的項(xiàng)目當(dāng)中,我們將models文件放在/models/目錄之下,所以我們在這個(gè)文件夾之下創(chuàng)建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()這個(gè)方法,它會觸發(fā)Yii自帶的表單驗(yàn)證規(guī)則,比如這里就是textpermissions這兩個(gè)表單輸入框都不能為空,至于getPermissions()這個(gè)方法是為了在使用dropdown輸入框的時(shí)候使用的。

Status模型創(chuàng)建好之后,我們就可以接著創(chuàng)建對應(yīng)的控制器和方法。在平時(shí)的開發(fā)中我習(xí)慣是為每一個(gè)模型都創(chuàng)建一個(gè)對應(yīng)的控制器,里面一般都是包含幾個(gè)最常見的方法:index,?create,?store,?update,?delete等。這里我創(chuàng)建一個(gè)StatusController.php,這個(gè)文件應(yīng)該是位于/controllers/文件夾當(dāng)中,而我們希望實(shí)現(xiàn)一個(gè)發(fā)表狀態(tài)的功能,我們必須需要一個(gè)create操作方法,比如我們的目的是:在用戶訪問http://localhost:8999/status/create的時(shí)候,我們可以展示創(chuàng)建一條狀態(tài)的頁面給用戶。

<?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數(shù)據(jù)時(shí)直接展示
            return $this->render('view', ['model' => $model]);
        } else {
            // 沒有數(shù)據(jù)的時(shí)候,直接渲染create視圖
            return $this->render('create', ['model' => $model]);
        }
    }
}

首先,根據(jù)URL的規(guī)則,我們創(chuàng)建了一個(gè)actionCreate()方法,在這個(gè)方法里,我們通過條件判斷來確定展示某個(gè)特定的視圖。

創(chuàng)建好控制器和方法之后,我們就可以走到下一步了:創(chuàng)建視圖。在Yii2中,視圖文件的存放位置跟控制器的名字是息息相關(guān)的,比如上面我們創(chuàng)建了一個(gè)StatusController,我們現(xiàn)在首先需要在views/創(chuàng)建一個(gè)status/文件夾,然后在這個(gè)文件夾里創(chuàng)建各個(gè)跟StatusController相關(guān)的視圖文件,比如上面actionCreate()return $this->render()兩個(gè)視圖:view.phpcreate.php

Forms

首先,我們需要一個(gè)Create視圖來展示我們創(chuàng)建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(); ?>

在我們平時(shí)開發(fā)web應(yīng)用的時(shí)候,表單幾乎總是每時(shí)每刻都得存在,只要是需要收集信息的地方就需要表單。而Yii2在對表單支持這方面做得非常不錯,就如你看到的一樣,上面的Yii2 ActiveForm就是Yii2內(nèi)置的用來幫助我們生成表單的小組件,這里需要注意的是dropDownList這個(gè)輸入框式怎么實(shí)現(xiàn)的,它直接使用了getPermissions(),這個(gè)方法正好返回了一個(gè)我們需要的數(shù)組。

這時(shí)候訪問:http://localhost:8999/status/create?就可以看到上面創(chuàng)建的表單了:

替代文字

至于為什么就自動排版好了,不用我們寫css,那是因?yàn)閅ii2默認(rèn)會給我們加載Bootstrap的css文件,所以我們在使用的時(shí)候直接指定類名就OK了。而且很明顯地,我們可以看到,一旦輸入框在失去焦點(diǎn)的時(shí)候,如果里面沒有輸入任何內(nèi)容,每個(gè)輸入框就會有相應(yīng)的錯誤提示,用戶體驗(yàn)很不錯。這個(gè)其實(shí)是得益于我們在Status模型中聲明的rules()方法,Yii2會根據(jù)指定的規(guī)則通過js在前端給出相應(yīng)的驗(yàn)證。

然后我們嘗試填入一些內(nèi)容,你就會看到輸入框的變化了:

替代文字

點(diǎn)擊Submit?按鈕,表單會提交到StatusControlleractionCreate()方法,一旦有post數(shù)據(jù)傳過來,就會渲染view.php視圖:

替代文字到這里,其實(shí)我們就走通整個(gè)MVC的過程,并且在這個(gè)過程中,我們順帶說了一下Forms的知識點(diǎn)。

Layouts

為什么要說Layouts呢?因?yàn)長ayouts在Yii中其實(shí)可以看作是視圖中經(jīng)常重復(fù)用到的部分,比如一個(gè)HTML文件的headernavigation bar?和footer等,這些都是幾乎是在每一個(gè)視圖文件中都會用到,所以Yii采取了一種一勞永逸的方法來管理這些共用的部分:Layouts就應(yīng)運(yùn)而生。這樣你就不用在每一個(gè)view文件中重復(fù)不必要的代碼了,而且又特別好管理。

Yii允許你創(chuàng)建多個(gè)Layouts,不過我貌似還沒遇到那樣的使用場景,所以還是無法給出有實(shí)證的說法,不管怎么說,一個(gè)Layouts就基本夠用了。

最后,我們借著Layouts的東風(fēng)來看看我們怎么修改一下Yii2的默認(rèn)導(dǎo)航欄:添加一個(gè)新的導(dǎo)航。

在上一節(jié)我就提到過views\layouts\main.php這個(gè)文件,里面的具體結(jié)構(gòu)你可以直打開來看看,我們這里改動的是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']],
                ],
            ]);

我們在本來的基礎(chǔ)之上添加了下面這個(gè)內(nèi)容:

 [
    'label' => 'Status',
    'items' => [
        ['label' => 'Create', 'url' => ['/status/create']],
    ],
],

這樣之后,刷新一下頁面,你就可以看到我們的導(dǎo)航變化了。而且很神奇的是:這里還實(shí)現(xiàn)了dropdown menu的功能,這個(gè)其實(shí)就是使用Bootstrapdropdown menu來實(shí)現(xiàn)的。

替代文字

嗯,這篇文章貌似講得差不多了,至少我不知道還改講些什么了,接下來的文章我會嘗試講講Yii2的數(shù)據(jù)庫相關(guān)的內(nèi)容,先睡覺。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號