###### tags: `Laravel` `PHP` `書` # Lavarel 啟動與運行 ## 1.[[為何選擇 Lavarel]]? ### _為何使用框架?_ - #### "我想要自己建構" - #### 一致性與靈活性 ### _web 與 PHP 框架簡史_ - #### Ruby on Rails - #### 如雨後春筍般冒出的 PHP 框架 - #### CodeIgniter 的優與劣 - #### Lavarel 1、2 與 3 - #### Lavarel 4 - #### Lavarel 5 ### _到底 Lavarel 特別在哪?_ - #### Lavarel 的哲學 - #### Lavarel 如何讓開發者更幸福 - #### Lavarel 社群 - #### 它如何工作 - #### 為何選擇 Lavarel --- ## 2.[[設置 Lavarel 開發環境]] ### _系統需求_ ### _Composer_ ### _本地開發環境_ - #### Lavarel Valet - #### Lavarel Homestead ### _建立 Laravel 新專案_ - #### 使用 Laravel 安裝工具來安裝 Laravel - #### 使用 Composer 的 create-project 功能來安裝 Laravel - #### Lambo:超強的"Laravel New" ### _Laravel 的目錄結構_ - #### 資料夾 - #### 零星的檔案 ### _設置_ - #### .env ### _啟動並執行_ ### _測試_ --- ## 3.[[路由與 controller]] ### _簡介 MVC HTTP 動詞與 REST_ - #### 什麼是 MVC 1. modal 存取資料庫 2. controller 中間站 3. view client 端頁面 - #### HTTP 動詞 - #### 什麼是 REST ### _路由定義_ ```php //routes/web.php Route::get('/',function(){ return 'Hello,World!'; }) //當路由closure跟controller完成後中間會經過middleware在過去client端 ``` ```php Route::get('/',function(){ return view('welcome'); }) Route::get('/about',function(){ return view('about'); }) ``` - #### 路由動詞 - #### 路由處理 ```php Route::get('/','WelcomeController@index') ``` - #### 路由參數 ```php //可使用regex來篩選 Route:get('posts/{id}',function($id){ // })->where('id','[0-9]+'); //多個路由參數的限制 Route:get('posts/{id}/{slug}',function($id,$slug){ // })->where(['id'=>'[0-9]+','slug'=>'[A-Za-z]+']); ``` - #### 路由名稱 ```php //定義路由名稱 Route::get('members/{id}','MembersController@show')->name('members.show'); //view裡面用route() <a href="<?php echo route('members.show',['id'=>14]); ?>"> ``` 傳遞路由參數給 route()輔助函式 ```php // users/userId/comments/commentId如果userId=1 commentId=2 1.route('users.comments.show',[1,2]) 2.route('users.comments.show',['userId'=>1,'commentId'=>2]) 3.route('users.comments.show',['commentId'=>2],'userId'=>1) //http://myapp.com/users/1/comments/2 4.route('users.comments.show',['userId'=>1,'commentId'=>2,'opt'=>'a']) //http://myapp.com/users/1/comments/2?opt=a ``` ### _路由群組_ ```php Route::group(function(){ Route::route('hello',function(){ return 'Hello'; }); Route::route('World',function(){ return 'World'; }) }); ``` - #### middleware - ##### 在 controller 中套用 middleware ```php class DashboardController extends Controller { public function __construct() { $this->middleware('auth'); $this->middleware('admin-auth') ->only('editUser'); $this->middleware('team-member') ->except('editUser'); }; } ``` - ##### 速率限制 ```php Route::middleware('auth:api','throttle:60,1')->group(function(){ Route::get('/profile',function(){ // }); }) ``` - #### 路徑前綴詞 ```php Route::prefix('dashboard')->group(function(){ Route::get('/',function(){}); // /dashboard/ Route::get('/users',function(){}); // /dashboard/users }); ``` - #### 後備路由 找不到放在最後 ```php Route::fallback(function(){ // }); ``` - #### 子網域路由 ```php //基本用法 Route::domain('api/myapp.com')->group(function(){ Route::get('/',function(){}); }); //參數化 Route::domain('{account}/myapp.com')->group(function(){ Route::get('/',function($account){}); Route::get('/users/{id}',function($account,$id){}); }); ``` - #### 名稱空間前綴詞 使用子網域路由 controller 通常會有差不多的名稱空間 ```php //App\Http\Controllers\UsersController Route::get('','UsersController@index'); //App\Http\Controllers\Dashboard\PurchasesController Route::namespace('Dashboard')->group(function(){ Route::get('dashboard/purchases','PurchasesController@index'); }) ``` - #### 名稱前綴詞 ```php Route::name('users.')->prefix('users')->group(function(){ Route::name('comments.')->prefix('comments')->group(function(){ Route::get('{id}',function(){ })->name('show'); }); }); ``` ### _signed 路由_ - #### 簽署路由 ```php //產生一般的連結 URL::route('invitations',['invitations'=>12345,'answer'=>'yes']); //產生signed連結 URL::signedRoute('invitations',['invitations'=>12345,'answer'=>'yes']); //產生有期限的signed連結 URL::temporarySignedRoute( 'invitations', now()->addHour(4), ['invitations'=>12345,'answer'=>'yes'] ); ``` - #### 修改路由來允許 signed 連結 ```php Route::get('invitations/{invitations}/{answer}','InvitationController') ->name('invitations') ->middleware('signed'); ``` ### _view_ ```php //將變數傳給view Route::get('tasks',function(){ return view('tasks.index') ->with('tasks',Task::all()); }); ``` - #### 用 Route::view()直接回傳簡單的路由 Route::view() ```php //不需要傳變數 Route::view('/','welcome') //傳遞簡單資料 Route::view('/','welcome',['User'=>'Michael']) ``` - #### 使用 view composer 來讓所有 view 共用變數 ```php //view composer讓所有view共用變數 view()->share('variableName','variableValue'); ``` ### _controller_ ```php //這會在app/Http/Controllers建立TasksController.php php artisan make:controller TasksController //原始TasksController.php樣子 <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class TasksController extends Controller{ } //修改成 namespace App\Http\Controllers; use Illuminate\Http\Request; class TasksController extends Controller{ public function index(){ return 'Hello World'; } } //建立簡單路由 //routes/web.php <?php Route::get('/','TasksController@index') //去/就可以看到Hello World ``` - #### 常見 controller 方法案例 ```php //TasksController.php ... public function index(){ return view('tasks.index') ->with('tasks',Task::all()); } //會載入resources/views/tasks/index.blade.php 或者....index.php //傳入tasks變數,這個變數有Task::all()Eloquent方法的結果 ``` - #### 取得用戶輸入 ```php //routes/web.php Route::get('tasks/create','TasksController@create'); Route::post('tasks','TasksController@store'); //TasksController內的store方法 //TasksController.php ... public function store() { Task::create(request()->only(['title','description'])); return redirect('tasks'); } ``` - #### 將依賴項目注入 controller 例如:想使 Request 物件實例,而不是使用全域輔助函示,只需將方法中 typehint Illuminate\Http\Request ```php //TasksController.php ... public function store(\Illuminate\Http\Request $request) { Task::create(request()->only(['title','description'])); return redirect('tasks'); } ``` - #### 資源控制器 內建產生器 ``` //commend lines製作新controller php artisan make::controller MySampleController.php //裡面就內建一些方法 ``` - #### API 資源控制器 建立 controller 時加--api ```commend lines php artisan make::controller MySampleController.php --api ``` - #### 單一動作 controller 將單一路由指向單一 controller ```php // \APP\Http\Controller\UpdateUserAvatar.php public function __invoke(User $user){ // } //routes/web.php Route::post('users/{user}/update_avatar','UpdateUserAvatar'); ``` ### _路由 modal 綁定_ 常見路由模式:所有 controller 方法第一行會試著找出特定 ID ```php Route::get('controller/{id}', function($id){ $conference = Conference::findOrFail($id); }); ``` Laravel 有簡化的功能,稱為 **_路由 modal 綁定_** - #### 隱性路由 modal 綁定 ```php //使用顯性路由modal綁定 Route::get('controller/{conference}', function(Conference $conference){ return view('conferences.show')->with('conference', $conference); }); ``` - #### 自訂路由 modal 綁定 在 App\Providers\RouteServiceProvider 中的 boot()加入 ```php public function boot() { //為了讓父代的boot()方法持續運行 parent::boot(); //執行綁定 Route::model('event',Conference::class); } ``` ```php Route::get('events/{event}',function(Conference $event){ return view('events.show')->with('event', $event); }); ``` ### _路由快取_ ```commend lines //Laravel會將routes/*檔案結果序列化 php artisan route:cache //刪除快取 php artisan route:clear ``` **缺點** Laravel 會拿路由與快取比較,而不是 routes/\*,所以修改路由檔案不會有效果,除非再次 cache **建議** 使用 git 然後執行 php artisan route:cache ### _表單方法欺騙_ - #### Lavarel 的 HTTP 動詞 - #### 在 HTML 表單內的 HTTP 方法欺騙 ### _CSRF 保護_ //跨網站偽造請求,使用權杖保護所有入站路由 1. form 內加入\_token 輸入 2. <meta>中儲存權杖 ```javascript //axios window.axios.defaults.headers.common["X-CSRF-Token"] = document.head.querySelector('meta[name="X-CSRF-Token"]'); ``` ### _轉址_ - #### redirect()->to() - #### redirect()->route() - #### redirect()->back() - #### 其他轉址方法 - #### redirect()->with() ### _中止請求_ ### _自訂回應_ - #### response()->make() - #### response()->json() 與 ->jsonp() - #### response()->download()、 ->streamDownload()與->file() ### _測試_ --- ## 4.[[Blade 模板]] ### *echo 資料*  ### *控制結構*  - #### 條件邏輯 - #### 迴圈 ### *模板繼承*  - #### 使用@section/@show 與@yield 來定義區段 - #### 包含部分 view - #### 使用堆疊 - #### 使用元件與槽 ### _view composer 與服務注入_ - #### 使用 view composer 來將資料綁定 view - #### Blade 服務注入 ### _自訂 Blade 指令_ - #### 自訂 Blade 指令的參數 - #### 範例:在多租戶 app 中使用自訂 Blade 指令 - #### 用更簡單的方式自訂"if"陳述式的指令 ### _測試_ --- ## 5.[[資料庫與 Eloquent]] ### _設置_ - #### 資料庫連結 - #### 其他的資料庫設定選項 - #### 定義 migration - #### 執行 migration ### _seeding_ - #### 建立 seeder - #### model 工廠 ### _查詢購建器_ - #### DB 靜態介面的基本用法 - #### 原始 SQL - #### 串接查詢構建器 - #### 交易 ### _Eloquent 簡介_ - #### 建立與定義 Eloquent model - #### 使用 Eloquent 取出資料 - #### 使用 Eloquent 來插入與更新 - #### 使用 Eloquent 來刪除 - #### 範圍 - #### 使用 accessor、mutator 及屬性轉義來自訂欄位互動 - #### Eloquent 集合 - #### Eloquent 序列化 - #### Eloquent 關係 - #### 從子紀錄更新親紀錄的時戳 ### _Eloquent 事件_ ### _測試_ --- --- ## 6.[[前端元件]] ### _Laravel Mix_ - #### Mix 資料結構 - #### 執行 Mix\*\*- - #### Mix 提供什麼 ### _前端 preset 與身分驗證鷹架_ - #### 前端 preset - #### 身分驗證鷹架 ### _分頁_ - #### 將資料庫結果分頁 - #### 手動建立分頁器 ### _訊息袋_ - #### 具名錯誤袋 - #### 字串輔助函示、複數化與當地語系化 - #### 字串輔助函示與複數化 - #### 當地語系化 ### _測試_ - #### 測試訊息與錯誤袋 - #### 翻譯與當地語系化 --- --- ## 7.[[收集與處理用戶資料]] ### _注入 Request 物件_ - #### $request->all() - #### $request->except()與$request->only() - #### $request->has() - #### $request->input() - #### $request->method()與->isMethod() - #### 陣列輸入 - #### JSON 輸入(與$request->json()) ### _路由資料_ - #### 透過 Request - #### 透過路由參數 ### _被上傳的檔案_ ### _驗證_ - #### Request 物件的 validate() - #### 手動驗證 - #### 自訂規則物件 - #### 顯示驗證錯誤訊息 ### _表單請求_ - #### 建立表單請求 - #### 使用表單請求 ### _Eloquent model 的大量賦值_ ### _{{vs.{!!_ ### _測試_ --- --- ## 8.[[Artisan 與 Tinker]] ### _Artisan 簡介_ ### \*基本 Artisan 命令 - #### 選項 - #### 分組的命令 ### _編寫自訂的 Artisan 命令_ - #### 命令範圍 - #### 引數與選項 - #### 使用輸入 - #### 提示 - #### 輸出 - #### 將命令寫成 closure ### _在一般程式中呼叫 Artisan 命令_ ### _Tinker_ ### _Laravel dump 伺服器_ ### _測試_ --- --- ## 9.[[用戶身分驗證與授權]] ### _用戶 model 與 migration_ ### _使用 auth()全域輔助函示與 Auth 靜態介面_ ### _Auth controller_ - #### RegisterController - #### LoginController - #### ResetPasswordController - #### ForgotPasswordController - #### VerificationController ### _Auth::routes()_ ### _Auth 鷹架_ ### _"記住我"_ ### _手動驗證用戶_ ### _手動登出用戶_ - #### 讓其他裝置上的 session 失效 ### _驗證 middleware_ ### _email 驗證_ ### _Blade 身分驗證指令_ ### _守衛_ - #### 改變預設的守衛 - #### 使用其他的守衛而不改變內定的守衛 - #### 加入新守衛 - #### closure 請求守衛 - #### 建立自訂用戶 provider - #### 為非關連式資料庫自訂 user provider ### _驗證式建_ ### _授權(ACL)與角色_ - #### 定義授權規則 - #### Gate 靜態介面(與注入 Gate) - #### 資源 Gate - #### Authorize middleware - #### controller 授權 - #### 在用戶實例檢查 - #### Blade 檢查 - #### 攔截檢查 - #### policy ### _測試_ --- --- ## 10.[[請求、回應與 middleware]] ### _Laravel 請求的生命週期_ - #### 啟動應用程式 - #### 服務供應器 ### _Request 物件_ - #### 在 Laravel 中取得 Request 物件 - #### 取得 Request 的基本資訊 ### _Response 物件_ - #### 在 controller 中使用與建立 Response 物件 --- ## 11.[[容器]] ### _依賴項目注入簡介_ ### _依賴項目注入與 Laravel_ ### _app()全域輔助函示_ ### _容器是如何連接的?_ ### _將類別綁定容器_ - #### 綁定 closure - #### 綁定 singleton、別名與實例 - #### 將具體實例綁定介面 - #### 情境綁定 ### _在 Laravel 框架檔案內進行建構式注入_ ### _方法注入_ ### _靜態介面與容器_ - #### 靜態介面如何運作? - #### 即時靜態介面 ### _服務供應器_ ### _測試_ --- ## 12.[[測試]] ### _測試基本知識_ ### _為測試命名_ ### _測試環境_ ### _測試特徵_ - #### RefreshDatabase - #### WithoutMiddleware - #### DatabaseMigrations - #### DatabaseTranslations ### _簡單的單元測試_ ### _應用測試:工作原理_ - #### TestCase ### _HTTP 測試_ - #### 用$this->get()與其他 HTTP 呼叫來測試基本網頁 - #### 用$this->getJson()和其他 JSON HTTP 呼叫來測試 JSON API - #### 對著$response 斷言 - #### 身分驗證回應 - #### HTTP 測試的其他自訂選項 - #### 在應用測試中處理例外 ### _資料庫測試_ - #### 在測試中使用 model 工廠 - #### 在測試中 seeding ### _測試其他的 Laravel 系統_ - #### 事件 fake - #### Bus 與 Queue fake - #### Mail fake - #### Notification fake - #### Storage fake ### _模仿(mocking)_ - #### Mock 簡介 - #### Mockery 簡介 - #### 偽造其他靜態介面 ### _測試 Artisan 命令_ - #### 對 Artisan 命令語法執行斷言 ### _瀏覽器測試_ - #### 選擇工具 - #### 使用 Dusk 進行測試 --- ## 13.[[編寫 API]] ### _類 REST JSON API 基礎_ ### _controller 組織與 JSON 回傳_ ### _讀取與傳送標頭_ - #### 在 Laravel 中傳送回應標頭 - #### 在 Laravel 中讀取請求標頭 ### _Eloquent 分頁_ ### _排序與篩選_ - #### 排序 API 結果 - #### 篩選 API 結果 ### _轉換結果_ - #### 編寫你自己的轉換器 - #### 使用自訂轉換器時的嵌套與關係 ### _API 資源_ - #### 建立資源類別 - #### 資源集合 - #### 嵌套的關係 - #### 使用 API 資源分頁 - #### 有條件第套用屬性 - #### 關於 API 資源的其他自訂 ### *使用 Laravel Passport*來做 API 身分驗證 - #### OAuth2.0 簡介 - #### 安裝 Passport - #### Passport 的 API - #### Passport 的授權類行 - #### 使用 Passport API 與 Vue 元件來管理用戶端與權杖 - #### Passport 範圍 - #### 部屬 Passport ### _API 權杖驗證_ ### _自訂 404 回應_ - #### 觸發後備路由 ### _測試_ - #### 測試 Passport --- ## 14.[[儲存與取回]] ### _本地與雲端檔案管理器_ - #### 組態檔案存取 - #### 使用 Storage 靜態介面 - #### 增加額外的 Flysystem 提供者 ### _基本檔案上傳與操作_ ### _簡單的檔案下載_ ### _Session_ - #### 存取 session - #### session 實例提供的方法 - #### Flash session 儲存系統 ### _快取_ - #### 存取快取 - #### Cache 實例提供的方法 ### _cookie_ - #### Laravel 的 cookie - #### 使用 cookie 工具 ### _log_ - #### 何時與為何使用 log? - #### 寫入 log - #### log 通道 ### _用 Laravel Scout 來做全文搜尋_ - #### 安裝 Scout - #### 標記你的索引 model - #### 搜尋你的索引 - #### 佇列與 Scout - #### 不使用索引來執行操作 - #### 依條件檢所的 model - #### 透過程式碼來手動觸發索引 - #### 透過 CLI 來手動觸發檢索 ### _測試_ - #### 檔案儲存系統 - #### session - #### 快取 - #### cookie - #### log - #### Scout --- ## 15.[[郵件與通知]] ### _郵件_ - #### "classic"郵件 - #### 基本的"mailable"郵件用法 - #### 郵件模板 - #### build()提供的方法 - #### 附加與內嵌圖像 - #### Markdown mailable - #### 將 mailable 算繪至瀏覽器 - #### 佇列 - #### 本地開發 ### _通知_ - #### 為你的 notifiable 定義 via()方法 - #### 傳送通知 - #### 將通知放入佇列 - #### 內建的通知類型 ### _測試_ - #### 郵件 - #### 通知 --- ## 16.[[佇列、job、事件、廣播與排程器]] ### _佇列_ - #### 為何使用佇列? - #### 基本的佇列組態設定 - #### 佇列中的 job - #### 運行佇列工人 - #### 處理錯誤 - #### 控制佇列 - #### 佇列支援其他功能 ### _Laravel Horizon_ ### _事件_ - #### 觸發事件 - #### 監聽事件 ### _用 WebSocket 與 Laravel Echo 來廣播事件_ - #### 組態與設定 - #### 廣播事件 - #### 接收訊息 - #### 進階廣播工具 - #### Laravel Echo(Javascript 端) ### _排程器_ - #### 可用的工作類型 - #### 可用的時間範圍 - #### 定義排程命令的時區 - #### 阻塞與重疊 - #### 處理工作輸出 - #### 工作掛勾 ### _測試_ --- ## 17.[[輔助函式與集合]] ### _輔助函式_ - #### 陣列 - #### 字串 - #### 應用程式路徑 - #### URL - #### 其他 ### _集合_ - #### 基本知識 - #### 一些方法 --- ## 18.[[Laravel 生態系統]] ### _本書介紹過的工具_ - #### Valet - #### Homestead - #### Laravel 安裝程式 - #### Mix - #### Dusk - #### Passport - #### Horizon - #### Echo ### _本書介紹過的工具_ - #### Forge - #### Envoyer - #### Cashier - #### Socialite - #### Nova - #### Spark - #### Lumen - #### Envoy - #### Telescope ### _其他資源_