中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
【Laravel系統(tǒng)3.3】控制器與表單驗(yàn)證

控制器與表單驗(yàn)證

在請(qǐng)求過(guò)程中,控制器往往是我們?cè)谧鰳I(yè)務(wù)開(kāi)發(fā)時(shí)繞不過(guò)的一環(huán)。從 MVC 理論的成熟到現(xiàn)代化的開(kāi)發(fā)過(guò)程中,控制器一直扮演著重要的角色。可以說(shuō),我們可以不要前端(只做接口),可以不要模型(直接讀取數(shù)據(jù)),但控制器卻是必不可少的。當(dāng)然,在正式的 MVC 模型中,視圖是可以直接和模型交互的,由此,也引申出了 MVP 模型,其中的這個(gè) P 就是強(qiáng)化控制器的作用,讓模型和視圖解耦。其實(shí)我們大部分正規(guī)的開(kāi)發(fā),都是基于這個(gè) MVP 的,很少會(huì)直接讓視圖和模型去交互。

所以說(shuō),只要是遵循 MVC 模式的框架,控制器都是最核心的部分。在傳統(tǒng)的框架中,我們的控制器往往也充當(dāng)路由的功能,比如 TP3.2 系列,定義控制器名稱就是我們要請(qǐng)求的 URL 路徑名稱。之前在講路由的時(shí)候也說(shuō)過(guò)這個(gè)問(wèn)題,但是在 Laravel 中,實(shí)現(xiàn)了路由和控制器的解耦,所以我們的控制器是可以隨意定義并且命名的,直接通過(guò)路由來(lái)進(jìn)行綁定。

基礎(chǔ)控制器

我們可以通過(guò)命令行來(lái)創(chuàng)建一個(gè)控制器,當(dāng)然,您也可以直接自己創(chuàng)建一個(gè)控制器類。

php artisan make:controller TestController

如果是自己創(chuàng)建的控制器類,需要繼承 app/Http/Controllers/Controllers 這個(gè)基類。如果不繼承這個(gè)基類,也就無(wú)法使用框架的能力,比如說(shuō)中間件之類的功能。我們這里測(cè)試的是直接通過(guò)命令行創(chuàng)建的,看看它的代碼。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
    //
}

非常簡(jiǎn)單,也沒(méi)有什么別的特別的地方,接下來(lái),我們就可以在這個(gè)控制器中寫(xiě)需要的控制方法了。

public function test(){
}

最簡(jiǎn)單的一個(gè)控制器就這樣實(shí)現(xiàn)了,接下來(lái)要如何訪問(wèn)它呢?當(dāng)然就是去配下路由就好啦。

Route::get('test/test''App\Http\Controllers\TestController@test');
// http://laravel8/test/test

這時(shí)訪問(wèn)的結(jié)果是一個(gè)空白的頁(yè)面,因?yàn)樵谶@個(gè)控制器方法中我們什么都沒(méi)有做,也沒(méi)有任何的返回,所以頁(yè)面上沒(méi)有任何的顯示。但其實(shí),Laravel 中還是為我們做了一些事情。比如返回 HTTP 的頭信息,包括響應(yīng)狀態(tài)碼、基礎(chǔ)的頭信息之類的內(nèi)容。

另外,我們還可以定義一個(gè)單行為控制器,這是什么意思呢?其實(shí)就是一個(gè)控制器里面只有一個(gè)方法,這樣的一個(gè)控制器就不需要在路由中指定控制方法。


namespace App\Http\Controllers;

use Illuminate\Http\Request;

class Test2Controller extends Controller
{
    //
    public function __invoke()
    
{
        echo 'single action controller';
    }
}

注意到單行為控制器中使用的這個(gè) __invoke() 魔術(shù)方法了嗎?不記得的小伙伴可以回到我們最早的文章中 PHP的那些魔術(shù)方法(二)https://mp.weixin.qq.com/s/8WgQ3eVYKjGaEd2CwnB0Ww 復(fù)習(xí)一下,在 Laravel 中,我們會(huì)用到很多之前學(xué)習(xí)過(guò)的基礎(chǔ)知識(shí)。所以說(shuō),框架的學(xué)習(xí)其實(shí)就是一次對(duì)于基礎(chǔ)知識(shí)的全面鞏固復(fù)習(xí),同時(shí)也需要我們對(duì)于 PHP 的基礎(chǔ)知識(shí)有牢固的掌握。

接下來(lái)就是路由和我們的測(cè)試了。

Route::get('test/test2''App\Http\Controllers\Test2Controller');
// http://laravel8/test/test2
// single action controller

參數(shù)接收

對(duì)于請(qǐng)求參數(shù)的接收來(lái)說(shuō),在控制器中和在路由的回調(diào)函數(shù)中接收參數(shù)沒(méi)有什么區(qū)別。都可以通過(guò)依賴注入的方式獲取到指定的參數(shù)。

// 控制器
public function test2(Request $request, $id){
    var_dump($request === \request()); // bool(true)
    return 'test2: ' . $id . ', ' . $request->input('name''') . ', ' . \request()->input('sex''');
}

// 路由
Route::get('test/test2/{id}''App\Http\Controllers\TestController@test2');
// http://laravel8/test/test2/2?name=Bob&sex=male

在這里,我們使用了兩種接收 Request 的方式。一個(gè)是使用依賴注入的 request 對(duì)象,一個(gè)是使用 request() 方法返回的 Request 對(duì)象。兩種方式在本質(zhì)上沒(méi)有什么區(qū)別,在代碼中我們也打印了這兩種方式的對(duì)象是否是全等的。只不過(guò)一個(gè)是通過(guò)依賴注入到當(dāng)前方法的參數(shù)中,而另一個(gè) request() 方法則是通過(guò)全局的服務(wù)容器來(lái)獲取 Request 對(duì)象的。關(guān)于依賴注入和服務(wù)容器的內(nèi)容都會(huì)在后面核心架構(gòu)相關(guān)的文章中學(xué)習(xí)到。

資源型控制器

在上篇路由的文章中就講過(guò),我們可以定制一個(gè)資源型的路由,對(duì)應(yīng)的就是一個(gè)資源型的控制器,這倆貨是相輔相成的。那么什么是資源型呢?其實(shí)就是標(biāo)準(zhǔn)的 RESTful 類型的一套請(qǐng)求鏈接。對(duì)于 REST 有疑問(wèn)的同學(xué)可以自行查閱相關(guān)的文檔,在這里就不多說(shuō)了,畢竟我們的主旨還是在于 Laravel 框架如何實(shí)現(xiàn)這些功能。

我們可以直接使用命令:

php artisan make:controller ResourceTestController --resource

創(chuàng)建一個(gè)資源型的控制器,直接來(lái)看看代碼,這個(gè)控制器已經(jīng)為我們準(zhǔn)備好了一系列的方法。


namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ResourceTestController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */

    public function index()
    
{
        //
        return 'get列表';
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */

    public function create()
    
{
        //
        return 'post添加數(shù)據(jù)-顯示表單';
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */

    public function store(Request $request)
    
{
        //
        return 'post保存數(shù)據(jù)';
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */

    public function show($id)
    
{
        //
        return 'get單條數(shù)據(jù)';
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */

    public function edit($id)
    
{
        //
        return 'get修改數(shù)據(jù)-顯示表單';
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */

    public function update(Request $request, $id)
    
{
        //
        return 'put/patch修改數(shù)據(jù)';
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */

    public function destroy($id)
    
{
        //
        return 'delete刪除數(shù)據(jù)';
    }
}

當(dāng)定義完成資源型控制器之后,就可以在路由上非常方便地配置這個(gè)資源的路由,一行就搞定。

Route::resource('test/resource''App\Http\Controllers\ResourceTestController');

剩下的呢?Laravel 框架會(huì)自動(dòng)幫我們配置以下這些路由,大家只要按照規(guī)則訪問(wèn)就好了。

請(qǐng)求方式鏈接說(shuō)明
GET/test/resource索引/列表
GET/test/resource/create創(chuàng)建(顯示表單)
POST/test/resource/store保存你創(chuàng)建的數(shù)據(jù)
GET/test/resource/{id}顯示對(duì)應(yīng)id的內(nèi)容
GET/test/resource/{id}/edit編輯(顯示表單)
PUT/PATCH/test/resource/{id}保存你編輯的數(shù)據(jù)
DELETE/test/resource/{id}刪除

是不是感覺(jué)很高大上,確實(shí)如此,而且這一套路由也是非常符合 RESTFul 規(guī)范的,并且最主要的是,這一套路由不需要我們?cè)偈謩?dòng)去寫(xiě)了,它直接就幫我們定義好了。在測(cè)試的時(shí)候直接訪問(wèn)它們就可以了。

控制器的調(diào)用

對(duì)于路由到控制器的調(diào)用,還記得上篇文章中學(xué)習(xí)過(guò)的 laravel/framework/src/Illuminate/Routing/Route.php 這個(gè)文件中的 run() 方法嗎?如果我們定義的路由是指定的控制器,那么它就會(huì)走到 runController() 。在這個(gè) runController() 方法中,會(huì)指定分發(fā)到的控制器,其實(shí)也是從一個(gè)控制器的集合中查找指定的控制器信息。

protected function runController()
{
    return $this->controllerDispatcher()->dispatch(
        $this$this->getController(), $this->getControllerMethod()
    );
}

getController() 和 getControllerMethod() 都是獲取的當(dāng)前文件中的 action 里面的 uses 字段里面的內(nèi)容,它保存的就是我們?cè)诼酚芍刑顚?xiě)的控制器信息。

$this->action->uses = "App\Http\Controllers\ResourceTestController@index";

在我們實(shí)例化所有路由時(shí),都會(huì)創(chuàng)建一個(gè) Route 對(duì)象。傳遞過(guò)來(lái)的數(shù)據(jù)就是我們?cè)诼酚晌募卸x的數(shù)據(jù),也就是調(diào) get()/post() 這些方法的時(shí)候添加的數(shù)據(jù)。而第二個(gè)參數(shù),也就是我們指定的回調(diào)或者控制器參數(shù)就會(huì)充當(dāng) action 參數(shù),交給 Route.php 中的 parseAction() 方法進(jìn)行處理,處理之后的結(jié)果就會(huì)保存在當(dāng)前這個(gè) Route 對(duì)象的 action 屬性里面。

整體來(lái)說(shuō),控制器的調(diào)用和回調(diào)路由的調(diào)用本質(zhì)上是沒(méi)有什么區(qū)別的。

快速表單驗(yàn)證

在日常的業(yè)務(wù)開(kāi)發(fā)中,出于安全以及數(shù)據(jù)格式驗(yàn)證的考慮,我們通常會(huì)對(duì)接收到的參數(shù)進(jìn)行驗(yàn)證過(guò)濾,一般情況下,都是通過(guò)一個(gè)個(gè)的 if...else 來(lái)進(jìn)行這項(xiàng)工作。既然說(shuō)到這里了,那么在 Laravel 框架中,其實(shí)也是有對(duì)應(yīng)的表單驗(yàn)證的功能的,可以方便地讓我們進(jìn)行表單參數(shù)的驗(yàn)證。

首先我們需要定義一個(gè)頁(yè)面,這個(gè)頁(yè)面用于提交表單,只需要簡(jiǎn)單的定義一個(gè)模板頁(yè)就可以。

// ValidateController
public function create(){
    return view("validate.create");
}

// validate/create.blade.php
@if ($errors->any())
<div class="alert alert-danger">
    <ul>
        @foreach ($errors->all() as $error)
        <li>
{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif

<h2>表單驗(yàn)證</h2>
<form method="post" action="http://laravel8/validate/store">
    <label>標(biāo)題</label><input name="title"/><br/>
    <label>作者</label><input name="author"/><br/>
    <label>年齡</label><input name="age"/><br/>
    <label>內(nèi)容</label><input name="body"/><br/>
    <input type="hidden" name="_token" value="{{ csrf_token() }}"/>
    <button type="submit">提交</button>
</form>

// route/web.php
Route::get('validate/create''App\Http\Controllers\ValidateController@create');

這個(gè)就相當(dāng)于是一個(gè)要提交數(shù)據(jù)的靜態(tài)表單頁(yè)面,我們沒(méi)有做別的任何操作。其中在模板文件中,csrf_token() 這個(gè)東西是用于 CSRF 攻擊防御的,這個(gè)在后面如果學(xué)習(xí)到了相關(guān)的內(nèi)容再說(shuō),大家也可以自行查閱一下相關(guān)的資料。如果沒(méi)有這個(gè) _token 的話,那么表單提交之后就會(huì)報(bào) 419 的錯(cuò)誤。

繼續(xù)寫(xiě)我們的這個(gè) store 接收頁(yè)面。來(lái)看看我們?nèi)绾悟?yàn)證這個(gè)表單里面提交的數(shù)據(jù)信息。

// ValidateController
public function store(Request $request){
    $validatedData = $request->validate([
        'title'=>"required|max:20",
        'author'=>['required','min:2''max:20'],
        'age'=>"numeric",
        'body'=>"required"
    ]);
}

// route/web.php
Route::post('validate/store''App\Http\Controllers\ValidateController@store');

接下來(lái)就是去測(cè)試一下,在表單頁(yè)面,我們什么都不填,直接提交,就可以看到頁(yè)面上輸出了如下的錯(cuò)誤提示信息。


這個(gè)錯(cuò)誤信息正是在模板中的

@if ($errors->any())
<div class="alert alert-danger">
    <ul>
        @foreach ($errors->all() as $error)
        <li>
{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif

這段代碼輸出的。而驗(yàn)證的規(guī)則,則是在 request 的 validate() 方法中配置的這些。從英文可以看出,我們讓 title 這個(gè)字段 required(必填)、max:20(最大不超過(guò)20個(gè)),讓 age 這個(gè)字段的內(nèi)容 numeric(只能是數(shù)字)。當(dāng)然,還有很多可配置的內(nèi)容,在這里就不一一列舉了,大家可以自己查閱相關(guān)的文檔,畢竟這些東西都是文檔中現(xiàn)成的,學(xué)習(xí)這些配置參數(shù)的使用也不是我們這個(gè)系列文章的重點(diǎn)。

從這段功能的測(cè)試代碼中,我們可以看出幾個(gè)問(wèn)題。其一,這個(gè)驗(yàn)證是直接通過(guò)請(qǐng)求對(duì)象實(shí)現(xiàn)的,也就是這個(gè) Request 對(duì)象中的方法,而且我們?cè)诳刂破髦袥](méi)有返回 Response ,也就是說(shuō),這一切框架都自動(dòng)為我們處理了。其二,錯(cuò)誤信息會(huì)直接傳到模板的一個(gè) $errors 變量中,這個(gè)也不是我們控制的,也是框架自動(dòng)處理的,這個(gè)地方也是我們平常在寫(xiě)業(yè)務(wù)代碼的時(shí)候需要注意的,因?yàn)檫@個(gè)變量名是寫(xiě)死在框架內(nèi)部的,不能修改的。其三,沒(méi)有地方設(shè)置錯(cuò)誤信息的內(nèi)容,比如說(shuō)我們要顯示中文的錯(cuò)誤信息。

太智能太自動(dòng)的東西有好處,但也有很多的限制,比如這個(gè)第三點(diǎn),如果需要顯示中文的錯(cuò)誤信息的話,我們需要去下載或者自己配置一個(gè) resource/lang 下的語(yǔ)言包,并且修改框架配置中的 lang 為對(duì)應(yīng)的語(yǔ)言包。不過(guò),我們有別的辦法來(lái)解決,那就是我們自己配置,手動(dòng)驗(yàn)證。

手動(dòng)驗(yàn)證

說(shuō)實(shí)話,上面的自動(dòng)表單驗(yàn)證平常還真沒(méi)用過(guò)。平常用得最多的反而是這個(gè)自定義的手動(dòng)驗(yàn)證,說(shuō)是手動(dòng)驗(yàn)證,其實(shí)大部分也是已經(jīng)框架提供好的內(nèi)容,我們只需要簡(jiǎn)單的配置就可以了。

public function store2(Request $request){
    $validator = Validator::make($request->all(), [
        'title'=>"required|max:20",
        'author'=>['required','min:2''max:20'],
        'age'=>"numeric",
        'body'=>"required"
    ], [
        'title.required'=>'請(qǐng)?zhí)顚?xiě)標(biāo)題',
        'title.max'=>'標(biāo)題最大不超過(guò)20個(gè)字符',
        'author.required'=>'請(qǐng)?zhí)顚?xiě)作者',
        'author.min'=>'作者最少填寫(xiě)2個(gè)字符',
        'author.max'=>'作者最大不超過(guò)20個(gè)字符',
        'age.numeric'=>'年齡必須是數(shù)字',
        'body.required'=>'內(nèi)容必填'
    ]);

    if($validator->fails()){
        return redirect('validate/create')
            ->withErrors($validator)
            ->withInput();
    }
}

在這個(gè)控制器中,我們使用的是 Validator 這個(gè)門(mén)面類 make() 出來(lái)的一個(gè)驗(yàn)證器。它的第一個(gè)參數(shù)我們傳遞的是所有的請(qǐng)求數(shù)據(jù),當(dāng)然,也可以自己傳遞一個(gè)數(shù)組進(jìn)來(lái)進(jìn)行驗(yàn)證。第二個(gè)參數(shù)就是和上面一樣的驗(yàn)證配置信息。不同的,它的第三個(gè)參數(shù)是我們可以自定義的驗(yàn)證提示信息。有了這個(gè)參數(shù),返回的提示需要什么樣的內(nèi)容就方便了很多。

最后,還有一處不同的是,這個(gè) Validator 對(duì)象不是用得請(qǐng)求 Request 的方法,所以它不會(huì)自動(dòng)返回,需要自己構(gòu)造 Response ,在這里,我們跳轉(zhuǎn)回了原來(lái)的頁(yè)面,并且將錯(cuò)誤信息通過(guò) withErrors() 添加到了模板的 \$errors 變量中。進(jìn)入 withError() 方法,我們可以看到 $errors 是保存在 session 的 flash() 中,這個(gè)我們后面講 session 的時(shí)候再說(shuō)。

// laravel/framework/src/Illuminate/Http/RedirectResponse.php
public function withErrors($provider, $key = 'default')
{
    $value = $this->parseErrors($provider);

    $errors = $this->session->get('errors'new ViewErrorBag);

    if (! $errors instanceof ViewErrorBag) {
        $errors = new ViewErrorBag;
    }

    $this->session->flash(
        'errors', $errors->put($key, $value)
    );

    return $this;
}

數(shù)據(jù)驗(yàn)證的源碼處理

不管是請(qǐng)求對(duì)象的驗(yàn)證函數(shù),還是我們通過(guò)門(mén)面 make() 后獲得的驗(yàn)證對(duì)象,它的核心都是 laravel/framework/src/Illuminate/Validation/Validator.php 這個(gè)文件中的 Validator 對(duì)象。在初始化的時(shí)候,會(huì)將數(shù)據(jù) data 、 規(guī)則 initialRules 、提示消息 customMessages 存放到這個(gè)對(duì)象的相關(guān)變量中,然后通過(guò)對(duì)象里面的 validateAttribute() 方法進(jìn)行參數(shù)和規(guī)則的匹配,并通過(guò) addFailure() 方法匹配對(duì)應(yīng)的提示消息信息,最后將這些信息放在 messages 屬性中。上面 withErrors() 的代碼中的 parseErrors() 最終的調(diào)用其實(shí)就是走到了 Validator 對(duì)象的 validateAttribute() 這個(gè)方法中。

基本上整個(gè)處理過(guò)程都是在這個(gè) Validator 對(duì)象里面,所以這里我也就不貼代碼了,大家自己調(diào)試一下。

總結(jié)

這篇文章的內(nèi)容不少吧,我們學(xué)習(xí)了控制器和驗(yàn)證器相關(guān)的內(nèi)容,之所以把這兩個(gè)放在一起,也是因?yàn)轵?yàn)證這個(gè)功能一般都會(huì)在控制器的最開(kāi)始使用。當(dāng)然,我們?cè)谥v數(shù)據(jù)庫(kù)模型的時(shí)候,還有數(shù)據(jù)庫(kù)驗(yàn)證相關(guān)的內(nèi)容,和這邊又不太一樣了,這個(gè)我們等學(xué)習(xí)到的時(shí)候再說(shuō)。

控制器的內(nèi)容其實(shí)并不多,但里面的很多東西我們并沒(méi)有都講解到,畢竟現(xiàn)成的文檔都在,也沒(méi)必要全部再?gòu)?fù)制一遍,還是以調(diào)用路徑的源碼分析分主。下一個(gè)要講的內(nèi)容相信也是很多同學(xué)非常感興趣的,那就是中間件的應(yīng)用以及源碼的分析。

參考文檔:

https://learnku.com/docs/laravel/8.x/controllers/9368

https://learnku.com/docs/laravel/8.x/validation/937

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
【auth】登錄認(rèn)證權(quán)限控制
【干貨】Laravel - Redis 緩存三部曲 (一) 初識(shí)Predis
laravel結(jié)合easyWeChat的使用
在使用 Go 兩年之后,我又轉(zhuǎn)回 PHP 了
laravel-服務(wù)提供者-我是這么理解的
文件上傳原理簡(jiǎn)單實(shí)現(xiàn)
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服