30分鐘用 Laravel 實現一個博客

30分鐘用 Laravel 實現一個博客

介紹

  • laravel 是一款 mvc架構、 目前最流行的 php框架。
  • Laravel的優點在于: 豐富的composer類庫支持, 優雅的代碼, 未來的主流框架(目前市場占有率最高的框架)
  • Laravel的缺點在于: 過于優雅(我們只需要編寫極少的代碼即可實現功能,意味著底層極其復雜的封裝)導致程序的執行效率略低, 和thinkphp等國內主流框架相比,上手難度略高(因為它為我們集成了很多其他的功能,甚至你還需要學習nodeJS相關的知識)。
  • 本項目,是完全使用 Laravel框架 內的所提供的最基礎,但是又是最有用(能顯著提升我們開發效率)的工具而開發出來的。在學習過程中,你只需要操作一次數據庫,不需要自己構建html視圖模板(當然還是要寫一些html和js代碼的),不需要考慮外部的css、js。本教程的目的完全為向各位 phper 以及對 laravel 有興趣的小伙伴推薦這款我相信是未來主流的php框架。

推薦教程:2019年最新的五個Laravel視頻教程推薦

準備工作

如果你愿意用root用戶,你甚至只需要 create 一個 database 即可。 (不過不推薦,我的習慣是一個項目 對應 一個用戶 + 一個數據庫,root則只用來管理他們)

#?創建用戶?blog,?密碼自定義 CREATE?USER?'blog'@'%'?IDENTIFIED?BY?'密碼'; #?創建數據庫?blog,?設置默認編碼為utf8 CREATE?DATABASE?`blog`?DEFAULT?CHARACTER?SET?utf8?COLLATE?utf8_general_ci; #?授權?授予?blog庫下所有表的?所有權限?給?用戶blog GRANT?ALL?on?blog.*?to?'blog'@'%';
  • 使用 composer 創建一個 laravel 項目 取名叫blog
#?進入你本地服務器用于存放網站文檔的目錄,輸入命令 composer?create-project?--prefer-dist?laravel/laravel?blog

下文中,“/” 即表示 laravel 框架的根目錄

  • 配置 /.env 文件
#?數據庫配置 DB_CONNECTION=mysql?#類型 DB_HOST=127.0.0.1?#ip DB_PORT=3306?#端口 DB_DATABASE=數據庫名 DB_USERNAME=用戶名 DB_PASSWORD=密碼
  • 下載中文包 composer require caouecs/laravel-lang 然后將 /vendor/caouecs/src/zh-CN/ 放入 /Resources/lang/ 下
  • 配置一下 /config/app.php
#?時區 'timezone'?=>?'Asia/Shanghai', #?語言 'locale'?=>?'zh-CN',

準備工作總結

  • 1、創建用戶、數據庫,然后授權。
  • 2、使用 composer 創建項目。
  • 3、配置 laravel 的環境 ./env 。 然后使用 composer 安裝了漢化包,并且在 /config/app.php 中設置時區并且讓中文包生效。

第一階段: Migration、Factory、Seeder

你可能沒有見過上面3個名詞,不過和他們有關的文件都存放在 /database/ 下: 通過這個文件夾的名稱,你大概已經猜到:這三個文件都是用來操作數據庫的。


  • 上文中,我們只是創建了數據庫,并沒有創建數據表,現在來確定一下我們的數據表

    • 一個用戶表 users
    • 一個博客表 blogs
    • 一個評論表 comments

    項目是一個個人博客,因此只有博主可以發布、刪除、修改博客。其他用戶則可以查看博客和發布評論。

  • 使用 Migration 創建這3張數據表

    • 打開命令行,創建 migrations
      php artisan make:migration create_blogs –create=blogs 博客表,
      php artisan make:migration create_comments –create=comments 評論表

    php aritsan 是laravel內置的命令 你可以直接在控制臺輸入它,則會在控制臺提示你接下來你能輸入的命令。
    上文我們就使用 make:migration 幫我們創建了遷移文件, –create 是參數,即告訴這條命令,幫我們創建一個用于創建數據表的遷移文件

  • 為什么不創建用戶表呢? 打開 /database/migrations/ 你會發現有一個2014年就創建好的 針對 users 和 password_resets 表。這是框架自帶的。

  • 編輯這兩個遷移文件

    • create_blogs
    //?首先類定義中,有兩個方法,up()可以理解為正向操作:創建表,而?down()可以理解為回滾操作:刪除表。 //?up() Schema::create('blogs',?function?(Blueprint?$table)?{ ????$table->increments('id'); ????$table->string('title'); ????$table->text('content'); ????$table->timestamps(); }); //?down()?已經自動幫我們寫好了。
    • create_comments
    //?up() Schema::create('comments',?function?(Blueprint?$table)?{ ????????$table->increments('id'); ????????$table->string('content'); ????????$table->integer('blog_id');?//這條評論是針對哪一篇博客的? ????????$table->integer('user_id');?//這條評論是哪一位用戶發送的? ????????$table->timestamps(); ????});
  • 執行遷移: 1、確保你的 /.env 配置正確 2、確保你的數據庫可以正常使用 3、確保數據庫中沒有數據表或者沒有和users blogs comments重名的數據表 php artisan migrate

  • 打開數據庫(你可以任選一款數據庫管理工具,或者直接使用mysql的命令行),打開數據庫 blog ,你會發現有以下表

    • blogs => 我們創建的博客表
    • comments => 我們創建的評論表
    • migrations => 系統創建的遷移記錄表
    • password_resets => 框架自帶遷移文件生成的重置密碼用表
    • users => 框架自帶的用戶表
  • 主要解釋一下 migrations 表:

    • 這是一個記錄你的遷移文件名稱和批次的表。它的主要作用是通過記錄批次,方便你對數據庫進行版本控制:打開 migrations表,你會發現,當前記錄了4張表的遷移文件名,而他們的batch都是1,你可以理解為當前數據庫是第一批,版本1。
    • 如果你執行 php artisan migrate:rollback 即回滾數據庫,將會執行批次batch最大的記錄的那些遷移文件的 down() 方法。
  • migration 的作用:1、幫我們省略了去寫sql語句的麻煩,2、讓我們對數據庫可以進行有效的版本控制。


  • 使用模型工廠 Factory 來插入虛構的數據

在日常的開發中,我們需要很多模擬的數據進行測試,模型工廠的作用就是幫我們快速的,隨機的生成這些數據。

  • 創建模型工廠 ?php artisan make:factory BlogFactory –model=Blog , 關于評論表的模型工廠請自己寫。
  • 注意此時我們其實沒有模型 Blog 和模型 Comment,我們只是創建了數據表而已。因此我們再創建兩個模型。
    php artisan make:model Blog, 關于評論表的模型請自己寫。

細心的你可能發現了,我們的數據表和模型的名字是有區別的:數據表為“小寫復數形式”,而模型名為“大寫單數形式”。 創建的模型都存在于 /app/ 下。

  • 編輯模型工廠 /database/factories
    • BlogFactory
    //?使用?Faker?類為我們提供的生成隨機偽造數據的方法生成數據 ??return?[? ?????'title'?=>?$faker->name,???? ?????'content'?=>?$faker->text, ];
    • CommentFactory
    return?[ ????'content'?=>?$faker->text,???? ????'blog_id'?=>?1,???? ????'user_id'?=>?1,? ];
  • 使用 tinker 模式調試代碼
    • 進入 “修補匠模式” php artisan tinker , 當命令提示符變為 “>>>” 時,你就處于tinker模式下了,此時你可以輸入php代碼,或者調用laravel提供的全局函數,甚至引用一個類,調用它的靜態方法或者實例化它。
    • 在 tinker 模式下使用全局函數 factory() 生成模擬的數據 factory(AppBlog::class)->make() 此時屏幕上會顯示,它給你模擬出來的一個虛擬數據數組。
    • 使用 create() 一次性向數據表中插入100條模擬的數據 factory(AppBlog::class, 100)->create() 打開數據庫,您會發現100條標題和內容都無關緊要,但是對我們快速開發特別有用的測試數據已經存放在數據庫中了。

  • 使用 Seeder 一次性完成多個數據庫的批量虛擬數據插入
  • 創建 Seeder (如果你處于 tinker, 【ctrl】+【c】 先退出) php artisan make:seeder UserTableSeeder ,針對博客表和評論表的Seeder創建命令自己寫。
  • 打開 /database/seeds/ 我們創建的Seeder都在這里了,不過多了一個 DatabaseSeeder.php,我們等下再來了解它,先編輯其他Seeder,以 UserTableSeeder.php 為例
... use?AppUser;? //?在?class?關鍵字前面,引用一下?User?模型 class?... public?function?run()? { ????factory(AppUser::class,?50)->create();?//向users表中插入50條模擬數據 ????$user?=?User::find(1);?//插入完后,找到?id?為?1?的用戶 ????$user->name?=?"najiuyuanzou";?//設置?用戶名 ????$user->email?=?"najiuyuanzou@test.com";?//設置?郵箱 ????$user->password?=?bcrypt('liuhaoyu');?//設置?密碼 ????$user->save();?//保存 ?}

在這里我們明確1號用戶為真實的可用的管理員用戶!所以我們設置一下它的 用戶名 郵箱 以及密碼

  • 其余的Seeder我們可以只插入模擬的數據即可。

  • 現在回過頭來,編輯 DatabaseSeeder

public?function?run() { ????//?$this->call(UsersTableSeeder::class);? ????//?這里給我們舉例了如何引用其他Seeder???? ????$this->call(UserTableSeeder::class);???? ????$this->call(BlogTableSeeder::class);???? ????$this->call(CommentTableSeeder::class);//?這里有先后關系需要注意一下:?評論n?:?1文章/用戶,所以應該把它寫在最后 }

  • 使用命令,刷新整個數據庫并且執行模擬數據插入 php artisan migrate:refresh –seed => 查看數據庫,發現數據庫重置了,并且 users blogs comments 每張表都有很多虛擬的數據。

第一階段總結

  • 學習使用 migrations 的創建、編輯、執行以及回滾: 實現對數據表的結構更改以及數據庫版本管理(說白了就是個帶日志的數據表結構管理工具)
  • 學習使用 factories 的創建、使用 tinker 調試、使用 factory() 全局函數制造和插入數據。
  • 學習使用 seeds 的創建(Seeder)、編輯其他Seeder(在 run() 中調用 factory() )、編輯DatabaseSeed(在 run() 中調用 其他 Seeder)。
  • 最后通過它們3個的配合,使用命令刷新了整個數據庫并且分別向3張表插入了很多模擬的數據,便于我們開發。

也許你到這里會覺得這還不如你寫sql語句。但是請相信我,等你熟練掌握使用這些東西之后,你的開發速度會非常快!(畢竟你不需要再 “INSERT INTO table values ()” 復制粘貼修改100遍了)

第二階段: Auth的使用

  • 輸入神奇的命令,看看發生了什么 php artisan make:auth
  • 打開瀏覽器輸入你配置的虛擬主機地址,你會看到一個Laravel框架的歡迎頁面,這不是重點,點擊右上角的 register ,你可以注冊賬號,點擊 login 你可以登陸…
  • 本階段結束。

第二階段繼續: Auth

  • 好吧你可能很懵逼,但這就是Laravel的厲害之處,那個2014年就建好的migration遷移文件可不是個擺設。它就是通過操作users表來實現注冊登陸等等的。

  • php artisan make:auth 到底干了哪些事情呢?

    • 它給你創造了一組控制器,位于 /app/http/Controllers/Auth
    • 它在 /routes/web.php 中給你定義了2條路由
    Auth::routes();?//這是用戶操作相關的路由 Route::get('/home',?'HomeController@index')->name('home');?//這是主頁的路由
    • 它給你創造了一組視圖 /resources/views/auth/ 下是用戶操作相關的路由, home.blade.php是主頁, layouts/下是布局模板。
  • 我們改良一下它自動為我們生成的東西

    • 路由方面 (routes/web.php) 我們將根路由也指向視圖 home.blade.php ,這是最后的有效代碼:
    //?Route::action('uri',?'Controller@function'); Route::get('/',?'HomeController@index');  Auth::routes();  Route::get('/home',?'HomeController@index')->name('home');
    • 控制器方面 app/Http/Controllers/ 我們修改一下 HomeController.php
    /** ?*?這里這個構造函數調用了?中間件auth?對我們進行權限認證 ?*?即要求我們必須登陸才可以訪問該控制器的其他方法 ?*?有兩種解決方法,一直是在?$this->middleware('auth')->except('你要排除權限認證的方法'),比如?...->except('index') ?*?另一種是直接干掉這個函數(我們確定這個控制器就只是來展示首頁的,那么就干掉它吧) ?*/ //?public?function?__construct() //?{ //?????$this->middleware('auth'); //?}
    • 視圖方面:HomeController@index (這里我指的是 Home控制器的 index() 方法)調用了 return view(‘視圖名稱’) 來抓取視圖顯示在頁面上,現在打開瀏覽器訪問主頁,你就可以看得到 home.blade.php 中的內容了,我們看看 /resources/views/home.blade.php 的內容: 重點: @extens @section
    {{--??內容不重要我們等下要改,先來看下?@符號?的作用??--}}  {{--??@extends繼承其他模板??--}} @extends('layouts.app')?{{--??這里的layouts.app?=>?/resources/views/layouts/app.blade.php??--}}  {{--??@section?填充在布局模板上用?@yield?標注的占位符??--}} @section('content')?{{--??你可以在?/resources/views/layouts/app.blade.php?看到?@?yield('content')標注的占位符?--}} ????...?這里面是html內容 @endsection

    Auth為我們生成的整個視圖模板的邏輯: layouts/app.blade.php 為布局模板,其他模板都繼承該模板。

    • 最后我們“漢化”這些視圖
      • home.blade.php,你可以自由發揮,展示一個好看的主頁,這是我的
      @extends('layouts.app')  @section('content')<div> ????<div>???? ????????<div>??????????? ?????????<div>?????????????? ???????????<div>歡迎!這里是?“那就遠走”?的個人博客</div>? ???????????<div> ????????????????????如無牽掛,那就遠走。 ????????????????????{{--??這里等下要添加一個跳轉到展示文章列表頁面的按鈕??--}} ????????????</div>???????? ??????????</div>???? ???????</div>??? ????</div> ?</div> ?@endsection
      • ../layouts/app.blade.php & ../auth/login.blade.php & register.blade.php
      #?首先布局模板我們需要把?brand?登陸、注冊這些東西改一改 {{?config('app.name',?'Laravel')?}}?=&gt;?我的博客?//注意這里有一個?config('app.name')?該函數其實是讀取的?/.env?里的?APP_NAME?值,且默認值為?'Laravel'?,也就是說,你改?APP_NAME?也可以改這里顯示的值,不過我嫌麻煩,直接查找替換了。 {{?__('Login')?}}?=&gt;?登陸 {{?__('Register')?}}?=&gt;?注冊 {{?__('Logout')?}}?=&gt;?退出 #?然后登陸模板: {{?__('Login')?}}?=&gt;?登陸 {{?__('E-Mail?Address')?}}?=&gt;?郵箱 {{?__('Password')?}}?=&gt;?密碼 {{?__('Remember?Me')?}}?=&gt;?記住我 然后我們把?ForgetPassword?那個按鈕給干掉吧(這個找回密碼的功能需要一個SMTP服務的郵箱才能實現,現在暫時不弄) #?然后注冊模板 {{?__('Register')?}}?=&gt;?注冊 {{?__('Name')?}}?=&gt;?昵稱(用戶名) {{?__('Confirm?Password')?}}?=&gt;?密碼確認 #?有可能有說漏的,反正自己看著頁面上的英文查找替換成中文就可以了。

第二階段總結

  • 我們使用一條命令就實現了用戶操作的相關功能。
  • 但是這條命令生成的視圖是英文的,所以需要我們改成中文。
  • 這條命令主要是 生成了一組用戶操作的控制器+主頁控制器(其實還有中間件),生成了2條路由,生成了一組視圖。

第三階段_1: 路由、模型、視圖、控制器詳解。

  • 如果你完全熟悉MVC架構,可以跳過這一步。
  • 這里用大白話解釋:
    • 路由: /routes/web.php 瀏覽器中輸入的地址,比如定義 Route::get(‘home’, ‘HomeController@home’) => 即表示,你輸入 “http://localhost/blog/public/home” 是以GET的請求方式去請求 HomeController 的 home() 方法。
    • 模型: /app/ 一個模型對應數據庫中的一張數據表。(注意大小寫和單復數,模型:Model => 數據表:models)
    • 視圖: /resources/views/ 視圖就是普通的html模板,它等待控制器通過 return view() 調用和渲染它,最終展示給網站訪客。
    • 控制器: /app/Http/Controllers/ 處理數據、調用模型、簡單地操作數據庫、渲染視圖…,都由它完成。
    • 總結 => 路由定義在瀏覽器中訪問某控制器中某方法的地址,控制器完成一系列操作:如果需要操作數據庫,需要調用模型,每一個模型對應一張表。如果需要顯示數據,則需要找到框架內指定位置的視圖,對它完成渲染。

第三階段_2:資源路由、在資源控制器中完成對博客的增刪改查。

我們寫的程序,除了前臺好看的界面,就是后臺的程序,而后臺的程序無非就是“增刪改查”以及“花式增刪改查”罷了。
因此,仔細想想,對于一張數據表的操作,我們通常就需要這些行為:1、一個分頁展示所有數據的列表 2、一個添加數據的功能 3、一個編輯數據的功能 4、一個顯示單條數據詳細信息的功能 5、一個刪除功能。

  • 創建一個資源控制器,一次性幫我們生成能實現上面5個功能的方法 php artisan make:controller BlogController –resource –model=Blog ( –resouce生成的控制器為資源控制器即自帶 CURD增刪改查 所有方法的控制器 ) ( –model 是讓生成的控制器在參數列表中自動幫我們完成依賴注入生成實際變量 )

  • 根據 三_1 階段的說法,我們其實需要設置很多路由,來對應生成的 BlogController 下的各種方法,Laravel已經幫我們想到了所以它給我們提供了這樣一種方法配置路由,編輯 /routes/web.php ,在最后面添加這么一句 Route::resource(‘blog’, ‘BlogController’);

  • 有一個命令可以看到當前所有生效的路由 php artisan route:list ,控制臺自動彈出的表格中,Method 表示 請求方法,即
    Route::這里的方法() ?,URI 表示 請求地址,即 Route::action(‘這里就是uri’), name 表示 路由別名,可以通過 Route::action(‘uri’, ‘Controller@function’)->name(‘這里可以定義路由別名’)。

  • 你會發現,有7條關于 blog 的路由,這就是 Route::resource(‘blog’, ‘BlogController’) 幫我們生成的。(5個功能7條是因為 添加和編輯多了2條載入視圖的路由)

  • 完成增刪改查吧: 首先完成 BlogController@index : 展示列表

    • 先來個入口鏈接,打開 home.blade.php
    {{--??上面說過這里會添加一個按鈕??--}} <a>點擊這里查看我的博客</a>
    • 編輯 BlogController@index => 這里還是再提醒一下吧,這是說 BlogController 的 index() 方法。控制器文件都在 appHttpControllers 中
    <?php      namespace AppHttpControllers;      use AppBlog; //這里是使用命令創建控制器時,通過 --model=Blog 自動幫我們生成的      use IlluminateHttpRequest;      class BlogController extends Controller{          public function index()              {                    // 查詢數據,并且讓查詢結果是一個可分頁對象         $blogs = Blog::orderBy(&#39;created_at&#39;, &#39;desc&#39;) // 調用 Blog模型 的靜態方法 orderBy(&#39;根據created_at字段&#39;, &#39;倒敘排序&#39;)             ->paginate(6);?//?-&gt;?鏈式操作:paginate(6)?即數據沒頁6條?? ??????????????//?跳轉到視圖并傳值?? ????????????return?view('blog.index',?[?//第一個參數是說,視圖模板是?/resources/views/blog/index.blade.php????????????'blogs'?=&gt;?$blogs,?//這里是說,我們給視圖傳遞一個叫?$'blogs'的變量,值是前面我們查詢的數據,也叫$blogs。 ????????]);?//?view()?的第二參數也可以使用?view(...,?compact('blogs')) ????}
    • 此時刷新頁面當然會報錯了,因為我們的視圖還不存在,新建文件夾 /resources/views/blog/index.blade.php
    @extends('layouts.app')  @section('content') <div>?? ??<div>????? ?????<div>?????????? ???????<div>這是頁面小標題</div>???????????? ???????<div> ????????????????這里是內容??????????? ???????</div>??????? ?????</div>??? ???</div> ?</div> @endsection

    這就是我們所有頁面的布局,可以復制一份,作為模板。

    • 完成視圖里面的內容
    <div> ????<div>?????? ??????<div>????????? ?????????<div>文章列表</div>???????????? ?????????<div>?????????????? ???????????<table>??? ??????????????<thead>?????????????????????? ????????????????<tr>??????????????????????????? ?????????????????<th>文章標題</th>????????????????????????? ?????????????????<th>發布時間</th>?????????????????????????? ?????????????????<th>相關操作</th>???????????????????????? ???????????????</tr>???????????????????? ????????????????</thead>??????????????? ??????????????<tbody> ?????????{{--?這里通過?@foreach?遍歷數據?--}}?@foreach?($blogs?as?$blog)????? ????????????????<tr>??????????????????????????? ?????????????????<td>{{?$blog-&gt;title?}}</td>???????????????? ?????????????????<td>{{?$blog-&gt;created_at?}}</td>????????????? ?????????????????<td></td>???????????????????????? ?????????????????</tr> ??????????????????@endforeach???????????????????? ?????????????????</tbody>??????????????????? ????????????????<tfoot> ????????{{--?這里通過?$blogs-&gt;links()?來顯示分頁按鈕?--}}?{{?$blogs-&gt;links()?}}? ?????????????????</tfoot>?????????????? ?????????????</table>??????????? ????????</div>????? ??????</div>??? ????</div> ?</div>
    • 完成文章添加 添加入口鏈接, ../layouts/app.blade.php
    {{--?route('路由別名')?在視圖上就是一個指向?BlogController@create?的鏈接?--}} <a>?添加文章?</a>
    • 完成文章的添加 BlogController@create
    public?function?create(){ ????return?view('blog.create');?//載入視圖 ????}
    • 編輯視圖 重點:表單中添加@csrf告訴框架,這是我們自己的表單,不用擔心csrf跨站請求偽造的攻擊
    @extends('layouts.app')  @section('content') <div> ????<div>????? ???????<div>????????? ??????????<div>添加文章</div>???????????? ??????????<div> ??????{{--??from.method="POST"?action="通過?route()函數讀取路由別名?"?--}}??? ??????????<form> ??????????{{--??聲明?csrf?令牌??--}} ???????????@csrf?????????????????? ?????????????<div>??????????????????????? ??????????????<label>文章標題</label>????????????????? ???????????????<input>? ??????????????</div>???????????????????? ?????????????<div>??????????????????????? ??????????????<label>文章內容</label>??????????????? ????????????????<textarea></textarea>? ?????????????</div>?????????????????? ????????????<button>發布新文章</button>???? ???????????</form>??????????? ?????????</div>?????? ???????</div>??? ?????</div> ???</div> ??@endsection

    所謂跨站請求偽造,可以理解為來自于其他ip的表單,惡意請求我們的服務器。Laravel提供了一種防范這種攻擊的手段,即將自己的路由隱藏起來,只有帶有 @csrf 聲明的表單可以找得到接收表單信息的路由

    • 編輯 BlogController@store
    public?function?store(Request?$request)?//這里的?$request?是通過依賴注入的方法實例化的?Request?類的對象,包含的有所有請求的信息 { ????//?我們只需要調用?Blog模型?的靜態方法?create()?插入?$request-&gt;post()?數據即可??? ?????$blog?=?Blog::create($request-&gt;post());?//改方法的返回值是新插入的數據生成的對象 ????//?redirect()?頁面重定向???? ????return?redirect()-&gt;route('blog.show',?$blog);?//?這里我們將?$blog?作為參數請求?BlogController@show? }
    • 回到頁面,點擊提交,會發現報錯了,Laravel是一個極其注重安全的框架,用戶能修改哪些字段,必須要在模型文件中聲明,因此打開 appBlog.php 模型文件
    //?可填字段白名單 protected?$fillable?=?[ ????'title',?'content' ????];
    • 再次提交,頁面一片空白,是因為我們的 BlogController@show 方法還沒有寫,不過你可以注意到地址欄已經發生了改變。

    • 完成 show 方法

    public?function?show(Blog?$blog)?//這里已經通過依賴注入的形式幫我們實例化了?$blog { ????return?view('blog.show',?[????? ???????'blog'?=&gt;?$blog,?//直接將$blog傳給視圖進行渲染 ????]); }
    • 新建 ../blog/show.blade.php
    @extends('layouts.app')  @section('content') <div>? ???<div>?????? ?????<div>?????????? ???????<div>文章詳情</div>?????????? ?????????<div>?????????????? ???????????<h1>{{?$blog-&gt;title?}}</h1>???????????? ???????????????<p>發布時間<small>{{?$blog-&gt;created_at?}}</small></p>??????? ????????????????<hr>??????????????? ?????????????????<p>?{{?$blog-&gt;content?}}?</p>???????????? ????????????</div>??????? ??????????</div>???? ???????</div> ?????</div> ??@endsection
    • 刷新頁面,文章就顯示出來了。

    • 完成我們的編輯入口鏈接: 在 ?../blog/index.blade.php & show.blade.php 中合理的位置添加一個編輯按鈕

    <a>id)?}}"?class="btn?btn-info"&gt;編輯文章</a>
    • 完成 BlogController@edit
    public?function?edit(Blog?$blog){? ???return?view('blog.edit',?[???? ???????'blog'?=&gt;?$blog, ????]); }
    • 完成視圖 重點:action聲明文章編號,根據路由要求action在表單中使用@method偽造請求動作類型
    @extends('layouts.app')  @section('content') <div>? ???<div>???????? ?????<div>??????????? ??????<div>編輯文章</div>???????????? ??????<div> ???{{--?action需要聲明當前編輯的文章編號$blog-&gt;id?--}}???????????????? ???????<form>id)?}}"&gt; ???????{{--??聲明?csrf?令牌??--}} ??????????@csrf ???????{{--??偽造?PATCH?方法??--}} ??????????@method("PATCH")???????????????????? ???????<div>?????????????????????? ?????????<label>文章標題</label>??????????????????????? ??????????<input>title?}}"&gt;?? ???????</div>??????????????????? ???????<div>?????????????????????? ?????????<label>文章內容</label>?????????????????????? ???????????<textarea>{{?$blog-&gt;content?}}</textarea>?? ????????</div>???????????????????? ??????????<p>發表于<small>{{?$blog-&gt;created_at?}}</small></p>?????? ??????????<p>修改于<small>{{?$blog-&gt;updated_at?}}</small></p>?????????????? ??????????<button>確認編輯</button>??? ????????</form>???????????? ??????</div>???????? ????</div>???? ??</div> </div> @endsection
    • 完成 BlogController@update
    public?function?update(Request?$request,?Blog?$blog){ ????$blog-&gt;update($request-&gt;post());?//調用?$blog對象-&gt;update(更新數據組成的數組)?更新? ????return?redirect()-&gt;route('blog.show',?$blog); }
    • 完成刪除功能 在 index.blade.php 和 show.blade.php 合理的位置插入刪除按鈕
    <a>id?}});"?class="btn?btn-danger?btn-sm"&gt;刪除文章</a> ???????????????????????????? {{--??因為刪除也需要?csrf?令牌認證,所以弄個表單??--}} 
    id)?}}”?id=”delete-blog-{{?$blog->id?}}”> ????@csrf ????{{–??這里偽造DELETE請求??–}} ????@method(“DELETE”)
    • “刪除文章” 按鈕其實是調用了一個 js 函數,我們在 ../layousts/app.blade.php 中完成
    <script>     function deleteConfirm(id) {            var confirm = window.confirm(&#39;確認要刪除這篇文章嗎?&#39;);               if(confirm === true) {             $("#delete-blog-" + id).submit(); //提交表單         }else {                 window.alert(&#39;你選擇不刪除!&#39;);         }     }  </script>
    • 完成 BlogController@delete 方法
    public?function?destroy(Blog?$blog){ ????$blog-&gt;delete(); ????return?redirect()-&gt;route('blog.index');?//跳轉到首頁 ??}
    • 增刪改查完成。
  • 完善和優化

    • 首先無論增刪改查操作,成功后我們沒有任何提示,我們使用 Session 閃存方法消息吧:

      • 新建組件視圖文件夾 /resources/views/components/
      • 然后新建一個組件視圖 _message.blade.php => 組件視圖我們都用_下劃線開頭
      <div> ????{{--??遍歷?success?danger?這兩個我們等會會在?session-&gt;flash()?方法中設置的"key"??--}} ????@foreach?(['success',?'danger']?as?$msg) ????????{{--??當key存在的時候,證明我們給?session?flash?閃存里面裝載了一次提示信息,那么就顯示提示信息??--}} ????????@if?(session()-&gt;has($msg))? ????????????<div> ????????????????<ul> ????????????????????<li>{{?session()-&gt;get($msg)?}}</li> ????????????????</ul> ????????????</div> ????????@endif ????@endforeach </div>
      • 在 ../layousts/app.blade.php 中導入該組件 重點:@include 導入html片段
      {{--??在導航下面,內容上面導入??--}}@include('components._message')
      • 編輯 BlogController 里的各種方法,在執行成功某些方法時,頁面重定向前,裝載閃存。以刪除舉例
      $blog-&gt;delete(); session()-&gt;flash('success',?'刪除文章成功!');?//裝載session閃存 return?redirect()-&gt;route('blog.index');
    • 然后有個問題,就是在于,我們這是一個個人博客,所以只有我們自己可以對博客文章進行增刪改,而用戶只可以進行查看。因此我們需要:

      • 使用構造函數調用 auth中間件 來排除沒有登陸的用戶查看文章詳情: 編輯 BlogController
      public?function?__construct(){ ??$this-&gt;middleware('auth')-&gt;except('index'); }
      • 在 新增create、編輯edit、和刪除方法中加入一次用戶認證,以 create 方法舉例
      //?因為比較簡單,所以我們不用Policy進行認證,我會在以后的教程里面教大家如何使用Policy策略進行權限認證 //?這里我們就使用判斷當前用戶在數據表中信息的主鍵id是不是1即可(因為我們在Seeder里面把編號為1的用戶設置為了可用的管理員賬號) //?1、在代碼開頭引用?Auth //?2、在方法內先判斷一下是不是?1號用戶 if(Auth::user()-&gt;id?!=?1)?{ ?//?Auth::user()?獲取當前用戶信息?-&gt;?id獲取屬性id(主鍵) ????session()-&gt;flash('danger',?'抱歉,只有博主才可以新增文章!');??? ????return?redirect()-&gt;back(); }
  • 針對博客的增刪改查在這里就結束了。

第三階段總結

  • 我們使用命令創建了一個 “資源控制器”
  • 我們在 /routes/web.php 定義了一條資源路由
  • 我們使用 BlogController 中的7個方法完成了對 博客文章 的 CURD(增刪改查)操作。
  • 我們優化了一下體驗,使用 session()->flash() 裝載閃存信息,用一個組件html片段加載信息,最后用@include()在模板上加載這個html組件。
  • 我們最后增加了一個簡單的權限認證,判斷進行增刪改的用戶是不是管理員,不是管理員則不允許操作,直接裝載一條錯誤提示閃存,然后返回。

第四階段 評論功能

  • 新建一個評論資源控制器 php artisan make:controller CommentController –model=Commment
  • 新增一條資源路由,但只支持發表 /routes/web.php Route::resource(‘comment’, ‘CommentController’, [‘only’ => ‘store’]);

其實我們可以定義一條 Route::post(‘comment’, ‘CommentController@store’) 路由,但是為什么要寫資源路由呢?因為我要告訴你資源路由可以用 [‘onlu’=>’操作’] 讓其只支持一種操作:)

  • 在文章詳情頁面下方增加一個表單 show.blade.php

????@csrf?? ??????id?}}”>???? ??????id?}}”>??? ???????

??????? ??????????????? ??????????? ???????

??? ?????? ?

  • 編輯 CommentController@store
public?function?store(Request?$request){ ????Comment::create($request-&gt;post()); ????session()-&gt;flash('success',?'評論成功!'); ????return?redirect()-&gt;back(); }
  • 提交評論出錯了,又忘了寫可填字段白名單,編輯模型 appComment
protected?$fillable?=?[ ???'content',?'user_id',? ???'blog_id' ?];
  • 展示評論
    • 首先我們需要確定 Blog 和 Comment 的關系 => Blog 1:n Comment “一篇博客有多個評論”
    • 我們來綁定他們的關系
      • appBlog.php
      //?綁定1:n關系 public?function?comments()?{ ???return?$this-&gt;hasMany('AppComment');?//?1?hasMany?n ?}
      • appComment.php
      public?function?blog()?{? ???return?$this-&gt;belongsTo('AppBlog');?//?n?belongsTo?1 ?}
    • 然后通過他們的關系,我們可以在 BlogController@show 方法中調用 $blog->comments 來獲取屬于這篇文章的評論
    //?查詢評論 $comments?=?$blog-&gt;comments; //?視圖渲染 return?view('blog.show',?[ ????'blog'?=&gt;?$blog,???? ????'comments'?=&gt;?$comments,?//把評論也傳過去 ??]);
    • 在視圖層遍歷評論 show.blade.php
    <h3>評論</h3> 
      ????@foreach?($comments?as?$comment) ????????

    • {{?$comment->userName()?}}?評論說:“?{{?$comment->content?}}?”
    • ????@endforeach

    • 注意我們調用了 $comment->userName() 方法,現在沒有,所以我們再 appComment.php 模型中完成
    use?AppUser;?//引用模型 //?根據?user_id?獲取用戶名 public?function?userName()?{? ???return?User::find($this-&gt;user_id)-&gt;name;?//這里通過當前對象的?user_id?獲取?user對象,?然后指向-&gt;name屬性 ?}
  • 評論驗證

在博客中,我們就沒有使用驗證,那是因為項目定位是一個個人博客,能夠操縱博客增刪改的只有我們自己。而評論則是只要有人注冊賬號,就可以評論了,所以我們應該對評論進行一些校驗以防惡意攻擊。

  • 新建一個請求Request php artisan make:request CommentRequest

  • 新建的請求位于 appHttpRequests 下,編輯 CommentRequest

    //?1、?開啟授權 public?function?authorize(){? ???return?true;?//如果返回false則所有請求都無法生效,會告訴你沒有授權(其實在這里面我們是需要去進行判斷的,但是這里的邏輯很簡單:只有登陸才能查看文章詳情,才能看到文章詳情下面發表評論的表單,才能發表評論。)所以我們這里直接?return?true;}//?2、?編輯規則public?function?rules(){????return?[????????'content'?=&gt;?'required|min:15|max:100',?//這里你可以定義規則我的是:必填、最少15字、最多100字 ????]; }
    • 在 CommentController@store 方法的參數列表中通過 CommentRequest 構造 $request, 自動完成校驗
    public?function?store(CommentRequest?$request)?//?這將?Request?改成?CommentRequest?就會自動調用?CommentRequest@rules?來校驗請求的數據了 { ????Comment::create($request-&gt;post()); ????session()-&gt;flash('success',?'評論成功!');???? ????return?redirect()-&gt;back(); }
    • 優化視圖 show.blade.php
    {{--?樣式里面加一個判斷,判斷是否有關于content的錯誤有的話給樣式給文本域加一個紅邊邊?--}} <textarea>has('content')???'?is-invalid'?:?''?}}"?cols="30"?rows="10"?name="content"&gt;你對文章有什么看法呢?</textarea>  {{--?如果有錯誤,再顯示一個小的錯誤提示信息?--}} @if?($errors-&gt;has('content')) ????<span> ????????<strong>{{?$errors-&gt;first('content')?}}</strong> ????</span> @endif
    • 此時提交表單,左下角會提醒你 “內容不能為空”,如果你想改“內容兩個字”,可以打開 /resources/lang/zh-CN/validation.php
    'content'?=&gt;?'內容',?//這里就是配置字段的中文名,你把它改成評論即可。
    • 有時候文章過長,導致提交了,往下拉才看得到文本域變紅,所以我們需要新建一個錯誤組件../components/_error.blade.php
    {{--??判斷是否有錯誤??--}} @if?(count($errors)?&gt;?0)? ???<div> ????????{{--??遍歷所有錯誤??--}} ????????@foreach?($errors-&gt;all()?as?$error)?????????? ??????????<ul> ????????????????{{--??打印錯誤??--}}??????????????? ?????????????????<li>?{{?$error?}}</li>???????????? ??????????</ul> ????????@endforeach???? ?????</div>
  • ?@endif
    • 然后在 show.blade.php 中引用 @include(‘components._error’)

第四階段總結

  • 我們依然創建資源控制器,但是在路由中使用[‘only’=>’store’] 讓資源路由只暴露指向 CommentController@store 的路由
  • 我們學會了通過hasMany() & belongsTo()綁定模型之間的1:n關系。然后通過文章->評論+s;的方法直接獲取了屬于某篇文章的所有評論。
  • 我們學會了創建請求Request,并且在它的內部配置驗證規則,在控制器層中通過依賴注入的形式驗證數據。
  • 一旦表單提交的數據不符合 Request@rules Laravel會自動幫我們生成一個叫 $errors 的數組,它存放著所有的錯誤信息, 我們在視圖上通過判斷它是否有 content 字段來判斷是否是表單提交的評論有問題,然后修改文本域的樣式并且在下方用一個小的提示span顯示錯誤提示信息
  • 錯誤提示信息顯示的是“內容 怎么怎么樣…”,我們想把“內容”改成評論只需要修改中文語言包下的validation.php中的’content’字段的別名即可。

第五階段 最后總結

  • 想讓項目上線,也許你需要
    • 更好看的html排版
    • 重新執行一次 php artisan migrate:rollback
    • 權限認證太水了。你需要學習使用 Policy 來進行更安全和全面的權限認證。

也許文字很多,但是真正的代碼可能只有不到100行,你如果熟練掌握,可能不需要30分鐘,甚至10分鐘,你就可以開發出這樣一個博客了。

  • 視圖方面
    • 我們有通過 auth 生成的模板
    • Laravel 自帶的 bootstrap4 + jquery
    • 所以我們解決了css和js的問題 => 我們只是寫了一個 “確認刪除” 的前端代碼
  • 數據庫方面
    • 我們有 /database/ 下提供的 3套解決方案 Migration / Factory / Seeder 來幫我們解決數據庫管理的問題
    • 因為上面的解決方案,我們甚至只寫了 建用戶、建表、授權3條 數據庫操作語句。
  • 路由方面
    • Auth 自動幫我們生成了用戶操作相關路由
    • 我們使用資源路由來映射一個 CURD 控制器
  • 控制器和模型方面,通過命令生成的所有類文件,都幾乎幫我們寫好了,我們只需要完成里面的邏輯。
  • 當然,我們還有 Request 請求認證 Policy 策略控制等等一些列的特性沒有學習,我們也只使用了一次composer,其實在開發Laravel時,我們還可以使用非常多的,支持Laravel的,完善的輪子可以利用。

現在請告訴我,它是否配得上 “優雅” 的兩字?:)

希望大家可以喜歡、學習和推廣Laravel。如果您愿意付出比學習thinkphp5多0.01分的努力,我想這個框架是非常簡單的。

如果您依然討厭它的龐大,我向您推薦 Lumen 框架。

? 版權聲明
THE END
喜歡就支持一下吧
點贊6 分享