├── artisan.md ├── authentication.md ├── authorization.md ├── billing.md ├── blade.md ├── broadcasting.md ├── cache.md ├── cashier-paddle.md ├── collections.md ├── concurrency.md ├── configuration.md ├── console-tests.md ├── container.md ├── context.md ├── contracts.md ├── contributions.md ├── controllers.md ├── csrf.md ├── database-testing.md ├── database.md ├── deployment.md ├── documentation.md ├── dusk.md ├── eloquent-collections.md ├── eloquent-factories.md ├── eloquent-mutators.md ├── eloquent-relationships.md ├── eloquent-resources.md ├── eloquent-serialization.md ├── eloquent.md ├── encryption.md ├── envoy.md ├── errors.md ├── events.md ├── facades.md ├── filesystem.md ├── folio.md ├── fortify.md ├── frontend.md ├── hashing.md ├── helpers.md ├── homestead.md ├── horizon.md ├── http-client.md ├── http-tests.md ├── installation.md ├── license.md ├── lifecycle.md ├── localization.md ├── logging.md ├── mail.md ├── middleware.md ├── migrations.md ├── mix.md ├── mocking.md ├── mongodb.md ├── notifications.md ├── octane.md ├── packages.md ├── pagination.md ├── passport.md ├── passwords.md ├── pennant.md ├── pint.md ├── precognition.md ├── processes.md ├── prompts.md ├── providers.md ├── pulse.md ├── queries.md ├── queues.md ├── rate-limiting.md ├── readme.md ├── redirects.md ├── redis.md ├── releases.md ├── requests.md ├── responses.md ├── reverb.md ├── routing.md ├── sail.md ├── sanctum.md ├── scheduling.md ├── scout.md ├── seeding.md ├── session.md ├── socialite.md ├── starter-kits.md ├── strings.md ├── structure.md ├── telescope.md ├── testing.md ├── upgrade.md ├── urls.md ├── valet.md ├── validation.md ├── verification.md ├── views.md └── vite.md /concurrency.md: -------------------------------------------------------------------------------- 1 | # 並行處理 2 | 3 | - [簡介](#introduction) 4 | - [執行並行任務](#running-concurrent-tasks) 5 | - [延遲執行並行任務](#deferring-concurrent-tasks) 6 | 7 | 8 | ## 簡介 9 | 10 | > [!WARNING] 11 | > Laravel 的 `Concurrency` 配接器目前處於測試階段,我們正在收集社區的意見。 12 | 13 | 有時您可能需要執行幾個不相互依賴的緩慢任務。在許多情況下,通過並行執行這些任務可以實現顯著的性能改進。Laravel 的 `Concurrency` 配接器提供了一個簡單、方便的 API,用於同時執行閉包。 14 | 15 | 16 | #### 並行相容性 17 | 18 | 如果您從 Laravel 10.x 應用升級到 Laravel 11.x,您可能需要將 `ConcurrencyServiceProvider` 添加到應用程式的 `config/app.php` 配置文件中的 `providers` 陣列中: 19 | 20 | ```php 21 | 'providers' => ServiceProvider::defaultProviders()->merge([ 22 | /* 23 | * Package Service Providers... 24 | */ 25 | Illuminate\Concurrency\ConcurrencyServiceProvider::class, // [tl! add] 26 | 27 | /* 28 | * Application Service Providers... 29 | */ 30 | App\Providers\AppServiceProvider::class, 31 | App\Providers\AuthServiceProvider::class, 32 | // App\Providers\BroadcastServiceProvider::class, 33 | App\Providers\EventServiceProvider::class, 34 | App\Providers\RouteServiceProvider::class, 35 | ])->toArray(), 36 | ``` 37 | 38 | 39 | #### 工作原理 40 | 41 | Laravel 通過序列化給定的閉包並將它們分派給隱藏的 Artisan CLI 命令來實現並行處理,該命令將閉包反序列化並在其自己的 PHP 進程中調用它。閉包被調用後,結果值被序列化回父進程。 42 | 43 | `Concurrency` 配接器支持三種驅動程式:`process`(默認)、`fork` 和 `sync`。 44 | 45 | `fork` 驅動程式相比默認的 `process` 驅動程式具有更好的性能,但它只能在 PHP 的 CLI 上下文中使用,因為 PHP 在 Web 請求期間不支持分叉。在使用 `fork` 驅動程式之前,您需要安裝 `spatie/fork` 套件: 46 | 47 | ```shell 48 | composer require spatie/fork 49 | ``` 50 | 51 | `sync` 驅動程式主要在測試期間非常有用,當您想要禁用所有並行處理並在父進程中按順序執行給定的閉包時。 52 | 53 | 54 | ## 執行並行任務 55 | 56 | 要執行並行任務,您可以調用 `Concurrency` 配接器的 `run` 方法。`run` 方法接受一個閉包陣列,這些閉包應該在子 PHP 進程中同時執行: 57 | 58 | 要使用特定的驅動程式,您可以使用 `driver` 方法: 59 | 60 | ```php 61 | $results = Concurrency::driver('fork')->run(...); 62 | ``` 63 | 64 | 或者,要更改預設的並行驅動程式,您應該透過 `config:publish` Artisan 命令發佈 `concurrency` 組態檔並在該檔案中更新 `default` 選項: 65 | 66 | ```shell 67 | php artisan config:publish concurrency 68 | ``` 69 | 70 | ## 延遲並行任務 71 | 72 | 如果您想要同時執行一組閉包,但不關心這些閉包返回的結果,您應該考慮使用 `defer` 方法。當調用 `defer` 方法時,給定的閉包不會立即執行。相反,Laravel 將在將 HTTP 回應發送給用戶後並行執行這些閉包: 73 | 74 | ```php 75 | use App\Services\Metrics; 76 | use Illuminate\Support\Facades\Concurrency; 77 | 78 | Concurrency::defer([ 79 | fn () => Metrics::report('users'), 80 | fn () => Metrics::report('orders'), 81 | ]); 82 | ``` 83 | -------------------------------------------------------------------------------- /console-tests.md: -------------------------------------------------------------------------------- 1 | # 控制台測試 2 | 3 | - [簡介](#introduction) 4 | - [成功 / 失敗期望](#success-failure-expectations) 5 | - [輸入 / 輸出期望](#input-output-expectations) 6 | - [控制台事件](#console-events) 7 | 8 | 9 | ## 簡介 10 | 11 | 除了簡化 HTTP 測試外,Laravel 還提供了一個簡單的 API 來測試應用程式的[自訂控制台命令](/docs/{{version}}/artisan)。 12 | 13 | 14 | ## 成功 / 失敗期望 15 | 16 | 要開始,讓我們探討如何對 Artisan 命令的退出碼進行斷言。為了完成這個任務,我們將使用 `artisan` 方法從測試中調用一個 Artisan 命令。然後,我們將使用 `assertExitCode` 方法來斷言該命令是否以給定的退出碼完成: 17 | 18 | ```php tab=Pest 19 | test('console command', function () { 20 | $this->artisan('inspire')->assertExitCode(0); 21 | }); 22 | ``` 23 | 24 | ```php tab=PHPUnit 25 | /** 26 | * Test a console command. 27 | */ 28 | public function test_console_command(): void 29 | { 30 | $this->artisan('inspire')->assertExitCode(0); 31 | } 32 | ``` 33 | 34 | 您可以使用 `assertNotExitCode` 方法來斷言該命令未以給定的退出碼退出: 35 | 36 | ```php 37 | $this->artisan('inspire')->assertNotExitCode(1); 38 | ``` 39 | 40 | 當終端機命令成功時,通常以狀態碼 `0` 退出,而失敗時以非零退出碼退出。因此,為了方便起見,您可以使用 `assertSuccessful` 和 `assertFailed` 斷言來斷言給定命令是否以成功的退出碼退出或否: 41 | 42 | ```php 43 | $this->artisan('inspire')->assertSuccessful(); 44 | 45 | $this->artisan('inspire')->assertFailed(); 46 | ``` 47 | 48 | 49 | ## 輸入 / 輸出期望 50 | 51 | Laravel 允許您使用 `expectsQuestion` 方法輕鬆“模擬”控制台命令的用戶輸入。此外,您可以使用 `assertExitCode` 和 `expectsOutput` 方法來指定您期望由控制台命令輸出的退出碼和文本。例如,考慮以下控制台命令: 52 | 53 | ```php 54 | Artisan::command('question', function () { 55 | $name = $this->ask('What is your name?'); 56 | 57 | $language = $this->choice('Which language do you prefer?', [ 58 | 'PHP', 59 | 'Ruby', 60 | 'Python', 61 | ]); 62 | 63 | $this->line('Your name is '.$name.' and you prefer '.$language.'.'); 64 | }); 65 | ``` 66 | 67 | 您可以使用以下測試來測試此命令: 68 | 69 | ```php tab=Pest 70 | test('console command', function () { 71 | $this->artisan('question') 72 | ->expectsQuestion('What is your name?', 'Taylor Otwell') 73 | ->expectsQuestion('Which language do you prefer?', 'PHP') 74 | ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.') 75 | ->doesntExpectOutput('Your name is Taylor Otwell and you prefer Ruby.') 76 | ->assertExitCode(0); 77 | }); 78 | ``` 79 | 80 | ```php tab=PHPUnit 81 | /** 82 | * Test a console command. 83 | */ 84 | public function test_console_command(): void 85 | { 86 | $this->artisan('question') 87 | ->expectsQuestion('What is your name?', 'Taylor Otwell') 88 | ->expectsQuestion('Which language do you prefer?', 'PHP') 89 | ->expectsOutput('Your name is Taylor Otwell and you prefer PHP.') 90 | ->doesntExpectOutput('Your name is Taylor Otwell and you prefer Ruby.') 91 | ->assertExitCode(0); 92 | } 93 | ``` 94 | 95 | 如果您正在使用 [Laravel Prompts](/docs/{{version}}/prompts) 提供的 `search` 或 `multisearch` 函數,您可以使用 `expectsSearch` 斷言來模擬用戶的輸入、搜索結果和選擇: 96 | 97 | ```php tab=Pest 98 | test('console command', function () { 99 | $this->artisan('example') 100 | ->expectsSearch('What is your name?', search: 'Tay', answers: [ 101 | 'Taylor Otwell', 102 | 'Taylor Swift', 103 | 'Darian Taylor' 104 | ], answer: 'Taylor Otwell') 105 | ->assertExitCode(0); 106 | }); 107 | ``` 108 | 109 | ```php tab=PHPUnit 110 | /** 111 | * Test a console command. 112 | */ 113 | public function test_console_command(): void 114 | { 115 | $this->artisan('example') 116 | ->expectsSearch('What is your name?', search: 'Tay', answers: [ 117 | 'Taylor Otwell', 118 | 'Taylor Swift', 119 | 'Darian Taylor' 120 | ], answer: 'Taylor Otwell') 121 | ->assertExitCode(0); 122 | } 123 | ``` 124 | 125 | 您也可以使用 `doesntExpectOutput` 方法斷言控制台命令不會生成任何輸出: 126 | 127 | ```php tab=Pest 128 | test('console command', function () { 129 | $this->artisan('example') 130 | ->doesntExpectOutput() 131 | ->assertExitCode(0); 132 | }); 133 | ``` 134 | 135 | ```php tab=PHPUnit 136 | /** 137 | * Test a console command. 138 | */ 139 | public function test_console_command(): void 140 | { 141 | $this->artisan('example') 142 | ->doesntExpectOutput() 143 | ->assertExitCode(0); 144 | } 145 | ``` 146 | 147 | `expectsOutputToContain` 和 `doesntExpectOutputToContain` 方法可用於對輸出的一部分進行斷言: 148 | 149 | ```php tab=Pest 150 | test('console command', function () { 151 | $this->artisan('example') 152 | ->expectsOutputToContain('Taylor') 153 | ->assertExitCode(0); 154 | }); 155 | ``` 156 | 157 | ```php tab=PHPUnit 158 | /** 159 | * Test a console command. 160 | */ 161 | public function test_console_command(): void 162 | { 163 | $this->artisan('example') 164 | ->expectsOutputToContain('Taylor') 165 | ->assertExitCode(0); 166 | } 167 | ``` 168 | 169 | 170 | #### 確認斷言 171 | 172 | 當編寫一個需要以 "yes" 或 "no" 答案形式確認的命令時,您可以使用 `expectsConfirmation` 方法: 173 | 174 | ```php 175 | $this->artisan('module:import') 176 | ->expectsConfirmation('您確定要運行此命令嗎?', 'no') 177 | ->assertExitCode(1); 178 | ``` 179 | 180 | 181 | #### 表格斷言 182 | 183 | 如果您的命令使用 Artisan 的 `table` 方法顯示信息表格,為整個表格編寫輸出斷言可能會很繁瑣。相反,您可以使用 `expectsTable` 方法。此方法將表格的標題作為第一個參數,表格的數據作為第二個參數: 184 | 185 | ```php 186 | $this->artisan('users:all') 187 | ->expectsTable([ 188 | 'ID', 189 | 'Email', 190 | ], [ 191 | [1, 'taylor@example.com'], 192 | [2, 'abigail@example.com'], 193 | ]); 194 | ``` 195 | 196 | 197 | ## 終端事件 198 | 199 | 默認情況下,在運行應用程序測試時,不會發送 `Illuminate\Console\Events\CommandStarting` 和 `Illuminate\Console\Events\CommandFinished` 事件。但是,您可以通過將 `Illuminate\Foundation\Testing\WithConsoleEvents` 特性添加到類中來為給定的測試類啟用這些事件: 200 | 201 | ```php tab=Pest 202 | 16 | ## 簡介 17 | 18 | Laravel 的「語境」功能使您能夠在應用程式中的請求、工作和命令執行期間捕獲、擷取和共享資訊。這些捕獲的資訊也包含在應用程式寫入的日誌中,讓您更深入地了解在寫入日誌條目之前發生的周圍程式碼執行歷史,並允許您在分佈式系統中追蹤執行流程。 19 | 20 | 21 | ### 運作方式 22 | 23 | 了解 Laravel 的語境功能的最佳方式是通過使用內建的記錄功能實際操作。要開始,您可以使用 `Context` 門面[添加資訊到語境](#capturing-context)。在此示例中,我們將使用[中介層](/docs/{{version}}/middleware)在每個傳入請求上添加請求 URL 和唯一追蹤 ID 到語境中: 24 | 25 | ```php 26 | url()); 44 | Context::add('trace_id', Str::uuid()->toString()); 45 | 46 | return $next($request); 47 | } 48 | } 49 | ``` 50 | 51 | 添加到語境的資訊會自動附加為任何[日誌條目](/docs/{{version}}/logging)的元資料,這些日誌條目在請求期間寫入。將語境附加為元資料允許將傳遞給個別日誌條目的資訊與通過 `Context` 共享的資訊區分開來。例如,假設我們寫入以下日誌條目: 52 | 53 | ```php 54 | Log::info('User authenticated.', ['auth_id' => Auth::id()]); 55 | ``` 56 | 57 | 寫入的日誌將包含傳遞給日誌條目的 `auth_id`,但它還將包含語境的 `url` 和 `trace_id` 作為元資料: 58 | 59 | ```text 60 | User authenticated. {"auth_id":27} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"} 61 | ``` 62 | 63 | 新增到上下文中的資訊也將提供給調度到佇列的工作。例如,假設我們在將一些資訊新增到上下文後,將 `ProcessPodcast` 工作調度到佇列: 64 | 65 | ```php 66 | // In our middleware... 67 | Context::add('url', $request->url()); 68 | Context::add('trace_id', Str::uuid()->toString()); 69 | 70 | // In our controller... 71 | ProcessPodcast::dispatch($podcast); 72 | ``` 73 | 74 | 當工作被調度時,當前存儲在上下文中的任何資訊都將被捕獲並與工作共享。然後,在執行工作時,捕獲的資訊將被重新注入到當前上下文中。因此,如果我們的工作的處理方法是寫入日誌: 75 | 76 | ```php 77 | class ProcessPodcast implements ShouldQueue 78 | { 79 | use Queueable; 80 | 81 | // ... 82 | 83 | /** 84 | * Execute the job. 85 | */ 86 | public function handle(): void 87 | { 88 | Log::info('Processing podcast.', [ 89 | 'podcast_id' => $this->podcast->id, 90 | ]); 91 | 92 | // ... 93 | } 94 | } 95 | ``` 96 | 97 | 生成的日誌條目將包含在原始調度工作的請求期間新增到上下文中的資訊: 98 | 99 | ```text 100 | 處理播客。{"podcast_id":95} {"url":"https://example.com/login","trace_id":"e04e1a11-e75c-4db3-b5b5-cfef4ef56697"} 101 | ``` 102 | 103 | 儘管我們專注於 Laravel 上下文的內建日誌相關功能,以下文件將說明上下文如何允許您跨 HTTP 請求/佇列工作邊界共享資訊,甚至如何添加[隱藏的上下文資料](#hidden-context),這些資料不會與日誌條目一起寫入。 104 | 105 | 106 | ## 捕獲上下文 107 | 108 | 您可以使用 `Context` 門面的 `add` 方法將資訊存儲在當前上下文中: 109 | 110 | ```php 111 | use Illuminate\Support\Facades\Context; 112 | 113 | Context::add('key', 'value'); 114 | ``` 115 | 116 | 要一次添加多個項目,可以將關聯陣列傳遞給 `add` 方法: 117 | 118 | ```php 119 | Context::add([ 120 | 'first_key' => 'value', 121 | 'second_key' => 'value', 122 | ]); 123 | ``` 124 | 125 | `add` 方法將覆蓋任何具有相同鍵的現有值。如果只希望在鍵不存在時將資訊添加到上下文中,可以使用 `addIf` 方法: 126 | 127 | ```php 128 | Context::add('key', 'first'); 129 | 130 | Context::get('key'); 131 | // "first" 132 | 133 | Context::addIf('key', 'second'); 134 | 135 | Context::get('key'); 136 | // "first" 137 | ``` 138 | 139 | 140 | #### 條件上下文 141 | 142 | `when` 方法可用於根據給定條件向上下文添加資料。提供給 `when` 方法的第一個閉包將在給定條件評估為 `true` 時被調用,而第二個閉包將在條件評估為 `false` 時被調用: 143 | 144 | ```php 145 | use Illuminate\Support\Facades\Auth; 146 | use Illuminate\Support\Facades\Context; 147 | 148 | Context::when( 149 | Auth::user()->isAdmin(), 150 | fn ($context) => $context->add('permissions', Auth::user()->permissions), 151 | fn ($context) => $context->add('permissions', []), 152 | ); 153 | ``` 154 | 155 | 156 | #### 作用域上下文 157 | 158 | `scope` 方法提供了一種在執行給定回呼時暫時修改上下文並在回呼執行完成時將上下文恢復到原始狀態的方法。此外,您可以在閉包執行時傳遞應合併到上下文中的額外數據(作為第二和第三個引數)。 159 | 160 | ```php 161 | use Illuminate\Support\Facades\Context; 162 | use Illuminate\Support\Facades\Log; 163 | 164 | Context::add('trace_id', 'abc-999'); 165 | Context::addHidden('user_id', 123); 166 | 167 | Context::scope( 168 | function () { 169 | Context::add('action', 'adding_friend'); 170 | 171 | $userId = Context::getHidden('user_id'); 172 | 173 | Log::debug("Adding user [{$userId}] to friends list."); 174 | // Adding user [987] to friends list. {"trace_id":"abc-999","user_name":"taylor_otwell","action":"adding_friend"} 175 | }, 176 | data: ['user_name' => 'taylor_otwell'], 177 | hidden: ['user_id' => 987], 178 | ); 179 | 180 | Context::all(); 181 | // [] 182 | 183 | Context::allHidden(); 184 | // [ 185 | // 'user_id' => 123, 186 | // ] 187 | ``` 188 | 189 | > [!WARNING] 190 | > 如果在作用域閉包內修改上下文中的對象,該變異將反映在作用域之外。 191 | 192 | 193 | ### 堆疊 194 | 195 | 上下文提供了創建“堆疊”的能力,這些堆疊是按添加順序存儲的數據列表。您可以通過調用 `push` 方法將信息添加到堆疊中: 196 | 197 | ```php 198 | use Illuminate\Support\Facades\Context; 199 | 200 | Context::push('breadcrumbs', 'first_value'); 201 | 202 | Context::push('breadcrumbs', 'second_value', 'third_value'); 203 | 204 | Context::get('breadcrumbs'); 205 | // [ 206 | // 'first_value', 207 | // 'second_value', 208 | // 'third_value', 209 | // ] 210 | ``` 211 | 212 | 堆疊可用於捕獲有關請求的歷史信息,例如應用程序中正在發生的事件。例如,您可以創建一個事件監聽器,每次執行查詢時都將其推送到堆疊中,將查詢 SQL 和持續時間作為元組捕獲: 213 | 214 | ```php 215 | use Illuminate\Support\Facades\Context; 216 | use Illuminate\Support\Facades\DB; 217 | 218 | DB::listen(function ($event) { 219 | Context::push('queries', [$event->time, $event->sql]); 220 | }); 221 | ``` 222 | 223 | 您可以使用 `stackContains` 和 `hiddenStackContains` 方法確定值是否在堆疊中: 224 | 225 | ```php 226 | if (Context::stackContains('breadcrumbs', 'first_value')) { 227 | // 228 | } 229 | 230 | if (Context::hiddenStackContains('secrets', 'first_value')) { 231 | // 232 | } 233 | ``` 234 | 235 | `stackContains` 和 `hiddenStackContains` 方法還接受閉包作為它們的第二個引數,從而更好地控制值比較操作: 236 | 237 | ```php 238 | use Illuminate\Support\Facades\Context; 239 | use Illuminate\Support\Str; 240 | 241 | return Context::stackContains('breadcrumbs', function ($value) { 242 | return Str::startsWith($value, 'query_'); 243 | }); 244 | ``` 245 | 246 | 247 | ## 檢索上下文 248 | 249 | 您可以使用 `Context` 門面的 `get` 方法從上下文中檢索信息: 250 | 251 | ```php 252 | use Illuminate\Support\Facades\Context; 253 | 254 | $value = Context::get('key'); 255 | ``` 256 | 257 | `only` 方法可用於檢索上下文中信息的子集: 258 | 259 | ```php 260 | $data = Context::only(['first_key', 'second_key']); 261 | ``` 262 | 263 | `pull` 方法可用於從上下文中檢索信息並立即從上下文中刪除它: 264 | 265 | ```php 266 | $value = Context::pull('key'); 267 | ``` 268 | 269 | 如果上下文數據存儲在[堆疊](#stacks)中,您可以使用`pop`方法從堆疊中彈出項目: 270 | 271 | ```php 272 | Context::push('breadcrumbs', 'first_value', 'second_value'); 273 | 274 | Context::pop('breadcrumbs') 275 | // second_value 276 | 277 | Context::get('breadcrumbs'); 278 | // ['first_value'] 279 | ``` 280 | 281 | 如果您想檢索存儲在上下文中的所有信息,可以調用`all`方法: 282 | 283 | ```php 284 | $data = Context::all(); 285 | ``` 286 | 287 | 288 | ### 確定項目存在性 289 | 290 | 您可以使用`has`和`missing`方法來確定上下文是否為給定鍵存儲任何值: 291 | 292 | ```php 293 | use Illuminate\Support\Facades\Context; 294 | 295 | if (Context::has('key')) { 296 | // ... 297 | } 298 | 299 | if (Context::missing('key')) { 300 | // ... 301 | } 302 | ``` 303 | 304 | `has`方法將返回`true`,無論存儲的值是什麼。例如,具有`null`值的鍵將被認為是存在的: 305 | 306 | ```php 307 | Context::add('key', null); 308 | 309 | Context::has('key'); 310 | // true 311 | ``` 312 | 313 | 314 | ## 刪除上下文 315 | 316 | `forget`方法可用於從當前上下文中刪除鍵及其值: 317 | 318 | ```php 319 | use Illuminate\Support\Facades\Context; 320 | 321 | Context::add(['first_key' => 1, 'second_key' => 2]); 322 | 323 | Context::forget('first_key'); 324 | 325 | Context::all(); 326 | 327 | // ['second_key' => 2] 328 | ``` 329 | 330 | 您可以通過向`forget`方法提供一個數組來一次性忘記多個鍵: 331 | 332 | ```php 333 | Context::forget(['first_key', 'second_key']); 334 | ``` 335 | 336 | 337 | ## 隱藏上下文 338 | 339 | 上下文提供了存儲“隱藏”數據的功能。這些隱藏信息不附加到日誌中,也無法通過上面記錄的數據檢索方法訪問。上下文提供了一組不同的方法來與隱藏上下文信息交互: 340 | 341 | ```php 342 | use Illuminate\Support\Facades\Context; 343 | 344 | Context::addHidden('key', 'value'); 345 | 346 | Context::getHidden('key'); 347 | // 'value' 348 | 349 | Context::get('key'); 350 | // null 351 | ``` 352 | 353 | “隱藏”方法與上面記錄的非隱藏方法的功能相同: 354 | 355 | ```php 356 | Context::addHidden(/* ... */); 357 | Context::addHiddenIf(/* ... */); 358 | Context::pushHidden(/* ... */); 359 | Context::getHidden(/* ... */); 360 | Context::pullHidden(/* ... */); 361 | Context::popHidden(/* ... */); 362 | Context::onlyHidden(/* ... */); 363 | Context::allHidden(/* ... */); 364 | Context::hasHidden(/* ... */); 365 | Context::forgetHidden(/* ... */); 366 | ``` 367 | 368 | 369 | ## 事件 370 | 371 | 上下文分發兩個事件,允許您鉤入上下文的水合和脫水過程。 372 | 373 | 為了說明這些事件如何使用,假設在應用程序的中間件中,您根據傳入的HTTP請求的`Accept-Language`標頭設置`app.locale`配置值。上下文的事件允許您在請求期間捕獲此值並在佇列上恢復它,確保在佇列上發送的通知具有正確的`app.locale`值。我們可以使用上下文的事件和[隱藏](#hidden-context)數據來實現這一點,以下文檔將進行說明。 374 | 375 | ### 脫水 376 | 377 | 每當作業被派送到佇列時,上下文中的資料會被「脫水」並與作業的有效載荷一起捕獲。`Context::dehydrating` 方法允許您註冊一個閉包,在脫水過程中將被調用。在這個閉包中,您可以對將與排入佇列的作業共享的資料進行更改。 378 | 379 | 通常,您應該在應用程式的 `AppServiceProvider` 類的 `boot` 方法中註冊 `dehydrating` 回呼: 380 | 381 | ```php 382 | use Illuminate\Log\Context\Repository; 383 | use Illuminate\Support\Facades\Config; 384 | use Illuminate\Support\Facades\Context; 385 | 386 | /** 387 | * Bootstrap any application services. 388 | */ 389 | public function boot(): void 390 | { 391 | Context::dehydrating(function (Repository $context) { 392 | $context->addHidden('locale', Config::get('app.locale')); 393 | }); 394 | } 395 | ``` 396 | 397 | > [!NOTE] 398 | > 您不應在 `dehydrating` 回呼中使用 `Context` 門面,因為這將改變當前處理程序的上下文。請確保您只對傳遞給回呼的存儲庫進行更改。 399 | 400 | ### 水合 401 | 402 | 每當排入佇列的作業開始在佇列上執行時,與作業共享的任何上下文將被「水合」回當前上下文中。`Context::hydrated` 方法允許您註冊一個閉包,在水合過程中將被調用。 403 | 404 | 通常,您應該在應用程式的 `AppServiceProvider` 類的 `boot` 方法中註冊 `hydrated` 回呼: 405 | 406 | ```php 407 | use Illuminate\Log\Context\Repository; 408 | use Illuminate\Support\Facades\Config; 409 | use Illuminate\Support\Facades\Context; 410 | 411 | /** 412 | * Bootstrap any application services. 413 | */ 414 | public function boot(): void 415 | { 416 | Context::hydrated(function (Repository $context) { 417 | if ($context->hasHidden('locale')) { 418 | Config::set('app.locale', $context->getHidden('locale')); 419 | } 420 | }); 421 | } 422 | ``` 423 | 424 | > [!NOTE] 425 | > 您不應在 `hydrated` 回呼中使用 `Context` 門面,而應確保您只對傳遞給回呼的存儲庫進行更改。 426 | -------------------------------------------------------------------------------- /contributions.md: -------------------------------------------------------------------------------- 1 | # 貢獻指南 2 | 3 | - [錯誤報告](#bug-reports) 4 | - [支援問題](#support-questions) 5 | - [核心開發討論](#core-development-discussion) 6 | - [使用哪個分支?](#which-branch) 7 | - [編譯資源檔](#compiled-assets) 8 | - [安全性漏洞](#security-vulnerabilities) 9 | - [程式碼風格](#coding-style) 10 | - [PHPDoc](#phpdoc) 11 | - [StyleCI](#styleci) 12 | - [行為準則](#code-of-conduct) 13 | 14 | 15 | ## 錯誤報告 16 | 17 | 為了鼓勵積極的協作,Laravel 強烈建議使用拉取請求,而不僅僅是錯誤報告。拉取請求只有在標記為「準備好審查」(不是「草稿」狀態)且所有新功能的測試都通過時才會進行審查。留在「草稿」狀態的未活動拉取請求將在幾天後關閉。 18 | 19 | 然而,如果您提交了錯誤報告,您的問題應包含標題和清晰的問題描述。您還應該包含盡可能多的相關信息和展示問題的程式碼示例。錯誤報告的目標是使自己和其他人能夠複製該錯誤並開發修復方案。 20 | 21 | 請記住,錯誤報告是希望其他遇到相同問題的人能夠與您合作解決。不要期望錯誤報告會自動得到任何活動,或者其他人會立即修復它。創建錯誤報告有助於您和其他人開始解決問題的道路。如果您想參與,您可以通過修復[我們問題跟蹤器中列出的任何錯誤](https://github.com/issues?q=is%3Aopen+is%3Aissue+label%3Abug+user%3Alaravel)來幫忙。您必須使用 GitHub 認證才能查看 Laravel 的所有問題。 22 | 23 | 如果您在使用 Laravel 時注意到不當的 DocBlock、PHPStan 或 IDE 警告,請不要建立 GitHub 問題。請提交拉取請求來修復問題。 24 | 25 | Laravel 的原始碼在 GitHub 上管理,每個 Laravel 專案都有對應的存儲庫: 26 | 27 |
28 | 29 | - [Laravel 應用程式](https://github.com/laravel/laravel) 30 | - [Laravel Art](https://github.com/laravel/art) 31 | - [Laravel 文件](https://github.com/laravel/docs) 32 | - [Laravel Dusk](https://github.com/laravel/dusk) 33 | - [Laravel Cashier Stripe](https://github.com/laravel/cashier) 34 | - [Laravel Cashier Paddle](https://github.com/laravel/cashier-paddle) 35 | - [Laravel Echo](https://github.com/laravel/echo) 36 | - [Laravel Envoy](https://github.com/laravel/envoy) 37 | - [Laravel Folio](https://github.com/laravel/folio) 38 | - [Laravel 框架](https://github.com/laravel/framework) 39 | - [Laravel Homestead](https://github.com/laravel/homestead)([建置腳本](https://github.com/laravel/settler)) 40 | - [Laravel Horizon](https://github.com/laravel/horizon) 41 | - [Laravel Livewire Starter Kit](https://github.com/laravel/livewire-starter-kit) 42 | - [Laravel Passport](https://github.com/laravel/passport) 43 | - [Laravel Pennant](https://github.com/laravel/pennant) 44 | - [Laravel Pint](https://github.com/laravel/pint) 45 | - [Laravel Prompts](https://github.com/laravel/prompts) 46 | - [Laravel React Starter Kit](https://github.com/laravel/react-starter-kit) 47 | - [Laravel Reverb](https://github.com/laravel/reverb) 48 | - [Laravel Sail](https://github.com/laravel/sail) 49 | - [Laravel Sanctum](https://github.com/laravel/sanctum) 50 | - [Laravel Scout](https://github.com/laravel/scout) 51 | - [Laravel Socialite](https://github.com/laravel/socialite) 52 | - [Laravel Telescope](https://github.com/laravel/telescope) 53 | - [Laravel Vue Starter Kit](https://github.com/laravel/vue-starter-kit) 54 | - [Laravel 網站](https://github.com/laravel/laravel.com) 55 | 56 | 57 |
58 | 59 | 60 | ## 支援問題 61 | 62 | Laravel 的 GitHub 問題追蹤器並不用於提供 Laravel 的幫助或支援。請改用以下其中一個管道: 63 | 64 |
65 | 66 | - [GitHub 討論區](https://github.com/laravel/framework/discussions) 67 | - [Laracasts 論壇](https://laracasts.com/discuss) 68 | - [Laravel.io 論壇](https://laravel.io/forum) 69 | - [StackOverflow](https://stackoverflow.com/questions/tagged/laravel) 70 | - [Discord](https://discord.gg/laravel) 71 | - [Larachat](https://larachat.co) 72 | - [IRC](https://web.libera.chat/?nick=artisan&channels=#laravel) 73 | 74 |
75 | 76 | 77 | ## 核心開發討論 78 | 79 | 您可以在 Laravel 框架存儲庫的 [GitHub 討論區](https://github.com/laravel/framework/discussions) 中提出新功能或改進現有 Laravel 行為的建議。如果您提出了新功能,請願意實現至少一些完成該功能所需的程式碼。 80 | 81 | 有關錯誤、新功能以及現有功能的實作的非正式討論發生在 [Laravel Discord 伺服器](https://discord.gg/laravel) 的 `#internals` 頻道中。Laravel 的維護者 Taylor Otwell 通常在該頻道中出現於 UTC-06:00 或 America/Chicago 的工作日上午 8 點至下午 5 點,並偶爾在其他時間出現。 82 | 83 | 84 | ## 使用哪個分支? 85 | 86 | **所有** 錯誤修復應發送到支援錯誤修復的最新版本(目前為 `12.x`)。錯誤修復**永遠**不應發送到 `master` 分支,除非它們修復的功能僅存在於即將發布的版本中。 87 | 88 | **次要** 功能,與當前版本完全向後兼容的功能,可以發送到最新的穩定分支(目前為 `12.x`)。 89 | 90 | **主要** 新功能或具有破壞性更改的功能應始終發送到 `master` 分支,其中包含即將發布的版本。 91 | 92 | 93 | ## 編譯資源檔 94 | 95 | 如果您提交的更改會影響編譯文件,例如 `laravel/laravel` 存儲庫中 `resources/css` 或 `resources/js` 中的大多數文件,請不要提交已編譯的文件。由於它們的大小較大,審查者實際上無法審查它們。這可能被利用為將惡意代碼注入 Laravel 的一種方式。為了防禦性地防止這種情況,所有編譯文件將由 Laravel 維護者生成並提交。 96 | 97 | ## 安全漏洞 98 | 99 | 如果您在 Laravel 中發現安全漏洞,請發送郵件給 Taylor Otwell,郵箱為 [taylor@laravel.com](mailto:taylor@laravel.com)。所有安全漏洞將被及時處理。 100 | 101 | ## 編碼風格 102 | 103 | Laravel 遵循 [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) 編碼標準和 [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) 自動加載標準。 104 | 105 | ### PHPDoc 106 | 107 | 以下是一個有效的 Laravel 文件塊示例。請注意,`@param` 屬性後面跟著兩個空格,引數類型,再加兩個空格,最後是變量名: 108 | 109 | ```php 110 | /** 111 | * Register a binding with the container. 112 | * 113 | * @param string|array $abstract 114 | * @param \Closure|string|null $concrete 115 | * @param bool $shared 116 | * @return void 117 | * 118 | * @throws \Exception 119 | */ 120 | public function bind($abstract, $concrete = null, $shared = false) 121 | { 122 | // ... 123 | } 124 | ``` 125 | 126 | 當由於使用原生類型而使 `@param` 或 `@return` 屬性多餘時,可以將其刪除: 127 | 128 | ```php 129 | /** 130 | * Execute the job. 131 | */ 132 | public function handle(AudioProcessor $processor): void 133 | { 134 | // 135 | } 136 | ``` 137 | 138 | 但是,當原生類型是通用的時,請通過使用 `@param` 或 `@return` 屬性來指定通用類型: 139 | 140 | ```php 141 | /** 142 | * Get the attachments for the message. 143 | * 144 | * @return array 145 | */ 146 | public function attachments(): array 147 | { 148 | return [ 149 | Attachment::fromStorage('/path/to/file'), 150 | ]; 151 | } 152 | ``` 153 | 154 | ### StyleCI 155 | 156 | 如果您的代碼風格不完美,不用擔心![StyleCI](https://styleci.io/) 將自動將任何風格修復合併到 Laravel 存儲庫中,以便在合併拉取請求後。這使我們可以專注於貢獻的內容,而不是代碼風格。 157 | 158 | ## 行為準則 159 | 160 | Laravel 的行為準則源自 Ruby 的行為準則。任何違反行為準則的行為都可以向 Taylor Otwell(taylor@laravel.com)舉報: 161 | 162 |
163 | 164 | - 參與者將容忍相反的觀點。 165 | - 參與者必須確保其語言和行為不含人身攻擊和貶低個人的言論。 166 | - 在解釋他人的言行時,參與者應始終假設良好意圖。 167 | - 任何可以合理被視為騷擾的行為將不被容忍。 168 | 169 |
170 | -------------------------------------------------------------------------------- /csrf.md: -------------------------------------------------------------------------------- 1 | # CSRF 保護 2 | 3 | - [簡介](#csrf-introduction) 4 | - [防止 CSRF 請求](#preventing-csrf-requests) 5 | - [排除 URI](#csrf-excluding-uris) 6 | - [X-CSRF-Token](#csrf-x-csrf-token) 7 | - [X-XSRF-Token](#csrf-x-xsrf-token) 8 | 9 | 10 | ## 簡介 11 | 12 | 跨站請求偽造是一種惡意利用的類型,未經授權的命令將代表已驗證的使用者執行。幸運的是,Laravel 讓您可以輕鬆保護應用程式免受 [跨站請求偽造](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) 攻擊。 13 | 14 | 15 | #### 漏洞說明 16 | 17 | 如果您對跨站請求偽造不熟悉,讓我們討論一個示例,說明這種漏洞如何被利用。想像一下,您的應用程式有一個 `/user/email` 路由,接受 `POST` 請求以更改已驗證使用者的電子郵件地址。很可能,這個路由期望一個 `email` 輸入欄位包含使用者想要開始使用的電子郵件地址。 18 | 19 | 如果沒有 CSRF 保護,一個惡意網站可以創建一個 HTML 表單,指向您應用程式的 `/user/email` 路由,並提交惡意使用者自己的電子郵件地址: 20 | 21 | ```blade 22 |
23 | 24 |
25 | 26 | 29 | ``` 30 | 31 | 如果惡意網站在頁面加載時自動提交表單,那麼惡意使用者只需誘導您應用程式的一個無憂無慮的使用者訪問他們的網站,他們的電子郵件地址將在您的應用程式中被更改。 32 | 33 | 為了防止這種漏洞,我們需要檢查每個傳入的 `POST`、`PUT`、`PATCH` 或 `DELETE` 請求,以確保惡意應用程式無法訪問的秘密會話值。 34 | 35 | 36 | ## 防止 CSRF 請求 37 | 38 | Laravel 自動為應用程式管理的每個活動 [使用者會話](/docs/{{version}}/session) 生成一個 CSRF「標記」。此標記用於驗證已驗證使用者是否實際在對應用程式進行請求。由於此標記存儲在使用者的會話中,並且每次會話重新生成時都會更改,惡意應用程式無法訪問它。 39 | 40 | 當前會話的 CSRF 標記可以通過請求的會話或通過 `csrf_token` 輔助函式來訪問: 41 | 42 | ```php 43 | use Illuminate\Http\Request; 44 | 45 | Route::get('/token', function (Request $request) { 46 | $token = $request->session()->token(); 47 | 48 | $token = csrf_token(); 49 | 50 | // ... 51 | }); 52 | ``` 53 | 54 | 每當您在應用程式中定義一個 "POST"、"PUT"、"PATCH" 或 "DELETE" HTML 表單時,應該在表單中包含一個隱藏的 CSRF `_token` 欄位,以便 CSRF 保護中介層可以驗證請求。為了方便起見,您可以使用 `@csrf` Blade 指示詞來生成隱藏的標記輸入欄位: 55 | 56 | ```blade 57 |
58 | @csrf 59 | 60 | 61 | 62 |
63 | ``` 64 | 65 | `Illuminate\Foundation\Http\Middleware\ValidateCsrfToken` [中介層](/docs/{{version}}/middleware),預設包含在 `web` 中介層組中,將自動驗證請求輸入中的標記是否與會話中存儲的標記匹配。當這兩個標記匹配時,我們知道認證的使用者是發起請求的人。 66 | 67 | 68 | ### CSRF 標記與 SPA 69 | 70 | 如果您正在構建一個將 Laravel 作為 API 後端的 SPA,您應該參考 [Laravel Sanctum 文件](/docs/{{version}}/sanctum) 以獲取有關如何使用 API 進行身份驗證並防範 CSRF 漏洞的信息。 71 | 72 | 73 | ### 從 CSRF 保護中排除 URIs 74 | 75 | 有時您可能希望從 CSRF 保護中排除一組 URIs。例如,如果您正在使用 [Stripe](https://stripe.com) 來處理付款並且正在使用他們的 Webhooks 系統,則需要從 CSRF 保護中排除您的 Stripe Webhook 處理程序路由,因為 Stripe 不知道要發送到您路由的 CSRF 標記。 76 | 77 | 通常,您應將這些類型的路由放在 Laravel 應用程式中的 `routes/web.php` 文件中 Laravel 應用程式應用於所有路由的 `web` 中介層組之外。但是,您也可以通過在應用程式的 `bootstrap/app.php` 文件中向 `validateCsrfTokens` 方法提供它們的 URIs 來排除特定路由: 78 | 79 | ```php 80 | ->withMiddleware(function (Middleware $middleware) { 81 | $middleware->validateCsrfTokens(except: [ 82 | 'stripe/*', 83 | 'http://example.com/foo/bar', 84 | 'http://example.com/foo/*', 85 | ]); 86 | }) 87 | ``` 88 | 89 | > [!NOTE] 90 | > 為了方便起見,在 [運行測試](/docs/{{version}}/testing) 時,所有路由的 CSRF 中介層將自動禁用。 91 | 92 | 93 | 94 | ## X-CSRF-TOKEN 95 | 96 | 除了檢查 CSRF 權杖作為 POST 參數外,`Illuminate\Foundation\Http\Middleware\ValidateCsrfToken` 中介層(預設包含在 `web` 中介層組中)還會檢查 `X-CSRF-TOKEN` 請求標頭。例如,您可以將權杖存儲在 HTML 的 `meta` 標籤中: 97 | 98 | ```blade 99 | 100 | ``` 101 | 102 | 然後,您可以指示像 jQuery 這樣的庫自動將權杖添加到所有請求標頭中。這為使用傳統 JavaScript 技術的 AJAX 應用程序提供了簡單、方便的 CSRF 保護: 103 | 104 | ```js 105 | $.ajaxSetup({ 106 | headers: { 107 | 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') 108 | } 109 | }); 110 | ``` 111 | 112 | 113 | ## X-XSRF-TOKEN 114 | 115 | Laravel 將當前的 CSRF 權杖存儲在加密的 `XSRF-TOKEN` Cookie 中,該 Cookie 包含在框架生成的每個回應中。您可以使用 Cookie 值來設置 `X-XSRF-TOKEN` 請求標頭。 116 | 117 | 這個 Cookie 主要作為開發者的方便,因為一些 JavaScript 框架和庫(如 Angular 和 Axios)會自動將其值放在同源請求的 `X-XSRF-TOKEN` 標頭中。 118 | 119 | > [!NOTE] 120 | > 默認情況下,`resources/js/bootstrap.js` 文件包含 Axios HTTP 库,它將自動為您發送 `X-XSRF-TOKEN` 標頭。 121 | -------------------------------------------------------------------------------- /database-testing.md: -------------------------------------------------------------------------------- 1 | # 資料庫測試 2 | 3 | - [簡介](#introduction) 4 | - [每次測試後重置資料庫](#resetting-the-database-after-each-test) 5 | - [模型工廠](#model-factories) 6 | - [執行 Seeder](#running-seeders) 7 | - [可用的斷言](#available-assertions) 8 | 9 | 10 | ## 簡介 11 | 12 | Laravel 提供了各種有用的工具和斷言,使得測試基於資料庫的應用程式更加容易。此外,Laravel 模型工廠和 Seeder 讓您可以輕鬆地使用應用程式的 Eloquent 模型和關聯來建立測試資料庫記錄。我們將在以下文件中討論所有這些強大的功能。 13 | 14 | 15 | ### 每次測試後重置資料庫 16 | 17 | 在繼續進一步之前,讓我們討論如何在每次測試後重置您的資料庫,以免前一個測試的資料干擾後續的測試。Laravel 包含的 `Illuminate\Foundation\Testing\RefreshDatabase` 特性將為您處理這個問題。只需在您的測試類別中使用這個特性: 18 | 19 | ```php tab=Pest 20 | get('/'); 28 | 29 | // ... 30 | }); 31 | ``` 32 | 33 | ```php tab=PHPUnit 34 | get('/'); 51 | 52 | // ... 53 | } 54 | } 55 | ``` 56 | 57 | `Illuminate\Foundation\Testing\RefreshDatabase` 特性不會遷移您的資料庫,如果您的架構是最新的。相反,它只會在資料庫交易中執行測試。因此,任何由不使用此特性的測試案例添加到資料庫的記錄可能仍然存在於資料庫中。 58 | 59 | 如果您想完全重置資料庫,您可以改用 `Illuminate\Foundation\Testing\DatabaseMigrations` 或 `Illuminate\Foundation\Testing\DatabaseTruncation` 特性。不過,這兩個選項的速度比 `RefreshDatabase` 特性慢得多。 60 | 61 | 62 | ## 模型工廠 63 | 64 | 在進行測試時,您可能需要在執行測試之前將一些記錄插入您的資料庫。而不是在建立這些測試資料時手動指定每個欄位的值,Laravel 允許您為每個 [Eloquent 模型](/docs/{{version}}/eloquent) 定義一組預設屬性,使用 [模型工廠](/docs/{{version}}/eloquent-factories)。 65 | 66 | 要了解如何建立和利用模型工廠來建立模型,請參考完整的[model factory documentation](/docs/{{version}}/eloquent-factories)。一旦您定義了一個模型工廠,您可以在測試中使用工廠來建立模型: 67 | 68 | ```php tab=Pest 69 | use App\Models\User; 70 | 71 | test('models can be instantiated', function () { 72 | $user = User::factory()->create(); 73 | 74 | // ... 75 | }); 76 | ``` 77 | 78 | ```php tab=PHPUnit 79 | use App\Models\User; 80 | 81 | public function test_models_can_be_instantiated(): void 82 | { 83 | $user = User::factory()->create(); 84 | 85 | // ... 86 | } 87 | ``` 88 | 89 | 90 | ## 執行 Seeders 91 | 92 | 如果您想在功能測試期間使用[資料庫 seeders](/docs/{{version}}/seeding)來填充您的資料庫,您可以調用 `seed` 方法。預設情況下,`seed` 方法將執行 `DatabaseSeeder`,該類應該執行您的所有其他 seeders。或者,您可以將特定的 seeder 類名傳遞給 `seed` 方法: 93 | 94 | ```php tab=Pest 95 | seed(); 106 | 107 | // Run a specific seeder... 108 | $this->seed(OrderStatusSeeder::class); 109 | 110 | // ... 111 | 112 | // Run an array of specific seeders... 113 | $this->seed([ 114 | OrderStatusSeeder::class, 115 | TransactionStatusSeeder::class, 116 | // ... 117 | ]); 118 | }); 119 | ``` 120 | 121 | ```php tab=PHPUnit 122 | seed(); 142 | 143 | // Run a specific seeder... 144 | $this->seed(OrderStatusSeeder::class); 145 | 146 | // ... 147 | 148 | // Run an array of specific seeders... 149 | $this->seed([ 150 | OrderStatusSeeder::class, 151 | TransactionStatusSeeder::class, 152 | // ... 153 | ]); 154 | } 155 | } 156 | ``` 157 | 158 | 或者,您可以指示 Laravel 在每次使用 `RefreshDatabase` 特性的測試之前自動填充資料庫。您可以通過在基本測試類上定義一個 `$seed` 屬性來完成這一點: 159 | 160 | ```php 161 | 192 | ## 可用斷言 193 | 194 | Laravel 為您的[Pest](https://pestphp.com)或[PHPUnit](https://phpunit.de)功能測試提供了幾個資料庫斷言。我們將在下面討論每個斷言。 195 | 196 | 197 | #### assertDatabaseCount 198 | 199 | 斷言資料庫中的表包含給定數量的記錄: 200 | 201 | ```php 202 | $this->assertDatabaseCount('users', 5); 203 | ``` 204 | 205 | 206 | #### assertDatabaseEmpty 207 | 208 | 斷言資料庫中的表不包含記錄: 209 | 210 | ```php 211 | $this->assertDatabaseEmpty('users'); 212 | ``` 213 | 214 | 215 | #### assertDatabaseHas 216 | 217 | 確認資料庫中的表格包含符合給定鍵/值查詢條件的記錄: 218 | 219 | ```php 220 | $this->assertDatabaseHas('users', [ 221 | 'email' => 'sally@example.com', 222 | ]); 223 | ``` 224 | 225 | 226 | #### assertDatabaseMissing 227 | 228 | 確認資料庫中的表格不包含符合給定鍵/值查詢條件的記錄: 229 | 230 | ```php 231 | $this->assertDatabaseMissing('users', [ 232 | 'email' => 'sally@example.com', 233 | ]); 234 | ``` 235 | 236 | 237 | #### assertSoftDeleted 238 | 239 | `assertSoftDeleted` 方法可用於斷言給定的 Eloquent 模型已被「軟刪除」: 240 | 241 | ```php 242 | $this->assertSoftDeleted($user); 243 | ``` 244 | 245 | 246 | #### assertNotSoftDeleted 247 | 248 | `assertNotSoftDeleted` 方法可用於斷言給定的 Eloquent 模型尚未被「軟刪除」: 249 | 250 | ```php 251 | $this->assertNotSoftDeleted($user); 252 | ``` 253 | 254 | 255 | #### assertModelExists 256 | 257 | 斷言資料庫中存在給定的模型: 258 | 259 | ```php 260 | use App\Models\User; 261 | 262 | $user = User::factory()->create(); 263 | 264 | $this->assertModelExists($user); 265 | ``` 266 | 267 | 268 | #### assertModelMissing 269 | 270 | 斷言資料庫中不存在給定的模型: 271 | 272 | ```php 273 | use App\Models\User; 274 | 275 | $user = User::factory()->create(); 276 | 277 | $user->delete(); 278 | 279 | $this->assertModelMissing($user); 280 | ``` 281 | 282 | 283 | #### expectsDatabaseQueryCount 284 | 285 | `expectsDatabaseQueryCount` 方法可在測試開始時調用,以指定預期在測試過程中要執行的總數資料庫查詢次數。如果實際執行的查詢次數與預期不完全匹配,測試將失敗: 286 | 287 | ```php 288 | $this->expectsDatabaseQueryCount(5); 289 | 290 | // 測試... 291 | ``` 292 | -------------------------------------------------------------------------------- /deployment.md: -------------------------------------------------------------------------------- 1 | # 部署 2 | 3 | - [簡介](#introduction) 4 | - [伺服器需求](#server-requirements) 5 | - [伺服器設定](#server-configuration) 6 | - [Nginx](#nginx) 7 | - [FrankenPHP](#frankenphp) 8 | - [目錄權限](#directory-permissions) 9 | - [優化](#optimization) 10 | - [快取設定](#optimizing-configuration-loading) 11 | - [快取事件](#caching-events) 12 | - [快取路由](#optimizing-route-loading) 13 | - [快取視圖](#optimizing-view-loading) 14 | - [偵錯模式](#debug-mode) 15 | - [健康路由](#the-health-route) 16 | - [使用 Laravel Cloud 或 Forge 部署](#deploying-with-cloud-or-forge) 17 | 18 | 19 | ## 簡介 20 | 21 | 當您準備將您的 Laravel 應用程式部署到正式環境時,有一些重要的事項可以確保您的應用程式運行效率最大化。在本文件中,我們將介紹一些確保您的 Laravel 應用程式正確部署的重要起點。 22 | 23 | 24 | ## 伺服器需求 25 | 26 | Laravel 框架有一些系統需求。您應確保您的網頁伺服器具備以下最低 PHP 版本和擴充功能: 27 | 28 |
29 | 30 | - PHP >= 8.2 31 | - Ctype PHP 擴充功能 32 | - cURL PHP 擴充功能 33 | - DOM PHP 擴充功能 34 | - Fileinfo PHP 擴充功能 35 | - Filter PHP 擴充功能 36 | - Hash PHP 擴充功能 37 | - Mbstring PHP 擴充功能 38 | - OpenSSL PHP 擴充功能 39 | - PCRE PHP 擴充功能 40 | - PDO PHP 擴充功能 41 | - Session PHP 擴充功能 42 | - Tokenizer PHP 擴充功能 43 | - XML PHP 擴充功能 44 | 45 |
46 | 47 | 48 | ## 伺服器設定 49 | 50 | 51 | ### Nginx 52 | 53 | 如果您將應用程式部署到運行 Nginx 的伺服器,您可以使用以下配置文件作為配置網頁伺服器的起點。很可能,根據您的伺服器配置,這個文件需要進行自定義。**如果您需要協助管理伺服器,考慮使用像 [Laravel Cloud](https://cloud.laravel.com) 這樣的完全管理的 Laravel 平台。** 54 | 55 | 請確保像下面的配置一樣,您的網頁伺服器將所有請求導向到您的應用程式的 `public/index.php` 檔案。您絕不應試圖將 `index.php` 檔案移至專案根目錄,因為從專案根目錄提供應用程式將會將許多敏感配置檔案暴露給公共網際網路: 56 | 57 | ```nginx 58 | server { 59 | listen 80; 60 | listen [::]:80; 61 | server_name example.com; 62 | root /srv/example.com/public; 63 | 64 | add_header X-Frame-Options "SAMEORIGIN"; 65 | add_header X-Content-Type-Options "nosniff"; 66 | 67 | index index.php; 68 | 69 | charset utf-8; 70 | 71 | location / { 72 | try_files $uri $uri/ /index.php?$query_string; 73 | } 74 | 75 | location = /favicon.ico { access_log off; log_not_found off; } 76 | location = /robots.txt { access_log off; log_not_found off; } 77 | 78 | error_page 404 /index.php; 79 | 80 | location ~ ^/index\.php(/|$) { 81 | fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; 82 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; 83 | include fastcgi_params; 84 | fastcgi_hide_header X-Powered-By; 85 | } 86 | 87 | location ~ /\.(?!well-known).* { 88 | deny all; 89 | } 90 | } 91 | ``` 92 | 93 | 94 | ### FrankenPHP 95 | 96 | [FrankenPHP](https://frankenphp.dev/) 也可以用來提供 Laravel 應用程式的服務。FrankenPHP 是一個用 Go 語言編寫的現代 PHP 應用伺服器。要使用 FrankenPHP 來提供 Laravel PHP 應用程式的服務,您只需呼叫其 `php-server` 指令: 97 | 98 | ```shell 99 | frankenphp php-server -r public/ 100 | ``` 101 | 102 | 要利用 FrankenPHP 支援的更強大功能,例如其 [Laravel Octane](/docs/{{version}}/octane) 整合、HTTP/3、現代壓縮,或將 Laravel 應用程式打包為獨立二進位檔,請參考 FrankenPHP 的 [Laravel 文件](https://frankenphp.dev/docs/laravel/)。 103 | 104 | 105 | ### 目錄權限 106 | 107 | Laravel 需要寫入 `bootstrap/cache` 和 `storage` 目錄,因此您應確保網頁伺服器進程擁有寫入這些目錄的權限。 108 | 109 | 110 | ## 優化 111 | 112 | 在將應用程式部署到正式環境時,應該將各種檔案進行快取,包括您的組態、事件、路由和視圖。Laravel 提供了一個方便的 `optimize` Artisan 指令,將快取所有這些檔案。這個指令通常應該作為應用程式部署過程的一部分來呼叫: 113 | 114 | ```shell 115 | php artisan optimize 116 | ``` 117 | 118 | `optimize:clear` 方法可用於刪除 `optimize` 指令生成的所有快取檔案以及預設快取驅動程式中的所有金鑰: 119 | 120 | ```shell 121 | php artisan optimize:clear 122 | ``` 123 | 124 | 在接下來的文件中,我們將討論 `optimize` 指令執行的每個細粒度優化指令。 125 | 126 | 127 | ### 快取組態 128 | 129 | 在將應用程式部署到正式環境時,您應該確保在部署過程中執行 `config:cache` Artisan 指令: 130 | 131 | ```shell 132 | php artisan config:cache 133 | ``` 134 | 135 | 此指令將所有 Laravel 的組態檔案合併為一個快取檔案,大大減少了框架在載入組態值時必須對檔案系統進行的查詢次數。 136 | 137 | 138 | > [!WARNING] 139 | > 如果您在部署過程中執行 `config:cache` 命令,請確保您只在配置文件中調用 `env` 函數。一旦配置被快取,`.env` 文件將不會被加載,對於 `.env` 變數的所有 `env` 函數調用將返回 `null`。 140 | 141 | 142 | ### 快取事件 143 | 144 | 您應該在部署過程中將應用程序自動發現的事件到監聽器映射進行快取。這可以通過在部署期間調用 `event:cache` Artisan 命令來完成: 145 | 146 | ```shell 147 | php artisan event:cache 148 | ``` 149 | 150 | 151 | ### 快取路由 152 | 153 | 如果您正在構建具有許多路由的大型應用程序,請確保在部署過程中運行 `route:cache` Artisan 命令: 154 | 155 | ```shell 156 | php artisan route:cache 157 | ``` 158 | 159 | 此命令將所有路由註冊縮減為一個方法調用在一個快取文件中,當註冊數百個路由時,將提高路由註冊的性能。 160 | 161 | 162 | ### 快取視圖 163 | 164 | 在將應用程序部署到正式環境時,請確保在部署過程中運行 `view:cache` Artisan 命令: 165 | 166 | ```shell 167 | php artisan view:cache 168 | ``` 169 | 170 | 此命令預編譯所有您的 Blade 視圖,因此它們不會按需編譯,提高每個返回視圖的請求的性能。 171 | 172 | 173 | ## 調試模式 174 | 175 | 您的 `config/app.php` 配置文件中的調試選項決定了實際向用戶顯示有關錯誤的信息量。默認情況下,此選項設置為尊重 `APP_DEBUG` 環境變量的值,該值存儲在應用程序的 `.env` 文件中。 176 | 177 | > [!WARNING] 178 | > **在您的正式環境中,此值應始終為 `false`。如果在正式環境中將 `APP_DEBUG` 變量設置為 `true`,則有風險將敏感配置值暴露給應用程序的最終用戶。** 179 | 180 | 181 | ## 健康路由 182 | 183 | Laravel 包含一個內建的健康檢查路由,可用於監控應用程式的狀態。在正式環境中,此路由可用於向正常運行監控器、負載平衡器或 Kubernetes 等協調系統報告應用程式的狀態。 184 | 185 | 預設情況下,健康檢查路由位於 `/up`,如果應用程式已經啟動且沒有異常,將返回 200 的 HTTP 回應。否則,將返回 500 的 HTTP 回應。您可以在應用程式的 `bootstrap/app` 檔案中配置此路由的 URI: 186 | 187 | ```php 188 | ->withRouting( 189 | web: __DIR__.'/../routes/web.php', 190 | commands: __DIR__.'/../routes/console.php', 191 | health: '/up', // [tl! remove] 192 | health: '/status', // [tl! add] 193 | ) 194 | ``` 195 | 196 | 當對此路由進行 HTTP 請求時,Laravel 還會發送一個 `Illuminate\Foundation\Events\DiagnosingHealth` 事件,讓您可以執行與應用程式相關的其他健康檢查。在此事件的 [監聽器](/docs/{{version}}/events) 中,您可以檢查應用程式的資料庫或快取狀態。如果您發現應用程式存在問題,只需從監聽器中拋出一個例外。 197 | 198 | 199 | ## 使用 Laravel Cloud 或 Forge 部署 200 | 201 | 202 | #### Laravel Cloud 203 | 204 | 如果您想要一個針對 Laravel 進行調整的全自動擴展部署平台,請查看 [Laravel Cloud](https://cloud.laravel.com)。Laravel Cloud 是一個強大的 Laravel 部署平台,提供管理的計算、資料庫、快取和物件儲存。 205 | 206 | 在 Cloud 上啟動您的 Laravel 應用程式,並愛上可擴展的簡單性。Laravel Cloud 經 Laravel 的創作者精心調校,以便與框架無縫配合,讓您可以像以前一樣繼續撰寫 Laravel 應用程式。 207 | 208 | 209 | #### Laravel Forge 210 | 211 | 如果您更喜歡管理自己的伺服器,但不熟悉配置運行強大 Laravel 應用程式所需的各種服務,[Laravel Forge](https://forge.laravel.com) 是一個針對 Laravel 應用程式的 VPS 伺服器管理平台。 212 | 213 | Laravel Forge 可在各種基礎設施提供者上創建伺服器,如 DigitalOcean、Linode、AWS 等。此外,Forge 安裝並管理構建強大 Laravel 應用程式所需的所有工具,如 Nginx、MySQL、Redis、Memcached、Beanstalk 等。 214 | 215 | I'm ready to translate. Please paste the Markdown content for me to work on. 216 | -------------------------------------------------------------------------------- /documentation.md: -------------------------------------------------------------------------------- 1 | - ## 序言 2 | - [發行說明](/docs/{{version}}/releases) 3 | - [升級指南](/docs/{{version}}/upgrade) 4 | - [貢獻指南](/docs/{{version}}/contributions) 5 | - ## 入門指南 6 | - [安裝](/docs/{{version}}/installation) 7 | - [配置](/docs/{{version}}/configuration) 8 | - [目錄結構](/docs/{{version}}/structure) 9 | - [前端](/docs/{{version}}/frontend) 10 | - [入門套件](/docs/{{version}}/starter-kits) 11 | - [部署](/docs/{{version}}/deployment) 12 | - ## 架構概念 13 | - [請求生命週期](/docs/{{version}}/lifecycle) 14 | - [服務容器](/docs/{{version}}/container) 15 | - [服務提供者](/docs/{{version}}/providers) 16 | - [Facades](/docs/{{version}}/facades) 17 | - ## 基礎知識 18 | - [路由](/docs/{{version}}/routing) 19 | - [中介層](/docs/{{version}}/middleware) 20 | - [CSRF 保護](/docs/{{version}}/csrf) 21 | - [控制器](/docs/{{version}}/controllers) 22 | - [請求](/docs/{{version}}/requests) 23 | - [回應](/docs/{{version}}/responses) 24 | - [視圖](/docs/{{version}}/views) 25 | - [Blade 模板](/docs/{{version}}/blade) 26 | - [資源檔捆綁](/docs/{{version}}/vite) 27 | - [URL 生成](/docs/{{version}}/urls) 28 | - [Session](/docs/{{version}}/session) 29 | - [確認](/docs/{{version}}/validation) 30 | - [錯誤處理](/docs/{{version}}/errors) 31 | - [記錄](/docs/{{version}}/logging) 32 | - ## 深入探討 33 | - [Artisan 指令列](/docs/{{version}}/artisan) 34 | - [廣播](/docs/{{version}}/broadcasting) 35 | - [快取](/docs/{{version}}/cache) 36 | - [集合](/docs/{{version}}/collections) 37 | - [並發](/docs/{{version}}/concurrency) 38 | - [上下文](/docs/{{version}}/context) 39 | - [合約](/docs/{{version}}/contracts) 40 | - [事件](/docs/{{version}}/events) 41 | - [檔案儲存](/docs/{{version}}/filesystem) 42 | - [輔助函式](/docs/{{version}}/helpers) 43 | - [HTTP 客戶端](/docs/{{version}}/http-client) 44 | - [本地化](/docs/{{version}}/localization) 45 | - [郵件](/docs/{{version}}/mail) 46 | - [通知](/docs/{{version}}/notifications) 47 | - [套件開發](/docs/{{version}}/packages) 48 | - [進程](/docs/{{version}}/processes) 49 | - [佇列](/docs/{{version}}/queues) 50 | - [速率限制](/docs/{{version}}/rate-limiting) 51 | - [字串](/docs/{{version}}/strings) 52 | - [任務排程](/docs/{{version}}/scheduling) 53 | - ## 安全性 54 | - [認證](/docs/{{version}}/authentication) 55 | - [授權](/docs/{{version}}/authorization) 56 | - [電子郵件驗證](/docs/{{version}}/verification) 57 | - [加密](/docs/{{version}}/encryption) 58 | - [雜湊](/docs/{{version}}/hashing) 59 | - [重設密碼](/docs/{{version}}/passwords) 60 | - ## 資料庫 61 | - [入門指南](/docs/{{version}}/database) 62 | - [查詢產生器](/docs/{{version}}/queries) 63 | - [分頁](/docs/{{version}}/pagination) 64 | - [遷移](/docs/{{version}}/migrations) 65 | - [資料填充](/docs/{{version}}/seeding) 66 | - [Redis](/docs/{{version}}/redis) 67 | - [MongoDB](/docs/{{version}}/mongodb) 68 | - ## Eloquent ORM 69 | - [入門指南](/docs/{{version}}/eloquent) 70 | - [關聯](/docs/{{version}}/eloquent-relationships) 71 | - [集合](/docs/{{version}}/eloquent-collections) 72 | - [賦值器 / 轉換器](/docs/{{version}}/eloquent-mutators) 73 | - [API 資源](/docs/{{version}}/eloquent-resources) 74 | - [序列化](/docs/{{version}}/eloquent-serialization) 75 | - [工廠](/docs/{{version}}/eloquent-factories) 76 | - ## 測試 77 | - [入門指南](/docs/{{version}}/testing) 78 | - [HTTP 測試](/docs/{{version}}/http-tests) 79 | - [指令列測試](/docs/{{version}}/console-tests) 80 | - [瀏覽器測試](/docs/{{version}}/dusk) 81 | - [資料庫](/docs/{{version}}/database-testing) 82 | - [模擬](/docs/{{version}}/mocking) 83 | - ## 套件 84 | - [Cashier (Stripe)](/docs/{{version}}/billing) 85 | - [Cashier (Paddle)](/docs/{{version}}/cashier-paddle) 86 | - [Dusk](/docs/{{version}}/dusk) 87 | - [Envoy](/docs/{{version}}/envoy) 88 | - [Fortify](/docs/{{version}}/fortify) 89 | - [Folio](/docs/{{version}}/folio) 90 | - [Homestead](/docs/{{version}}/homestead) 91 | - [Horizon](/docs/{{version}}/horizon) 92 | - [Mix](/docs/{{version}}/mix) 93 | - [Octane](/docs/{{version}}/octane) 94 | - [Passport](/docs/{{version}}/passport) 95 | - [Pennant](/docs/{{version}}/pennant) 96 | - [Pint](/docs/{{version}}/pint) 97 | - [Precognition](/docs/{{version}}/precognition) 98 | - [Prompts](/docs/{{version}}/prompts) 99 | - [Pulse](/docs/{{version}}/pulse) 100 | - [Reverb](/docs/{{version}}/reverb) 101 | - [Sail](/docs/{{version}}/sail) 102 | - [Sanctum](/docs/{{version}}/sanctum) 103 | - [Scout](/docs/{{version}}/scout) 104 | - [Socialite](/docs/{{version}}/socialite) 105 | - [Telescope](/docs/{{version}}/telescope) 106 | - [Valet](/docs/{{version}}/valet) 107 | - [API 文件](https://api.laravel.com/docs/12.x) 108 | 109 | I'm ready to translate. Please paste the Markdown content for me to work on. 110 | -------------------------------------------------------------------------------- /eloquent-collections.md: -------------------------------------------------------------------------------- 1 | # Eloquent: 集合 2 | 3 | - [簡介](#introduction) 4 | - [可用方法](#available-methods) 5 | - [自訂集合](#custom-collections) 6 | 7 | 8 | ## 簡介 9 | 10 | 所有返回多個模型結果的 Eloquent 方法將返回 `Illuminate\Database\Eloquent\Collection` 類的實例,包括通過 `get` 方法檢索的結果或通過關聯訪問的結果。Eloquent 集合物件擴展了 Laravel 的[基本集合](/docs/{{version}}/collections),因此自然繼承了數十種用於流暢處理底層 Eloquent 模型陣列的方法。請務必查看 Laravel 集合文件以了解所有這些有用的方法! 11 | 12 | 所有集合也作為迭代器,允許您像簡單的 PHP 陣列一樣對它們進行循環: 13 | 14 | ```php 15 | use App\Models\User; 16 | 17 | $users = User::where('active', 1)->get(); 18 | 19 | foreach ($users as $user) { 20 | echo $user->name; 21 | } 22 | ``` 23 | 24 | 然而,如前所述,集合比陣列強大得多,並公開了各種映射/減少操作,可以使用直觀的界面進行鏈接。例如,我們可以刪除所有非活動模型,然後為每個剩餘用戶收集名字: 25 | 26 | ```php 27 | $names = User::all()->reject(function (User $user) { 28 | return $user->active === false; 29 | })->map(function (User $user) { 30 | return $user->name; 31 | }); 32 | ``` 33 | 34 | 35 | #### Eloquent 集合轉換 36 | 37 | 雖然大多數 Eloquent 集合方法返回 Eloquent 集合的新實例,但 `collapse`、`flatten`、`flip`、`keys`、`pluck` 和 `zip` 方法返回一個[基本集合](/docs/{{version}}/collections)實例。同樣,如果 `map` 操作返回一個不包含任何 Eloquent 模型的集合,它將被轉換為基本集合實例。 38 | 39 | 40 | ## 可用方法 41 | 42 | 所有 Eloquent 集合都擴展了基本的[Laravel 集合](/docs/{{version}}/collections#available-methods)物件;因此,它們繼承了基本集合類提供的所有強大方法。 43 | 44 | 此外,`Illuminate\Database\Eloquent\Collection` 類提供了一組方法的超集,以幫助管理您的模型集合。大多數方法返回 `Illuminate\Database\Eloquent\Collection` 實例;但是,一些方法,如 `modelKeys`,返回一個 `Illuminate\Support\Collection` 實例。 45 | 46 | ```html 47 | 67 | 68 |
69 | 70 | [append](#method-append) 71 | [contains](#method-contains) 72 | [diff](#method-diff) 73 | [except](#method-except) 74 | [find](#method-find) 75 | [findOrFail](#method-find-or-fail) 76 | [fresh](#method-fresh) 77 | [intersect](#method-intersect) 78 | [load](#method-load) 79 | [loadMissing](#method-loadMissing) 80 | [modelKeys](#method-modelKeys) 81 | [makeVisible](#method-makeVisible) 82 | [makeHidden](#method-makeHidden) 83 | [only](#method-only) 84 | [setVisible](#method-setVisible) 85 | [setHidden](#method-setHidden) 86 | [toQuery](#method-toquery) 87 | [unique](#method-unique) 88 | 89 |
90 | 91 | 92 | #### `append($attributes)` {.collection-method .first-collection-method} 93 | 94 | `append` 方法可用於指示應為集合中的每個模型附加的屬性。此方法接受一個屬性數組或單個屬性: 95 | 96 | ```php 97 | $users->append('team'); 98 | 99 | $users->append(['team', 'is_admin']); 100 | ``` 101 | 102 | 103 | #### `contains($key, $operator = null, $value = null)` {.collection-method} 104 | 105 | `contains` 方法可用於確定集合中是否包含給定的模型實例。此方法接受主鍵或模型實例: 106 | 107 | ```php 108 | $users->contains(1); 109 | 110 | $users->contains(User::find(1)); 111 | ``` 112 | 113 | 114 | #### `diff($items)` {.collection-method} 115 | 116 | `diff` 方法返回不在給定集合中的所有模型: 117 | 118 | ```php 119 | use App\Models\User; 120 | 121 | $users = $users->diff(User::whereIn('id', [1, 2, 3])->get()); 122 | ``` 123 | 124 | 125 | #### `except($keys)` {.collection-method} 126 | ``` 127 | 128 | `except` 方法返回所有不具有給定主鍵的模型: 129 | 130 | ```php 131 | $users = $users->except([1, 2, 3]); 132 | ``` 133 | 134 | 135 | #### `find($key)` {.collection-method} 136 | 137 | `find` 方法返回具有與給定鍵匹配的主鍵的模型。如果 `$key` 是模型實例,`find` 將嘗試返回與主鍵匹配的模型。如果 `$key` 是一組鍵,`find` 將返回具有給定陣列中主鍵的所有模型: 138 | 139 | ```php 140 | $users = User::all(); 141 | 142 | $user = $users->find(1); 143 | ``` 144 | 145 | 146 | #### `findOrFail($key)` {.collection-method} 147 | 148 | `findOrFail` 方法返回具有與給定鍵匹配的主鍵的模型,如果集合中找不到匹配的模型,則拋出 `Illuminate\Database\Eloquent\ModelNotFoundException` 例外: 149 | 150 | ```php 151 | $users = User::all(); 152 | 153 | $user = $users->findOrFail(1); 154 | ``` 155 | 156 | 157 | #### `fresh($with = [])` {.collection-method} 158 | 159 | `fresh` 方法從資料庫中檢索集合中每個模型的新實例。此外,將急切載入任何指定的關聯: 160 | 161 | ```php 162 | $users = $users->fresh(); 163 | 164 | $users = $users->fresh('comments'); 165 | ``` 166 | 167 | 168 | #### `intersect($items)` {.collection-method} 169 | 170 | `intersect` 方法返回在給定集合中也存在的所有模型: 171 | 172 | ```php 173 | use App\Models\User; 174 | 175 | $users = $users->intersect(User::whereIn('id', [1, 2, 3])->get()); 176 | ``` 177 | 178 | 179 | #### `load($relations)` {.collection-method} 180 | 181 | `load` 方法為集合中的所有模型急切載入給定的關聯: 182 | 183 | ```php 184 | $users->load(['comments', 'posts']); 185 | 186 | $users->load('comments.author'); 187 | 188 | $users->load(['comments', 'posts' => fn ($query) => $query->where('active', 1)]); 189 | ``` 190 | 191 | 192 | #### `loadMissing($relations)` {.collection-method} 193 | 194 | `loadMissing` 方法為集合中的所有模型急切載入給定的關聯,如果關聯尚未載入: 195 | 196 | ```php 197 | $users->loadMissing(['comments', 'posts']); 198 | 199 | $users->loadMissing('comments.author'); 200 | 201 | $users->loadMissing(['comments', 'posts' => fn ($query) => $query->where('active', 1)]); 202 | ``` 203 | 204 | 205 | #### `modelKeys()` {.collection-method} 206 | 207 | `modelKeys` 方法返回集合中所有模型的主鍵: 208 | 209 | ```php 210 | $users->modelKeys(); 211 | 212 | // [1, 2, 3, 4, 5] 213 | ``` 214 | 215 | 216 | #### `makeVisible($attributes)` {.collection-method} 217 | 218 | `makeVisible` 方法會[使通常在集合中每個模型上為「隱藏」的屬性可見](/docs/{{version}}/eloquent-serialization#hiding-attributes-from-json): 219 | 220 | ```php 221 | $users = $users->makeVisible(['address', 'phone_number']); 222 | ``` 223 | 224 | 225 | #### `makeHidden($attributes)` {.collection-method} 226 | 227 | `makeHidden` 方法會[隱藏通常在集合中每個模型上為「可見」的屬性](/docs/{{version}}/eloquent-serialization#hiding-attributes-from-json): 228 | 229 | ```php 230 | $users = $users->makeHidden(['address', 'phone_number']); 231 | ``` 232 | 233 | 234 | #### `only($keys)` {.collection-method} 235 | 236 | `only` 方法會返回具有給定主鍵的所有模型: 237 | 238 | ```php 239 | $users = $users->only([1, 2, 3]); 240 | ``` 241 | 242 | 243 | #### `setVisible($attributes)` {.collection-method} 244 | 245 | `setVisible` 方法會[暫時覆蓋](/docs/{{version}}/eloquent-serialization#temporarily-modifying-attribute-visibility)集合中每個模型上的所有可見屬性: 246 | 247 | ```php 248 | $users = $users->setVisible(['id', 'name']); 249 | ``` 250 | 251 | 252 | #### `setHidden($attributes)` {.collection-method} 253 | 254 | `setHidden` 方法會[暫時覆蓋](/docs/{{version}}/eloquent-serialization#temporarily-modifying-attribute-visibility)集合中每個模型上的所有隱藏屬性: 255 | 256 | ```php 257 | $users = $users->setHidden(['email', 'password', 'remember_token']); 258 | ``` 259 | 260 | 261 | #### `toQuery()` {.collection-method} 262 | 263 | `toQuery` 方法會返回包含對集合模型主鍵的 `whereIn` 約束的 Eloquent 查詢生成器實例: 264 | 265 | ```php 266 | use App\Models\User; 267 | 268 | $users = User::where('status', 'VIP')->get(); 269 | 270 | $users->toQuery()->update([ 271 | 'status' => 'Administrator', 272 | ]); 273 | ``` 274 | 275 | 276 | #### `unique($key = null, $strict = false)` {.collection-method} 277 | 278 | `unique` 方法會返回集合中所有獨特的模型。任何具有與集合中另一個模型相同主鍵的模型都將被移除: 279 | 280 | ```php 281 | $users = $users->unique(); 282 | ``` 283 | 284 | 285 | ## 自訂集合 286 | 287 | 如果您想在與特定模型互動時使用自訂的 `Collection` 物件,您可以將 `CollectedBy` 屬性添加到您的模型中: 288 | 289 | ```php 290 | $models 322 | * @return \Illuminate\Database\Eloquent\Collection 323 | */ 324 | public function newCollection(array $models = []): Collection 325 | { 326 | return new UserCollection($models); 327 | } 328 | } 329 | ``` 330 | 331 | 一旦您定義了 `newCollection` 方法或將 `CollectedBy` 屬性添加到您的模型中,每當 Eloquent 通常會返回一個 `Illuminate\Database\Eloquent\Collection` 實例時,您將收到您自訂集合的實例。 332 | 333 | 如果您想要為應用程序中的每個模型使用自訂集合,您應該在一個基本模型類別上定義 `newCollection` 方法,該基本模型類別由應用程序的所有模型擴展。 334 | -------------------------------------------------------------------------------- /eloquent-serialization.md: -------------------------------------------------------------------------------- 1 | # Eloquent: 序列化 2 | 3 | - [簡介](#introduction) 4 | - [序列化模型和集合](#serializing-models-and-collections) 5 | - [序列化為陣列](#serializing-to-arrays) 6 | - [序列化為 JSON](#serializing-to-json) 7 | - [隱藏 JSON 中的屬性](#hiding-attributes-from-json) 8 | - [附加值到 JSON](#appending-values-to-json) 9 | - [日期序列化](#date-serialization) 10 | 11 | 12 | ## 簡介 13 | 14 | 在使用 Laravel 構建 API 時,您通常需要將您的模型和關聯轉換為陣列或 JSON。Eloquent 包含方便的方法來進行這些轉換,以及控制哪些屬性包含在模型的序列化表示中。 15 | 16 | > [!NOTE] 17 | > 若要更強大地處理 Eloquent 模型和集合的 JSON 序列化,請查看[Eloquent API 資源](/docs/{{version}}/eloquent-resources)的文件。 18 | 19 | 20 | ## 序列化模型和集合 21 | 22 | 23 | ### 序列化為陣列 24 | 25 | 要將模型及其已載入的[關聯](/docs/{{version}}/eloquent-relationships)轉換為陣列,應使用 `toArray` 方法。該方法是遞迴的,因此所有屬性和所有關聯(包括關聯的關聯)將被轉換為陣列: 26 | 27 | ```php 28 | use App\Models\User; 29 | 30 | $user = User::with('roles')->first(); 31 | 32 | return $user->toArray(); 33 | ``` 34 | 35 | `attributesToArray` 方法可用於將模型的屬性轉換為陣列,但不包括其關聯: 36 | 37 | ```php 38 | $user = User::first(); 39 | 40 | return $user->attributesToArray(); 41 | ``` 42 | 43 | 您也可以通過在集合實例上調用 `toArray` 方法來將整個[集合](/docs/{{version}}/eloquent-collections)的模型轉換為陣列: 44 | 45 | ```php 46 | $users = User::all(); 47 | 48 | return $users->toArray(); 49 | ``` 50 | 51 | 52 | ### 序列化為 JSON 53 | 54 | 要將模型轉換為 JSON,應使用 `toJson` 方法。與 `toArray` 一樣,`toJson` 方法是遞迴的,因此所有屬性和關聯將被轉換為 JSON。您也可以指定任何[PHP 支持的 JSON 編碼選項](https://secure.php.net/manual/en/function.json-encode.php): 55 | 56 | ```php 57 | use App\Models\User; 58 | 59 | $user = User::find(1); 60 | 61 | return $user->toJson(); 62 | 63 | return $user->toJson(JSON_PRETTY_PRINT); 64 | ``` 65 | 66 | 或者,您可以將模型或集合轉換為字符串,這將自動調用模型或集合上的 `toJson` 方法: 67 | 68 | ```php 69 | return (string) User::find(1); 70 | ``` 71 | 72 | 由於模型和集合在轉換為字符串時會轉換為 JSON,因此您可以直接從應用程序的路由或控制器中返回 Eloquent 物件。當從路由或控制器返回時,Laravel 將自動將您的 Eloquent 模型和集合序列化為 JSON: 73 | 74 | ```php 75 | Route::get('/users', function () { 76 | return User::all(); 77 | }); 78 | ``` 79 | 80 | 81 | #### 關聯 82 | 83 | 當將 Eloquent 模型轉換為 JSON 時,其已加載的關聯將自動包含為 JSON 對象的屬性。此外,儘管使用 "駝峰命名法" 方法名定義了 Eloquent 關聯方法,但關聯的 JSON 屬性將是 "蛇形命名法"。 84 | 85 | 86 | ## 從 JSON 中隱藏屬性 87 | 88 | 有時您可能希望限制包含在模型數組或 JSON 表示中的屬性,例如密碼。為此,請將 `$hidden` 屬性添加到您的模型中。在 `$hidden` 屬性的數組中列出的屬性將不包含在模型的序列化表示中: 89 | 90 | ```php 91 | 103 | */ 104 | protected $hidden = ['password']; 105 | } 106 | ``` 107 | 108 | > [!NOTE] 109 | > 要隱藏關聯,請將關聯的方法名添加到您的 Eloquent 模型的 `$hidden` 屬性中。 110 | 111 | 或者,您可以使用 `visible` 屬性來定義應包含在模型數組和 JSON 表示中的屬性的 "允許列表"。當模型轉換為數組或 JSON 時,不在 `$visible` 數組中的所有屬性將被隱藏: 112 | 113 | ```php 114 | 132 | #### 暫時修改屬性可見性 133 | 134 | 如果您希望在給定模型實例上使一些通常隱藏的屬性可見,則可以使用 `makeVisible` 方法。`makeVisible` 方法將返回模型實例: 135 | 136 | ```php 137 | return $user->makeVisible('attribute')->toArray(); 138 | ``` 139 | 140 | 同樣地,如果您想要隱藏一些通常可見的屬性,您可以使用 `makeHidden` 方法。 141 | 142 | ```php 143 | return $user->makeHidden('attribute')->toArray(); 144 | ``` 145 | 146 | 如果您希望暫時覆蓋所有可見或隱藏的屬性,您可以分別使用 `setVisible` 和 `setHidden` 方法: 147 | 148 | ```php 149 | return $user->setVisible(['id', 'name'])->toArray(); 150 | 151 | return $user->setHidden(['email', 'password', 'remember_token'])->toArray(); 152 | ``` 153 | 154 | 155 | ## 將值附加到 JSON 156 | 157 | 有時,在將模型轉換為陣列或 JSON 時,您可能希望添加一些在您的資料庫中沒有對應列的屬性。為此,首先定義一個[取值器](/docs/{{version}}/eloquent-mutators)來處理這個值: 158 | 159 | ```php 160 | 'yes', 176 | ); 177 | } 178 | } 179 | ``` 180 | 181 | 如果您希望取值器始終附加到您模型的陣列和 JSON 表示中,您可以將屬性名稱添加到模型的 `appends` 屬性中。請注意,屬性名稱通常使用它們的「蛇形命名法」序列化表示來引用,即使取值器的 PHP 方法是使用「駝峰命名法」定義的: 182 | 183 | ```php 184 | 204 | #### 在運行時附加 205 | 206 | 在運行時,您可以指示模型實例使用 `append` 方法附加額外的屬性。或者,您可以使用 `setAppends` 方法來覆蓋給定模型實例的整個附加屬性陣列: 207 | 208 | ```php 209 | return $user->append('is_admin')->toArray(); 210 | 211 | return $user->setAppends(['is_admin'])->toArray(); 212 | ``` 213 | 214 | 215 | ## 日期序列化 216 | 217 | 218 | #### 自訂預設日期格式 219 | 220 | 您可以通過覆蓋 `serializeDate` 方法來自定義默認的序列化格式。這個方法不會影響日期在數據庫中存儲的格式: 221 | 222 | ```php 223 | /** 224 | * Prepare a date for array / JSON serialization. 225 | */ 226 | protected function serializeDate(DateTimeInterface $date): string 227 | { 228 | return $date->format('Y-m-d'); 229 | } 230 | ``` 231 | 232 | 233 | #### 自定義屬性的日期格式 234 | 235 | 您可以通過在模型的 [轉換聲明](/docs/{{version}}/eloquent-mutators#attribute-casting) 中指定日期格式來自定義個別 Eloquent 日期屬性的序列化格式: 236 | 237 | ```php 238 | protected function casts(): array 239 | { 240 | return [ 241 | 'birthday' => 'date:Y-m-d', 242 | 'joined_at' => 'datetime:Y-m-d H:00', 243 | ]; 244 | } 245 | ``` 246 | -------------------------------------------------------------------------------- /encryption.md: -------------------------------------------------------------------------------- 1 | # 加密 2 | 3 | - [簡介](#introduction) 4 | - [組態設定](#configuration) 5 | - [優雅地輪換加密金鑰](#gracefully-rotating-encryption-keys) 6 | - [使用加密器](#using-the-encrypter) 7 | 8 | 9 | ## 簡介 10 | 11 | Laravel 的加密服務提供了一個簡單、方便的介面,通過 OpenSSL 使用 AES-256 和 AES-128 加密來加密和解密文本。所有 Laravel 的加密值都使用訊息驗證碼(MAC)簽名,因此一旦加密,它們的基礎值就無法被修改或篡改。 12 | 13 | 14 | ## 組態設定 15 | 16 | 在使用 Laravel 的加密器之前,您必須在 `config/app.php` 組態檔中設置 `key` 組態選項。這個組態值由 `APP_KEY` 環境變數驅動。您應該使用 `php artisan key:generate` 命令來生成這個變數的值,因為 `key:generate` 命令將使用 PHP 的安全隨機位元組生成器來為您的應用程式建立一個具有密碼安全性的金鑰。通常,`APP_KEY` 環境變數的值將在 [Laravel 的安裝](/docs/{{version}}/installation) 過程中為您生成。 17 | 18 | 19 | ### 優雅地輪換加密金鑰 20 | 21 | 如果您更改應用程式的加密金鑰,所有已驗證的使用者會話將從您的應用程式中登出。這是因為 Laravel 加密了每個 cookie,包括會話 cookie。此外,將無法解密使用先前加密金鑰加密的任何資料。 22 | 23 | 為了減輕這個問題,Laravel 允許您在應用程式的 `APP_PREVIOUS_KEYS` 環境變數中列出先前的加密金鑰。這個變數可以包含一個以逗號分隔的所有先前加密金鑰的清單: 24 | 25 | ```ini 26 | APP_KEY="base64:J63qRTDLub5NuZvP+kb8YIorGS6qFYHKVo6u7179stY=" 27 | APP_PREVIOUS_KEYS="base64:2nLsGFGzyoae2ax3EF2Lyq/hH6QghBGLIq5uL+Gp8/w=" 28 | ``` 29 | 30 | 當您設置這個環境變數時,Laravel 將始終在加密值時使用“當前”加密金鑰。但是,在解密值時,Laravel 將首先嘗試使用當前金鑰,如果使用當前金鑰解密失敗,Laravel 將嘗試使用所有先前的金鑰,直到其中一個金鑰能夠解密該值。 31 | 32 | 這種優雅的解密方法讓使用者可以在您的加密金鑰輪換時繼續無間斷地使用您的應用程式。 33 | 34 | 35 | ## 使用加密器 36 | 37 | 38 | #### 加密值 39 | 40 | 您可以使用`Crypt` Facades提供的`encryptString`方法來加密值。所有加密值都是使用OpenSSL和AES-256-CBC加密。此外,所有加密值都會簽署一個訊息驗證碼(MAC)。整合的訊息驗證碼將防止惡意使用者篡改的任何值的解密: 41 | 42 | ```php 43 | user()->fill([ 59 | 'token' => Crypt::encryptString($request->token), 60 | ])->save(); 61 | 62 | return redirect('/secrets'); 63 | } 64 | } 65 | ``` 66 | 67 | 68 | #### 解密值 69 | 70 | 您可以使用`Crypt` Facades提供的`decryptString`方法來解密值。如果值無法正確解密,例如當訊息驗證碼無效時,將拋出`Illuminate\Contracts\Encryption\DecryptException`: 71 | 72 | ```php 73 | use Illuminate\Contracts\Encryption\DecryptException; 74 | use Illuminate\Support\Facades\Crypt; 75 | 76 | try { 77 | $decrypted = Crypt::decryptString($encryptedValue); 78 | } catch (DecryptException $e) { 79 | // ... 80 | } 81 | ``` 82 | -------------------------------------------------------------------------------- /envoy.md: -------------------------------------------------------------------------------- 1 | # Laravel Envoy 2 | 3 | - [簡介](#introduction) 4 | - [安裝](#installation) 5 | - [撰寫任務](#writing-tasks) 6 | - [定義任務](#defining-tasks) 7 | - [多個伺服器](#multiple-servers) 8 | - [設定](#setup) 9 | - [變數](#variables) 10 | - [故事](#stories) 11 | - [鉤子](#completion-hooks) 12 | - [執行任務](#running-tasks) 13 | - [確認任務執行](#confirming-task-execution) 14 | - [通知](#notifications) 15 | - [Slack](#slack) 16 | - [Discord](#discord) 17 | - [Telegram](#telegram) 18 | - [Microsoft Teams](#microsoft-teams) 19 | 20 | 21 | ## 簡介 22 | 23 | [Laravel Envoy](https://github.com/laravel/envoy) 是一個用於在遠端伺服器上執行常見任務的工具。使用 [Blade](/docs/{{version}}/blade) 風格的語法,您可以輕鬆設定部署任務、Artisan 指令等。目前,Envoy 僅支援 Mac 和 Linux 作業系統。但是,可以使用 [WSL2](https://docs.microsoft.com/en-us/windows/wsl/install-win10) 實現 Windows 支援。 24 | 25 | 26 | ## 安裝 27 | 28 | 首先,使用 Composer 套件管理器將 Envoy 安裝到您的專案中: 29 | 30 | ```shell 31 | composer require laravel/envoy --dev 32 | ``` 33 | 34 | 安裝完成後,Envoy 二進制檔將位於應用程式的 `vendor/bin` 目錄中: 35 | 36 | ```shell 37 | php vendor/bin/envoy 38 | ``` 39 | 40 | 41 | ## 撰寫任務 42 | 43 | 44 | ### 定義任務 45 | 46 | 任務是 Envoy 的基本構建塊。任務定義了在調用任務時應在遠端伺服器上執行的 shell 命令。例如,您可以定義一個任務,在應用程式的所有佇列工作伺服器上執行 `php artisan queue:restart` 命令。 47 | 48 | 您應該在應用程式根目錄下的 `Envoy.blade.php` 檔案中定義所有 Envoy 任務。以下是一個示例以供參考: 49 | 50 | ```blade 51 | @servers(['web' => ['user@192.168.1.1'], 'workers' => ['user@192.168.1.2']]) 52 | 53 | @task('restart-queues', ['on' => 'workers']) 54 | cd /home/user/example.com 55 | php artisan queue:restart 56 | @endtask 57 | ``` 58 | 59 | 如您所見,`@servers` 的陣列在檔案頂部被定義,讓您可以透過任務聲明的 `on` 選項引用這些伺服器。`@servers` 的宣告應該始終放在單獨的一行上。在您的 `@task` 宣告中,您應該放置在調用任務時應在伺服器上執行的 shell 命令。 60 | 61 | 62 | 63 | #### 本地任務 64 | 65 | 您可以通過將伺服器的 IP 位址設置為 `127.0.0.1` 來強制在本地電腦上運行腳本: 66 | 67 | ```blade 68 | @servers(['localhost' => '127.0.0.1']) 69 | ``` 70 | 71 | 72 | #### 匯入 Envoy 任務 73 | 74 | 使用 `@import` 指示詞,您可以匯入其他 Envoy 檔案,以便將它們的故事和任務添加到您的檔案中。在匯入檔案後,您可以執行這些檔案中包含的任務,就好像它們是在您自己的 Envoy 檔案中定義的一樣: 75 | 76 | ```blade 77 | @import('vendor/package/Envoy.blade.php') 78 | ``` 79 | 80 | 81 | ### 多伺服器 82 | 83 | Envoy 允許您輕鬆地在多個伺服器上運行任務。首先,將額外的伺服器添加到您的 `@servers` 宣告中。每個伺服器應被指定一個唯一的名稱。一旦您定義了額外的伺服器,您可以在任務的 `on` 陣列中列出每個伺服器: 84 | 85 | ```blade 86 | @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) 87 | 88 | @task('deploy', ['on' => ['web-1', 'web-2']]) 89 | cd /home/user/example.com 90 | git pull origin {{ $branch }} 91 | php artisan migrate --force 92 | @endtask 93 | ``` 94 | 95 | 96 | #### 並行執行 97 | 98 | 默認情況下,任務將在每個伺服器上按順序執行。換句話說,在第一個伺服器上執行完任務後,才會繼續在第二個伺服器上執行。如果您想要在多個伺服器上並行運行任務,請將 `parallel` 選項添加到您的任務宣告中: 99 | 100 | ```blade 101 | @servers(['web-1' => '192.168.1.1', 'web-2' => '192.168.1.2']) 102 | 103 | @task('deploy', ['on' => ['web-1', 'web-2'], 'parallel' => true]) 104 | cd /home/user/example.com 105 | git pull origin {{ $branch }} 106 | php artisan migrate --force 107 | @endtask 108 | ``` 109 | 110 | 111 | ### 設置 112 | 113 | 有時候,在運行 Envoy 任務之前,您可能需要執行任意的 PHP 代碼。您可以使用 `@setup` 指示詞來定義一段 PHP 代碼區塊,在您的任務之前執行: 114 | 115 | ```php 116 | @setup 117 | $now = new DateTime; 118 | @endsetup 119 | ``` 120 | 121 | 如果您需要在執行任務之前要求其他 PHP 檔案,您可以在您的 `Envoy.blade.php` 檔案頂部使用 `@include` 指示詞: 122 | 123 | ```blade 124 | @include('vendor/autoload.php') 125 | 126 | @task('restart-queues') 127 | # ... 128 | @endtask 129 | ``` 130 | 131 | 132 | ### 變數 133 | 134 | 如果需要,您可以通過在調用 Envoy 時在命令列上指定參數來將參數傳遞給 Envoy 任務: 135 | 136 | ```shell 137 | php vendor/bin/envoy run deploy --branch=master 138 | ``` 139 | 140 | 您可以使用 Blade 的 "echo" 語法在您的任務中訪問這些選項。您也可以在您的任務中定義 Blade 的 `if` 陳述和迴圈。例如,讓我們在執行 `git pull` 命令之前驗證 `$branch` 變數的存在: 141 | 142 | ```blade 143 | @servers(['web' => ['user@192.168.1.1']]) 144 | 145 | @task('deploy', ['on' => 'web']) 146 | cd /home/user/example.com 147 | 148 | @if ($branch) 149 | git pull origin {{ $branch }} 150 | @endif 151 | 152 | php artisan migrate --force 153 | @endtask 154 | ``` 155 | 156 | 157 | ### 故事 158 | 159 | 故事將一組任務組合在一個方便的名稱下。例如,一個 `deploy` 故事可能會執行 `update-code` 和 `install-dependencies` 任務,方法是在其定義中列出任務名稱: 160 | 161 | ```blade 162 | @servers(['web' => ['user@192.168.1.1']]) 163 | 164 | @story('deploy') 165 | update-code 166 | install-dependencies 167 | @endstory 168 | 169 | @task('update-code') 170 | cd /home/user/example.com 171 | git pull origin master 172 | @endtask 173 | 174 | @task('install-dependencies') 175 | cd /home/user/example.com 176 | composer install 177 | @endtask 178 | ``` 179 | 180 | 故事編寫完成後,您可以像調用任務一樣調用它: 181 | 182 | ```shell 183 | php vendor/bin/envoy run deploy 184 | ``` 185 | 186 | 187 | ### 鉤子 188 | 189 | 當任務和故事運行時,將執行多個鉤子。Envoy 支持的鉤子類型包括 `@before`、`@after`、`@error`、`@success` 和 `@finished`。這些鉤子中的所有代碼都被解釋為 PHP 並在本地執行,而不是在您的任務與之交互的遠程服務器上執行。 190 | 191 | 您可以定義任意數量的每個鉤子。它們將按照它們在 Envoy 腳本中出現的順序執行。 192 | 193 | 194 | #### `@before` 195 | 196 | 在每個任務執行之前,將執行在您的 Envoy 腳本中註冊的所有 `@before` 鉤子。`@before` 鉤子接收將要執行的任務的名稱: 197 | 198 | ```blade 199 | @before 200 | if ($task === 'deploy') { 201 | // ... 202 | } 203 | @endbefore 204 | ``` 205 | 206 | 207 | #### `@after` 208 | 209 | 在每個任務執行之後,將執行在您的 Envoy 腳本中註冊的所有 `@after` 鉤子。`@after` 鉤子接收已執行的任務的名稱: 210 | 211 | ```blade 212 | @after 213 | if ($task === 'deploy') { 214 | // ... 215 | } 216 | @endafter 217 | ``` 218 | 219 | 220 | #### `@error` 221 | 222 | 在每個任務失敗後(退出狀態碼大於 `0`),將執行在您的 Envoy 腳本中註冊的所有 `@error` 鉤子。`@error` 鉤子接收已執行的任務的名稱: 223 | 224 | ```blade 225 | @error 226 | if ($task === 'deploy') { 227 | // ... 228 | } 229 | @enderror 230 | ``` 231 | 232 | 233 | #### `@success` 234 | 235 | 如果所有任務都沒有錯誤地執行,將執行在您的 Envoy 腳本中註冊的所有 `@success` 鉤子: 236 | 237 | ```blade 238 | @success 239 | // ... 240 | @endsuccess 241 | ``` 242 | 243 | 244 | #### `@finished` 245 | 246 | 在所有任務都已執行後(無論退出狀態如何),將執行所有 `@finished` 鉤子。`@finished` 鉤子接收已完成任務的狀態碼,可能為 `null` 或大於或等於 `0` 的 `integer`: 247 | 248 | ```blade 249 | @finished 250 | if ($exitCode > 0) { 251 | // There were errors in one of the tasks... 252 | } 253 | @endfinished 254 | ``` 255 | 256 | 257 | ## 執行任務 258 | 259 | 要執行在應用程式 `Envoy.blade.php` 檔案中定義的任務或故事,請執行 Envoy 的 `run` 指令,並傳遞您想要執行的任務或故事的名稱。Envoy 將執行該任務並顯示遠端伺服器的輸出,當任務正在執行時: 260 | 261 | ```shell 262 | php vendor/bin/envoy run deploy 263 | ``` 264 | 265 | 266 | ### 確認任務執行 267 | 268 | 如果您希望在在伺服器上執行特定任務之前收到確認提示,您應該將 `confirm` 指示詞添加到您的任務宣告中。此選項對於具有破壞性操作特別有用: 269 | 270 | ```blade 271 | @task('deploy', ['on' => 'web', 'confirm' => true]) 272 | cd /home/user/example.com 273 | git pull origin {{ $branch }} 274 | php artisan migrate 275 | @endtask 276 | ``` 277 | 278 | 279 | ## 通知 280 | 281 | 282 | ### Slack 283 | 284 | Envoy 支援在每次執行任務後將通知發送到 [Slack](https://slack.com)。`@slack` 指示詞接受一個 Slack 鉤子 URL 和一個頻道/使用者名稱。您可以通過在 Slack 控制面板中創建 "Incoming WebHooks" 整合來檢索您的 Webhook URL。 285 | 286 | 您應將整個 Webhook URL 作為傳遞給 `@slack` 指示詞的第一個參數。傳遞給 `@slack` 指示詞的第二個參數應該是頻道名稱 (`#channel`) 或使用者名稱 (`@user`): 287 | 288 | ```blade 289 | @finished 290 | @slack('webhook-url', '#bots') 291 | @endfinished 292 | ``` 293 | 294 | 預設情況下,Envoy 通知將向通知頻道發送一條描述已執行任務的訊息。但是,您可以通過將第三個參數傳遞給 `@slack` 指示詞,覆蓋此訊息並使用自己的自訂訊息: 295 | 296 | ```blade 297 | @finished 298 | @slack('webhook-url', '#bots', 'Hello, Slack.') 299 | @endfinished 300 | ``` 301 | 302 | 303 | ### Discord 304 | 305 | Envoy 也支援在每次執行任務後將通知發送到 [Discord](https://discord.com)。`@discord` 指示詞接受一個 Discord 鉤子 URL 和一個訊息。您可以通過在您的伺服器設定中創建 "Webhook" 並選擇 Webhook 應該發布到的頻道來檢索您的 Webhook URL。您應將整個 Webhook URL 傳遞給 `@discord` 指示詞: 306 | 307 | ```blade 308 | @finished 309 | @discord('discord-webhook-url') 310 | @endfinished 311 | ``` 312 | 313 | 314 | ### 電報 315 | 316 | Envoy 也支援在每個任務執行後發送通知到 [Telegram](https://telegram.org)。`@telegram` 指示詞接受一個 Telegram 機器人 ID 和一個聊天 ID。您可以通過使用 [BotFather](https://t.me/botfather) 創建新機器人來獲取您的機器人 ID。您可以使用 [@username_to_id_bot](https://t.me/username_to_id_bot) 獲取有效的聊天 ID。您應該將完整的機器人 ID 和聊天 ID 傳遞給 `@telegram` 指示詞: 317 | 318 | ```blade 319 | @finished 320 | @telegram('bot-id','chat-id') 321 | @endfinished 322 | ``` 323 | 324 | 325 | ### 微軟團隊 326 | 327 | Envoy 也支援在每個任務執行後發送通知到 [Microsoft Teams](https://www.microsoft.com/en-us/microsoft-teams)。`@microsoftTeams` 指示詞接受一個 Teams Webhook(必需)、一個訊息、主題顏色(成功、資訊、警告、錯誤)和一個選項陣列。您可以通過創建新的 [傳入 Webhook](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook) 來獲取您的 Teams Webhook。Teams API 還有許多其他屬性可自定義訊息框,如標題、摘要和區段。您可以在 [Microsoft Teams 文件](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using?tabs=cURL#example-of-connector-message) 中找到更多信息。您應該將完整的 Webhook URL 傳遞給 `@microsoftTeams` 指示詞: 328 | 329 | ```blade 330 | @finished 331 | @microsoftTeams('webhook-url') 332 | @endfinished 333 | ``` 334 | -------------------------------------------------------------------------------- /folio.md: -------------------------------------------------------------------------------- 1 | # Laravel Folio 2 | 3 | - [簡介](#introduction) 4 | - [安裝](#installation) 5 | - [頁面路徑 / URI](#page-paths-uris) 6 | - [子域路由](#subdomain-routing) 7 | - [建立路由](#creating-routes) 8 | - [巢狀路由](#nested-routes) 9 | - [索引路由](#index-routes) 10 | - [路由參數](#route-parameters) 11 | - [路由模型繫結](#route-model-binding) 12 | - [軟刪除模型](#soft-deleted-models) 13 | - [渲染掛勾](#render-hooks) 14 | - [命名路由](#named-routes) 15 | - [中介層](#middleware) 16 | - [路由快取](#route-caching) 17 | 18 | 19 | ## 簡介 20 | 21 | [Laravel Folio](https://github.com/laravel/folio) 是一個強大的基於頁面的路由器,旨在簡化 Laravel 應用程序中的路由。使用 Laravel Folio,生成路由就像在應用程序的 `resources/views/pages` 目錄中創建 Blade 模板一樣輕鬆。 22 | 23 | 例如,要創建一個可以在 `/greeting` URL 訪問的頁面,只需在應用程序的 `resources/views/pages` 目錄中創建一個 `greeting.blade.php` 文件: 24 | 25 | ```php 26 |
27 | Hello World 28 |
29 | ``` 30 | 31 | 32 | ## 安裝 33 | 34 | 要開始使用,使用 Composer 套件管理器將 Folio 安裝到您的項目中: 35 | 36 | ```shell 37 | composer require laravel/folio 38 | ``` 39 | 40 | 安裝 Folio 後,您可以執行 `folio:install` Artisan 命令,該命令將 Folio 的服務提供者安裝到您的應用程序中。此服務提供者註冊 Folio 將搜索路由 / 頁面的目錄: 41 | 42 | ```shell 43 | php artisan folio:install 44 | ``` 45 | 46 | 47 | ### 頁面路徑 / URI 48 | 49 | 默認情況下,Folio 從您的應用程序的 `resources/views/pages` 目錄中提供頁面,但您可以在 Folio 服務提供者的 `boot` 方法中自定義這些目錄。 50 | 51 | 例如,有時候在同一個 Laravel 應用程序中指定多個 Folio 路徑可能很方便。您可能希望為應用程序的 "管理" 區域指定一個獨立的 Folio 頁面目錄,同時使用另一個目錄來存放應用程序其餘頁面。 52 | 53 | 您可以使用 `Folio::path` 和 `Folio::uri` 方法來實現這一點。`path` 方法註冊 Folio 將掃描以路由傳入的 HTTP 請求時的頁面的目錄,而 `uri` 方法指定該目錄頁面的 "基本 URI": 54 | 55 | ```php 56 | use Laravel\Folio\Folio; 57 | 58 | Folio::path(resource_path('views/pages/guest'))->uri('/'); 59 | 60 | Folio::path(resource_path('views/pages/admin')) 61 | ->uri('/admin') 62 | ->middleware([ 63 | '*' => [ 64 | 'auth', 65 | 'verified', 66 | 67 | // ... 68 | ], 69 | ]); 70 | ``` 71 | 72 | 73 | ### 子域路由 74 | 75 | 您也可以根据传入请求的子域路由到页面。例如,您可能希望将来自 `admin.example.com` 的请求路由到不同的页面目录,而不是其余 Folio 页面。您可以在调用 `Folio::path` 方法后调用 `domain` 方法来实现此目的: 76 | 77 | ```php 78 | use Laravel\Folio\Folio; 79 | 80 | Folio::domain('admin.example.com') 81 | ->path(resource_path('views/pages/admin')); 82 | ``` 83 | 84 | `domain` 方法还允许您捕获域或子域的部分作为参数。这些参数将被注入到您的页面模板中: 85 | 86 | ```php 87 | use Laravel\Folio\Folio; 88 | 89 | Folio::domain('{account}.example.com') 90 | ->path(resource_path('views/pages/admin')); 91 | ``` 92 | 93 | 94 | ## 创建路由 95 | 96 | 您可以通过在任何 Folio 挂载目录中放置 Blade 模板来创建 Folio 路由。默认情况下,Folio 挂载 `resources/views/pages` 目录,但您可以在您的 Folio 服务提供者的 `boot` 方法中自定义这些目录。 97 | 98 | 一旦在 Folio 挂载目录中放置了 Blade 模板,您可以立即通过浏览器访问它。例如,放置在 `pages/schedule.blade.php` 中的页面可以在浏览器中通过 `http://example.com/schedule` 访问。 99 | 100 | 要快速查看所有 Folio 页面/路由的列表,您可以调用 `folio:list` Artisan 命令: 101 | 102 | ```shell 103 | php artisan folio:list 104 | ``` 105 | 106 | 107 | ### 嵌套路由 108 | 109 | 您可以通过在 Folio 的一个或多个目录中创建一个或多个目录来创建嵌套路由。例如,要创建一个可以通过 `/user/profile` 访问的页面,请在 `pages/user` 目录中创建一个 `profile.blade.php` 模板: 110 | 111 | ```shell 112 | php artisan folio:page user/profile 113 | 114 | # pages/user/profile.blade.php → /user/profile 115 | ``` 116 | 117 | 118 | ### 索引路由 119 | 120 | 有时,您可能希望将给定页面作为目录的“索引”。通过在 Folio 目录中放置一个 `index.blade.php` 模板,该目录的根目录的任何请求都将路由到该页面: 121 | 122 | ```shell 123 | php artisan folio:page index 124 | # pages/index.blade.php → / 125 | 126 | php artisan folio:page users/index 127 | # pages/users/index.blade.php → /users 128 | ``` 129 | 130 | 131 | ## 路由參數 132 | 133 | 通常,您需要將傳入請求的 URL 段注入到您的頁面中,以便與它們進行交互。例如,您可能需要訪問正在顯示的使用者「ID」的個人資料。為了實現這一點,您可以將頁面檔名的一部分封裝在方括號中: 134 | 135 | ```shell 136 | php artisan folio:page "users/[id]" 137 | 138 | # pages/users/[id].blade.php → /users/1 139 | ``` 140 | 141 | 捕獲的段可以在您的 Blade 模板中作為變數訪問: 142 | 143 | ```html 144 |
145 | 使用者 {{ $id }} 146 |
147 | ``` 148 | 149 | 要捕獲多個段,您可以使用三個點 `...` 作為封裝段的前綴: 150 | 151 | ```shell 152 | php artisan folio:page "users/[...ids]" 153 | 154 | # pages/users/[...ids].blade.php → /users/1/2/3 155 | ``` 156 | 157 | 在捕獲多個段時,捕獲的段將作為陣列注入到頁面中: 158 | 159 | ```html 160 | 165 | ``` 166 | 167 | 168 | ## 路由模型綁定 169 | 170 | 如果您的頁面模板檔名的萬用字元段對應到應用程式的一個 Eloquent 模型,Folio 將自動利用 Laravel 的路由模型綁定功能,並嘗試將解析的模型實例注入到您的頁面中: 171 | 172 | ```shell 173 | php artisan folio:page "users/[User]" 174 | 175 | # pages/users/[User].blade.php → /users/1 176 | ``` 177 | 178 | 捕獲的模型可以在您的 Blade 模板中作為變數訪問。模型的變數名將轉換為「駝峰式」: 179 | 180 | ```html 181 |
182 | 使用者 {{ $user->id }} 183 |
184 | ``` 185 | 186 | #### 自定義鍵 187 | 188 | 有時您可能希望使用除了 `id` 以外的列來解析綁定的 Eloquent 模型。為此,您可以在頁面的檔名中指定列。例如,檔名為 `[Post:slug].blade.php` 的頁面將嘗試通過 `slug` 列而不是 `id` 列來解析綁定的模型。 189 | 190 | 在 Windows 上,您應該使用 `-` 將模型名稱與鍵分開:`[Post-slug].blade.php`。 191 | 192 | #### 模型位置 193 | 194 | 預設情況下,Folio 將在應用程式的 `app/Models` 目錄中搜索您的模型。但是,如果需要,您可以在模板的檔名中指定完全合格的模型類別名稱: 195 | 196 | ```shell 197 | php artisan folio:page "users/[.App.Models.User]" 198 | 199 | # pages/users/[.App.Models.User].blade.php → /users/1 200 | ``` 201 | 202 | 203 | ### 軟刪除模型 204 | 205 | 預設情況下,已被軟刪除的模型在解析隱式模型綁定時不會被檢索。但是,如果您希望,您可以通過在頁面模板中調用 `withTrashed` 函數來指示 Folio 檢索已被軟刪除的模型: 206 | 207 | ```php 208 | 215 | 216 |
217 | User {{ $user->id }} 218 |
219 | ``` 220 | 221 | 222 | ## 渲染掛勾 223 | 224 | 預設情況下,Folio 將返回頁面 Blade 模板的內容作為對傳入請求的回應。但是,您可以通過在頁面模板中調用 `render` 函數來自定義回應。 225 | 226 | `render` 函數接受一個閉包,該閉包將接收由 Folio 渲染的 `View` 實例,允許您向視圖添加額外數據或自定義整個回應。除了接收 `View` 實例外,任何額外的路由參數或模型綁定也將提供給 `render` 閉包: 227 | 228 | ```php 229 | can('view', $post)) { 239 | return response('Unauthorized', 403); 240 | } 241 | 242 | return $view->with('photos', $post->author->photos); 243 | }); ?> 244 | 245 |
246 | {{ $post->content }} 247 |
248 | 249 |
250 | This author has also taken {{ count($photos) }} photos. 251 |
252 | ``` 253 | 254 | 255 | ## 命名路由 256 | 257 | 您可以使用 `name` 函數為給定頁面的路由指定名稱: 258 | 259 | ```php 260 | 271 | 所有使用者 272 | 273 | ``` 274 | 275 | 如果頁面有參數,您只需將其值傳遞給 `route` 函數: 276 | 277 | ```php 278 | route('users.show', ['user' => $user]); 279 | ``` 280 | 281 | 282 | ## 中介層 283 | 284 | 您可以通過在頁面模板中調用 `middleware` 函數來將中介層應用於特定頁面: 285 | 286 | ```php 287 | 294 | 295 |
296 | Dashboard 297 |
298 | ``` 299 | 300 | 或者,要將中介層分配給一組頁面,您可以在調用 `Folio::path` 方法後鏈接 `middleware` 方法。 301 | 302 | 要指定應將中介層應用於哪些頁面,中介層數組可以使用相應頁面的 URL 模式作為鍵。`*` 字元可以用作萬用字元: 303 | 304 | ```php 305 | use Laravel\Folio\Folio; 306 | 307 | Folio::path(resource_path('views/pages'))->middleware([ 308 | 'admin/*' => [ 309 | 'auth', 310 | 'verified', 311 | 312 | // ... 313 | ], 314 | ]); 315 | ``` 316 | 317 | 您可以在中介層陣列中包含閉包,以定義內聯的匿名中介層: 318 | 319 | ```php 320 | use Closure; 321 | use Illuminate\Http\Request; 322 | use Laravel\Folio\Folio; 323 | 324 | Folio::path(resource_path('views/pages'))->middleware([ 325 | 'admin/*' => [ 326 | 'auth', 327 | 'verified', 328 | 329 | function (Request $request, Closure $next) { 330 | // ... 331 | 332 | return $next($request); 333 | }, 334 | ], 335 | ]); 336 | ``` 337 | 338 | 339 | ## 路由快取 340 | 341 | 在使用 Folio 時,您應該始終利用 [Laravel 的路由快取功能](/docs/{{version}}/routing#route-caching)。Folio 監聽 `route:cache` Artisan 指令,以確保 Folio 頁面定義和路由名稱被正確快取,以獲得最佳效能。 342 | -------------------------------------------------------------------------------- /frontend.md: -------------------------------------------------------------------------------- 1 | # 前端 2 | 3 | - [簡介](#introduction) 4 | - [使用 PHP](#using-php) 5 | - [PHP 和 Blade](#php-and-blade) 6 | - [Livewire](#livewire) 7 | - [入門套件](#php-starter-kits) 8 | - [使用 React 或 Vue](#using-react-or-vue) 9 | - [Inertia](#inertia) 10 | - [入門套件](#inertia-starter-kits) 11 | - [打包資源檔](#bundling-assets) 12 | 13 | 14 | ## 簡介 15 | 16 | Laravel 是一個後端框架,提供了建立現代 Web 應用程式所需的所有功能,例如 [路由](/docs/{{version}}/routing)、[驗證](/docs/{{version}}/validation)、[快取](/docs/{{version}}/cache)、[佇列](/docs/{{version}}/queues)、[檔案儲存](/docs/{{version}}/filesystem) 等。然而,我們認為為開發人員提供美觀的全端體驗是很重要的,包括強大的方法來建立應用程式的前端。 17 | 18 | 在使用 Laravel 建立應用程式時,有兩種主要方式來處理前端開發,您可以選擇使用 PHP 或使用 JavaScript 框架如 Vue 和 React 來建立前端。我們將在下面討論這兩種選項,讓您可以就應用程式的前端開發最佳方式做出明智的決定。 19 | 20 | 21 | ## 使用 PHP 22 | 23 | 24 | ### PHP 和 Blade 25 | 26 | 過去,大多數 PHP 應用程式使用簡單的 HTML 模板與 PHP `echo` 陳述式將 HTML 渲染到瀏覽器,這些陳述式會渲染在請求期間從資料庫擷取的資料: 27 | 28 | ```blade 29 |
30 | 31 | Hello, name; ?>
32 | 33 |
34 | ``` 35 | 36 | 在 Laravel 中,仍然可以使用 [視圖](/docs/{{version}}/views) 和 [Blade](/docs/{{version}}/blade) 實現這種渲染 HTML 的方式。Blade 是一種非常輕量級的模板語言,提供了方便、簡短的語法來顯示資料、迭代資料等: 37 | 38 | ```blade 39 |
40 | @foreach ($users as $user) 41 | Hello, {{ $user->name }}
42 | @endforeach 43 |
44 | ``` 45 | 46 | 以這種方式建立應用程式時,表單提交和其他頁面互動通常會從伺服器接收到一個全新的 HTML 文件,並且整個頁面會被瀏覽器重新渲染。即使在今天,許多應用程式可能非常適合以這種方式構建其前端,使用簡單的 Blade 模板。 47 | 48 | #### 日益增長的期望 49 | 50 | 然而,隨著用戶對 Web 應用程序的期望日益成熟,許多開發人員發現需要構建更具動態性的前端,使互動感覺更加精緻。鑑於此,一些開發人員選擇開始使用 JavaScript 框架(如 Vue 和 React)來構建其應用程序的前端。 51 | 52 | 其他人則更傾向於堅持使用他們熟悉的後端語言,開發出允許構建現代 Web 應用程序 UI 的解決方案,同時仍主要利用他們選擇的後端語言。例如,在 [Rails](https://rubyonrails.org/) 生態系統中,這促使了像 [Turbo](https://turbo.hotwired.dev/)、[Hotwire](https://hotwired.dev/) 和 [Stimulus](https://stimulus.hotwired.dev/) 這樣的庫的創建。 53 | 54 | 在 Laravel 生態系統中,通過主要使用 PHP 創建現代、動態的前端的需求導致了 [Laravel Livewire](https://livewire.laravel.com) 和 [Alpine.js](https://alpinejs.dev/) 的創建。 55 | 56 | ### Livewire 57 | 58 | [Laravel Livewire](https://livewire.laravel.com) 是一個用於構建 Laravel 驅動的前端的框架,使其感覺動態、現代且生動,就像使用現代 JavaScript 框架(如 Vue 和 React)構建的前端一樣。 59 | 60 | 使用 Livewire 時,您將創建 Livewire "組件",這些組件呈現 UI 的一個獨立部分,並公開可以從應用程序的前端調用和互動的方法和數據。例如,一個簡單的 "Counter" 組件可能如下所示: 61 | 62 | ```php 63 | count++; 76 | } 77 | 78 | public function render() 79 | { 80 | return view('livewire.counter'); 81 | } 82 | } 83 | ``` 84 | 85 | 相應的計數器模板將如下所示: 86 | 87 | ```blade 88 |
89 | 90 |

{{ $count }}

91 |
92 | ``` 93 | 94 | 正如您所看到的,Livewire 讓您編寫新的 HTML 屬性,如 `wire:click`,將您的 Laravel 應用程序的前端和後端連接起來。此外,您可以使用簡單的 Blade 表達式呈現組件的當前狀態。 95 | 96 | 對許多人來說,Livewire 已經革新了 Laravel 的前端開發,使他們能夠在構建現代、動態 Web 應用程序時保持 Laravel 的舒適感。通常,使用 Livewire 的開發人員還將利用 [Alpine.js](https://alpinejs.dev/) 在前端上僅在需要時 "撒點" JavaScript,例如為了呈現對話框。 97 | 98 | 如果您是 Laravel 的新手,我們建議您熟悉 [視圖](/docs/{{version}}/views) 和 [Blade](/docs/{{version}}/blade) 的基本用法。然後,請參考官方的 [Laravel Livewire 文件](https://livewire.laravel.com/docs),了解如何通過互動式 Livewire 元件將應用程序提升到下一個水平。 99 | 100 | 101 | ### 起始套件 102 | 103 | 如果您想使用 PHP 和 Livewire 構建前端,您可以利用我們的 [Livewire 起始套件](/docs/{{version}}/starter-kits) 來加速應用程序的開發。 104 | 105 | 106 | ## 使用 React 或 Vue 107 | 108 | 儘管使用 Laravel 和 Livewire 可以構建現代前端,但許多開發人員仍然更喜歡利用像 React 或 Vue 這樣的 JavaScript 框架的強大功能。這使開發人員能夠利用通過 NPM 提供的豐富 JavaScript 套件和工具生態系統。 109 | 110 | 然而,如果沒有額外的工具支持,將 Laravel 與 React 或 Vue 搭配使用將需要解決各種複雜的問題,例如客戶端路由、數據注入和身份驗證。通常,使用具有明確意見的 React / Vue 框架(如 [Next](https://nextjs.org/) 和 [Nuxt](https://nuxt.com/))可以簡化客戶端路由,但數據注入和身份驗證仍然是搭配後端框架像 Laravel 與這些前端框架時需要解決的複雜和繁瑣的問題。 111 | 112 | 此外,開發人員需要維護兩個獨立的程式庫,通常需要協調兩個程式庫之間的維護、發布和部署。雖然這些問題並非無法克服,但我們認為這不是一種有效或令人愉快的應用程序開發方式。 113 | 114 | 115 | ### Inertia 116 | 117 | 幸運的是,Laravel 提供了最佳的解決方案。[Inertia](https://inertiajs.com) 橋接了您的 Laravel 應用程序與現代 React 或 Vue 前端之間的差距,使您可以使用 React 或 Vue 構建完整的現代前端,同時利用 Laravel 的路由和控制器進行路由、數據注入和身份驗證 — 一切都在單一程式庫中。通過這種方法,您可以充分發揮 Laravel 和 React / Vue 的功能,而不會削弱任何工具的功能。 118 | 119 | 在將 Inertia 安裝到您的 Laravel 應用程式之後,您將像平常一樣編寫路由和控制器。但是,您將不再從控制器返回 Blade 模板,而是返回一個 Inertia 頁面: 120 | 121 | ```php 122 | User::findOrFail($id) 140 | ]); 141 | } 142 | } 143 | ``` 144 | 145 | Inertia 頁面對應於 React 或 Vue 元件,通常存儲在應用程式的 `resources/js/pages` 目錄中。通過 `Inertia::render` 方法提供給頁面的數據將用於填充頁面元件的 "props": 146 | 147 | ```jsx 148 | import Layout from '@/layouts/authenticated'; 149 | import { Head } from '@inertiajs/react'; 150 | 151 | export default function Show({ user }) { 152 | return ( 153 | 154 | 155 |

Welcome

156 |

Hello {user.name}, welcome to Inertia.

157 |
158 | ) 159 | } 160 | ``` 161 | 162 | 正如您所看到的,Inertia 允許您在構建前端時充分利用 React 或 Vue 的功能,同時在 Laravel 強大的後端和 JavaScript 強大的前端之間提供輕量級的橋樑。 163 | 164 | #### 伺服器端渲染 165 | 166 | 如果您擔心深入研究 Inertia,因為您的應用程式需要伺服器端渲染,請不用擔心。Inertia 提供了 [伺服器端渲染支援](https://inertiajs.com/server-side-rendering)。而且,當通過 [Laravel Cloud](https://cloud.laravel.com) 或 [Laravel Forge](https://forge.laravel.com) 部署您的應用程式時,確保 Inertia 的伺服器端渲染過程始終運行非常輕鬆。 167 | 168 | 169 | ### 起始套件 170 | 171 | 如果您想使用 Inertia 和 Vue / React 構建您的前端,您可以利用我們的 [React 或 Vue 應用程式起始套件](/docs/{{version}}/starter-kits) 來快速啟動應用程式的開發。這兩個起始套件都使用 Inertia、Vue / React、[Tailwind](https://tailwindcss.com) 和 [Vite](https://vitejs.dev) 為您的應用程式的後端和前端身份驗證流程搭建腳手架,讓您可以開始構建您的下一個大型項目。 172 | 173 | 174 | ## 打包資源檔 175 | 176 | 無論您選擇使用 Blade 和 Livewire 還是 Vue / React 和 Inertia 開發前端,您可能需要將應用程式的 CSS 打包成產品就緒的資源檔。當然,如果您選擇使用 Vue 或 React 構建應用程式的前端,您還需要將組件打包成瀏覽器就緒的 JavaScript 資源檔。 177 | 178 | 預設情況下,Laravel 使用 [Vite](https://vitejs.dev) 來打包您的資源檔。Vite 提供快速的建置時間和在本地開發期間幾乎即時的熱模組替換(HMR)。在所有新的 Laravel 應用程式中,包括使用我們的 [入門套件](/docs/{{version}}/starter-kits) 的應用程式,您將找到一個 `vite.config.js` 檔案,該檔案載入我們輕量級的 Laravel Vite 插件,使 Vite 與 Laravel 應用程式一起使用變得輕鬆愉快。 179 | 180 | 使用 Laravel 和 Vite 開始應用程式開發的最快方法是使用 [我們的應用程式入門套件](/docs/{{version}}/starter-kits),這些套件通過提供前端和後端認證脚手架來快速啟動您的應用程式。 181 | 182 | > [!NOTE] 183 | > 有關在 Laravel 中使用 Vite 的更詳細文件,請參閱我們關於打包和編譯您的資源檔的 [專用文件](/docs/{{version}}/vite)。 184 | -------------------------------------------------------------------------------- /hashing.md: -------------------------------------------------------------------------------- 1 | # 雜湊 2 | 3 | - [簡介](#introduction) 4 | - [組態設定](#configuration) 5 | - [基本使用](#basic-usage) 6 | - [雜湊密碼](#hashing-passwords) 7 | - [驗證密碼是否符合雜湊](#verifying-that-a-password-matches-a-hash) 8 | - [確定是否需要重新雜湊密碼](#determining-if-a-password-needs-to-be-rehashed) 9 | - [雜湊演算法驗證](#hash-algorithm-verification) 10 | 11 | 12 | ## 簡介 13 | 14 | Laravel `Hash` [facade](/docs/{{version}}/facades) 提供安全的 Bcrypt 和 Argon2 雜湊功能,用於儲存使用者密碼。如果您使用其中一個 [Laravel 應用程式起始套件](/docs/{{version}}/starter-kits),預設將使用 Bcrypt 進行註冊和驗證。 15 | 16 | Bcrypt 是雜湊密碼的絕佳選擇,因為其 "加密係數" 可調整,這意味著生成雜湊所需的時間可以隨著硬體性能的提升而增加。在雜湊密碼時,速度較慢是好事。演算法花費的時間越長,惡意使用者生成所有可能的字串雜湊值的 "彩虹表" 用於對應用程式進行暴力攻擊的時間就越長。 17 | 18 | 19 | ## 組態設定 20 | 21 | 預設情況下,Laravel 在雜湊資料時使用 `bcrypt` 驅動程式。但是,還支援其他幾種雜湊驅動程式,包括 [`argon`](https://en.wikipedia.org/wiki/Argon2) 和 [`argon2id`](https://en.wikipedia.org/wiki/Argon2)。 22 | 23 | 您可以使用 `HASH_DRIVER` 環境變數指定應用程式的雜湊驅動程式。但是,如果您想自訂 Laravel 的所有雜湊驅動程式選項,應該使用 `config:publish` Artisan 指令發佈完整的 `hashing` 組態檔案: 24 | 25 | ```shell 26 | php artisan config:publish hashing 27 | ``` 28 | 29 | 30 | ## 基本使用 31 | 32 | 33 | ### 雜湊密碼 34 | 35 | 您可以通過在 `Hash` facade 上調用 `make` 方法來雜湊密碼: 36 | 37 | ```php 38 | user()->fill([ 56 | 'password' => Hash::make($request->newPassword) 57 | ])->save(); 58 | 59 | return redirect('/profile'); 60 | } 61 | } 62 | ``` 63 | 64 | 65 | #### 調整 Bcrypt 加密係數 66 | 67 | 如果您使用 Bcrypt 算法,`make` 方法允許您使用 `rounds` 選項來管理算法的工作因子;但是,Laravel 管理的默認工作因子對大多數應用程序來說是可以接受的: 68 | 69 | ```php 70 | $hashed = Hash::make('password', [ 71 | 'rounds' => 12, 72 | ]); 73 | ``` 74 | 75 | 76 | #### 調整 Argon2 工作因子 77 | 78 | 如果您使用 Argon2 算法,`make` 方法允許您使用 `memory`、`time` 和 `threads` 選項來管理算法的工作因子;但是,Laravel 管理的默認值對大多數應用程序來說是可以接受的: 79 | 80 | ```php 81 | $hashed = Hash::make('password', [ 82 | 'memory' => 1024, 83 | 'time' => 2, 84 | 'threads' => 2, 85 | ]); 86 | ``` 87 | 88 | > [!NOTE] 89 | > 有關這些選項的更多信息,請參閱[官方 PHP 文檔有關 Argon 雜湊](https://secure.php.net/manual/en/function.password-hash.php)。 90 | 91 | 92 | ### 驗證密碼是否與雜湊匹配 93 | 94 | `Hash` Facade 提供的 `check` 方法允許您驗證給定的明文字符串是否與給定的雜湊相對應: 95 | 96 | ```php 97 | if (Hash::check('plain-text', $hashedPassword)) { 98 | // 密碼匹配... 99 | } 100 | ``` 101 | 102 | 103 | ### 確定是否需要重新雜湊密碼 104 | 105 | `Hash` Facade 提供的 `needsRehash` 方法允許您確定雜湊器使用的工作因子是否自雜湊密碼後已更改。一些應用程序選擇在應用程序的身份驗證過程中執行此檢查: 106 | 107 | ```php 108 | if (Hash::needsRehash($hashed)) { 109 | $hashed = Hash::make('plain-text'); 110 | } 111 | ``` 112 | 113 | 114 | ## 雜湊算法驗證 115 | 116 | 為了防止雜湊算法操縱,Laravel 的 `Hash::check` 方法將首先驗證給定的雜湊是否是使用應用程序選定的雜湊算法生成的。如果算法不同,將拋出 `RuntimeException` 異常。 117 | 118 | 對於大多數應用程序來說,這是預期的行為,其中不希望雜湊算法發生變化,不同的算法可能表明存在惡意攻擊。但是,如果您需要在應用程序中支持多個雜湊算法,例如從一種算法遷移至另一種算法時,您可以通過將 `HASH_VERIFY` 環境變量設置為 `false` 來禁用雜湊算法驗證: 119 | 120 | ```ini 121 | HASH_VERIFY=false 122 | ``` 123 | -------------------------------------------------------------------------------- /installation.md: -------------------------------------------------------------------------------- 1 | # 安裝 2 | 3 | - [認識 Laravel](#meet-laravel) 4 | - [為什麼選擇 Laravel?](#why-laravel) 5 | - [建立 Laravel 應用程式](#creating-a-laravel-project) 6 | - [安裝 PHP 和 Laravel 安裝程式](#installing-php) 7 | - [建立應用程式](#creating-an-application) 8 | - [初始設定](#initial-configuration) 9 | - [基於環境的設定](#environment-based-configuration) 10 | - [資料庫和遷移](#databases-and-migrations) 11 | - [目錄設定](#directory-configuration) 12 | - [使用 Herd 進行安裝](#installation-using-herd) 13 | - [在 macOS 上使用 Herd](#herd-on-macos) 14 | - [在 Windows 上使用 Herd](#herd-on-windows) 15 | - [IDE 支援](#ide-support) 16 | - [下一步](#next-steps) 17 | - [Laravel 完整堆疊框架](#laravel-the-fullstack-framework) 18 | - [Laravel API 後端](#laravel-the-api-backend) 19 | 20 | 21 | ## 認識 Laravel 22 | 23 | Laravel 是一個具有表達力和優雅語法的 Web 應用程式框架。一個 Web 框架提供了創建應用程式的結構和起點,讓您可以專注於創建令人驚嘆的作品,而我們則負責細節。 24 | 25 | Laravel 致力於提供令人驚嘆的開發者體驗,同時提供強大的功能,如全面的依賴注入、表達性的資料庫抽象層、佇列和定時任務、單元和整合測試等。 26 | 27 | 無論您是 PHP Web 框架的新手還是有多年經驗,Laravel 都是一個能與您共同成長的框架。我們將幫助您作為 Web 開發人員邁出第一步,或者在您將專業知識提升到新水平時給予您支持。我們迫不及待想看到您的成就。 28 | 29 | 30 | ### 為什麼選擇 Laravel? 31 | 32 | 在建立 Web 應用程式時,有各種工具和框架可供選擇。然而,我們認為 Laravel 是建立現代、全堆疊 Web 應用程式的最佳選擇。 33 | 34 | #### 一個進步的框架 35 | 36 | 我們喜歡稱 Laravel 為一個「進步」的框架。這意味著 Laravel 會隨著您的成長而成長。如果您剛踏入 Web 開發的領域,Laravel 齊全的文件庫、指南和[影片教學](https://laracasts.com)將幫助您學習基礎知識,而不會讓您感到不知所措。 37 | 38 | 如果您是一位資深開發人員,Laravel 為您提供了強大的工具,用於[依賴注入](/docs/{{version}}/container)、[單元測試](/docs/{{version}}/testing)、[佇列](/docs/{{version}}/queues)、[即時事件](/docs/{{version}}/broadcasting)等等。Laravel 經過精心調校,適用於構建專業的 Web 應用程式,並且能夠處理企業級工作負載。 39 | 40 | #### 一個可擴展的框架 41 | 42 | Laravel 具有極高的擴展性。由於 PHP 和 Laravel 內建對於快速、分佈式快取系統如 Redis 的支援,使用 Laravel 進行水平擴展非常輕鬆。事實上,Laravel 應用程式已經輕鬆擴展,能夠處理每月數億次的請求。 43 | 44 | 需要極端擴展?像[Laravel Cloud](https://cloud.laravel.com)這樣的平台讓您可以將 Laravel 應用程式運行在幾乎無限的規模上。 45 | 46 | #### 一個社群框架 47 | 48 | Laravel 結合了 PHP 生態系統中最優秀的套件,提供了最強大且開發者友好的框架。此外,來自世界各地的成千上萬位有才華的開發者[貢獻了這個框架](https://github.com/laravel/framework)。誰知道,也許您甚至會成為 Laravel 的貢獻者。 49 | 50 | 51 | ## 創建 Laravel 應用程式 52 | 53 | 54 | ### 安裝 PHP 和 Laravel 安裝程式 55 | 56 | 在創建您的第一個 Laravel 應用程式之前,請確保您的本地機器已安裝[PHP](https://php.net)、[Composer](https://getcomposer.org)和[Laravel 安裝程式](https://github.com/laravel/installer)。此外,您應安裝[Node 和 NPM](https://nodejs.org)或[Bun](https://bun.sh/),以便編譯應用程式的前端資源。 57 | 58 | 如果您的本地機器尚未安裝 PHP 和 Composer,以下命令將在 macOS、Windows 或 Linux 上安裝 PHP、Composer 和 Laravel 安裝程式: 59 | 60 | ```shell tab=macOS 61 | /bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)" 62 | ``` 63 | 64 | ```shell tab=Windows PowerShell 65 | # 以系統管理員身份執行... 66 | Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://php.new/install/windows/8.4')) 67 | ``` 68 | 69 | ```shell tab=Linux 70 | /bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)" 71 | ``` 72 | 73 | 執行上述其中一個命令後,您應該重新啟動您的終端機會話。在通過 `php.new` 安裝 PHP、Composer 和 Laravel 安裝程式後,您可以在終端機中重新運行命令來更新它們。 74 | 75 | 如果您已經安裝了 PHP 和 Composer,您可以通過 Composer 安裝 Laravel 安裝程式: 76 | 77 | ```shell 78 | composer global require laravel/installer 79 | ``` 80 | 81 | > [!NOTE] 82 | > 若要獲得完整功能的圖形化 PHP 安裝和管理體驗,請查看 [Laravel Herd](#installation-using-herd)。 83 | 84 | 85 | ### 創建應用程式 86 | 87 | 安裝 PHP、Composer 和 Laravel 安裝程式後,您就可以開始創建新的 Laravel 應用程式。Laravel 安裝程式將提示您選擇首選的測試框架、資料庫和起始套件: 88 | 89 | ```shell 90 | laravel new example-app 91 | ``` 92 | 93 | 應用程式創建完成後,您可以使用 `dev` Composer 腳本啟動 Laravel 的本地開發伺服器、佇列工作者和 Vite 開發伺服器: 94 | 95 | ```shell 96 | cd example-app 97 | npm install && npm run build 98 | composer run dev 99 | ``` 100 | 101 | 啟動開發伺服器後,您可以在網頁瀏覽器中訪問您的應用程式,網址為 [http://localhost:8000](http://localhost:8000)。接下來,您可以準備 [進入 Laravel 生態系統的下一步](#next-steps)。當然,您可能還想 [配置資料庫](#databases-and-migrations)。 102 | 103 | > [!NOTE] 104 | > 如果您希望在開發 Laravel 應用程式時有一個起步優勢,請考慮使用我們的 [起始套件](/docs/{{version}}/starter-kits) 之一。Laravel 的起始套件為您的新 Laravel 應用程式提供了後端和前端驗證結構。 105 | 106 | 107 | ## 初始設定 108 | 109 | Laravel 框架的所有組態檔案都存儲在 `config` 目錄中。每個選項都有文件記錄,因此請隨意查看文件並熟悉可用的選項。 110 | 111 | Laravel 在開箱即用時幾乎不需要額外的配置。您可以自由開始開發!但是,您可能希望查看 `config/app.php` 文件及其文檔。它包含了一些選項,例如 `url` 和 `locale`,您可能希望根據應用程序進行更改。 112 | 113 | 114 | ### 基於環境的配置 115 | 116 | 由於 Laravel 的許多配置選項值可能會根據應用程序是在本地計算機上運行還是在生產 Web 伺服器上運行而有所不同,許多重要的配置值是使用存在於應用程序根目錄下的 `.env` 文件來定義的。 117 | 118 | 您的 `.env` 文件不應該提交到應用程序的源代碼控制中,因為使用您的應用程序的每個開發人員/伺服器可能需要不同的環境配置。此外,在入侵者獲得對您的源代碼存儲庫的訪問權限時,這將是一個安全風險,因為任何敏感憑證將被公開。 119 | 120 | > [!NOTE] 121 | > 有關 `.env` 文件和基於環境的配置的更多信息,請查看完整的 [配置文檔](/docs/{{version}}/configuration#environment-configuration)。 122 | 123 | 124 | ### 資料庫和遷移 125 | 126 | 現在您已經創建了 Laravel 應用程序,您可能希望在資料庫中存儲一些數據。默認情況下,您的應用程序的 `.env` 配置文件指定 Laravel 將與 SQLite 資料庫交互。 127 | 128 | 在創建應用程序時,Laravel 為您創建了一個 `database/database.sqlite` 文件,並運行了必要的遷移以創建應用程序的資料庫表。 129 | 130 | 如果您希望使用其他資料庫驅動程序,例如 MySQL 或 PostgreSQL,您可以更新您的 `.env` 配置文件以使用適當的資料庫。例如,如果您希望使用 MySQL,請像這樣更新您的 `.env` 配置文件中的 `DB_*` 變數: 131 | 132 | ```ini 133 | DB_CONNECTION=mysql 134 | DB_HOST=127.0.0.1 135 | DB_PORT=3306 136 | DB_DATABASE=laravel 137 | DB_USERNAME=root 138 | DB_PASSWORD= 139 | ``` 140 | 141 | 如果您選擇使用除 SQLite 外的其他資料庫,您將需要創建該資料庫並運行應用程序的 [資料庫遷移](/docs/{{version}}/migrations): 142 | 143 | ```shell 144 | php artisan migrate 145 | ``` 146 | 147 | > [!NOTE] 148 | > 如果您在 macOS 或 Windows 上進行開發並需要在本地安裝 MySQL、PostgreSQL 或 Redis,請考慮使用 [Herd Pro](https://herd.laravel.com/#plans) 或 [DBngin](https://dbngin.com/)。 149 | 150 | 151 | ### 目錄配置 152 | 153 | Laravel 應始終在為您的 Web 伺服器配置的 "Web 目錄" 的根目錄中提供服務。您不應試圖在 "Web 目錄" 的子目錄中提供 Laravel 應用程式的服務。這樣做可能會使應用程式中存在的敏感檔案暴露出來。 154 | 155 | 156 | ## 使用 Herd 進行安裝 157 | 158 | [Laravel Herd](https://herd.laravel.com) 是一個針對 macOS 和 Windows 的極速本機 Laravel 和 PHP 開發環境。Herd 包含了您開始使用 Laravel 開發所需的一切,包括 PHP 和 Nginx。 159 | 160 | 安裝完 Herd 後,您就可以開始使用 Laravel 進行開發了。Herd 包含了 `php`、`composer`、`laravel`、`expose`、`node`、`npm` 和 `nvm` 的命令列工具。 161 | 162 | > [!NOTE] 163 | > [Herd Pro](https://herd.laravel.com/#plans) 通過提供額外強大功能,例如創建和管理本地 MySQL、Postgres 和 Redis 資料庫,以及本地郵件查看和日誌監控等功能,增強了 Herd。 164 | 165 | 166 | ### 在 macOS 上使用 Herd 167 | 168 | 如果您在 macOS 上進行開發,您可以從 [Herd 網站](https://herd.laravel.com) 下載 Herd 安裝程式。安裝程式會自動下載最新版本的 PHP,並配置您的 Mac 以始終在背景運行 [Nginx](https://www.nginx.com/)。 169 | 170 | macOS 上的 Herd 使用 [dnsmasq](https://en.wikipedia.org/wiki/Dnsmasq) 來支援 "停放" 目錄。任何位於停放目錄中的 Laravel 應用程式將自動由 Herd 提供服務。預設情況下,Herd 在 `~/Herd` 創建了一個停放目錄,您可以使用其目錄名稱在 `.test` 域上訪問此目錄中的任何 Laravel 應用程式。 171 | 172 | 安裝完 Herd 後,創建新的 Laravel 應用程式的最快方式是使用與 Herd 捆綁的 Laravel CLI: 173 | 174 | 當然,您可以隨時通過Herd的UI管理您的停放目錄和其他PHP設置,該UI可以從系統托盤中的Herd菜單中打開。 175 | 176 | 您可以通過查看[Herd文檔](https://herd.laravel.com/docs)來了解更多關於Herd的信息。 177 | 178 | 179 | ### Windows上的Herd 180 | 181 | 您可以從[Herd網站](https://herd.laravel.com/windows)下載Windows版的Herd安裝程序。安裝完成後,您可以啟動Herd以完成入門流程,並首次訪問Herd UI。 182 | 183 | 通過在Herd的系統托盤圖標上單擊左鍵,即可訪問Herd UI。右鍵單擊會打開快速菜單,其中包含您日常所需的所有工具。 184 | 185 | 在安裝期間,Herd會在您的主目錄下的`%USERPROFILE%\Herd`創建一個“停放”目錄。任何位於停放目錄中的Laravel應用程序都將由Herd自動提供服務,您可以使用其目錄名在`.test`域上訪問此目錄中的任何Laravel應用程序。 186 | 187 | 安裝完Herd後,創建新的Laravel應用程序的最快方法是使用與Herd捆綁的Laravel CLI。要開始,打開Powershell並運行以下命令: 188 | 189 | ```shell 190 | cd ~\Herd 191 | laravel new my-app 192 | cd my-app 193 | herd open 194 | ``` 195 | 196 | 您可以通過查看[Herd Windows文檔](https://herd.laravel.com/docs/windows)來了解更多關於Herd的信息。 197 | 198 | 199 | ## IDE支援 200 | 201 | 在開發Laravel應用程序時,您可以自由選擇任何代碼編輯器;但是,[PhpStorm](https://www.jetbrains.com/phpstorm/laravel/)為Laravel及其生態系統提供廣泛支持,包括[Laravel Pint](https://www.jetbrains.com/help/phpstorm/using-laravel-pint.html)。 202 | 203 | 此外,由社區維護的[Laravel Idea](https://laravel-idea.com/) PhpStorm插件提供各種有用的IDE增強功能,包括代碼生成、Eloquent語法完成、驗證規則完成等。 204 | 205 | 如果您在[Visual Studio Code (VS Code)](https://code.visualstudio.com)中開發,現在可以使用官方的[Laravel VS Code擴展](https://marketplace.visualstudio.com/items?itemName=laravel.vscode-laravel)。此擴展將Laravel特定工具直接引入您的VS Code環境,提高生產力。 206 | 207 | ## 下一步 208 | 209 | 現在您已經建立了您的 Laravel 應用程式,您可能想知道接下來該學習什麼。首先,我們強烈建議通過閱讀以下文件來熟悉 Laravel 的運作方式: 210 | 211 |
212 | 213 | - [請求生命週期](/docs/{{version}}/lifecycle) 214 | - [組態設定](/docs/{{version}}/configuration) 215 | - [目錄結構](/docs/{{version}}/structure) 216 | - [前端](/docs/{{version}}/frontend) 217 | - [服務容器](/docs/{{version}}/container) 218 | - [Facades](/docs/{{version}}/facades) 219 | 220 |
221 | 222 | 您想如何使用 Laravel 也將決定您旅程中的下一步。有多種使用 Laravel 的方式,我們將在下面探討框架的兩個主要用例。 223 | 224 | ### Laravel 全棧框架 225 | 226 | Laravel 可以作為一個全棧框架。通過 "全棧" 框架,我們指的是您將使用 Laravel 將請求路由到您的應用程式並通過 [Blade 模板](/docs/{{version}}/blade) 或單頁應用程式混合技術如 [Inertia](https://inertiajs.com) 渲染您的前端。這是使用 Laravel 框架的最常見方式,也是我們認為最有效率的使用 Laravel 的方式。 227 | 228 | 如果這是您計劃使用 Laravel 的方式,您可能希望查看我們的 [前端開發](/docs/{{version}}/frontend)、[路由](/docs/{{version}}/routing)、[視圖](/docs/{{version}}/views) 或 [Eloquent ORM](/docs/{{version}}/eloquent) 的文件。此外,您可能有興趣了解像 [Livewire](https://livewire.laravel.com) 和 [Inertia](https://inertiajs.com) 這樣的社區套件。這些套件允許您將 Laravel 用作全棧框架,同時享受單頁 JavaScript 應用程式提供的許多 UI 優勢。 229 | 230 | 如果您將 Laravel 用作全棧框架,我們還強烈建議您學習如何使用 [Vite](/docs/{{version}}/vite) 編譯應用程式的 CSS 和 JavaScript。 231 | 232 | > [!NOTE] 233 | > 如果您想要快速開始構建您的應用程式,請查看我們其中一個官方 [應用程式起始套件](/docs/{{version}}/starter-kits)。 234 | 235 | ### Laravel API 後端 236 | 237 | Laravel 也可以作為 JavaScript 單頁應用程式或行動應用程式的 API 後端。例如,您可以將 Laravel 用作您的 [Next.js](https://nextjs.org) 應用程式的 API 後端。在這種情況下,您可以使用 Laravel 為應用程式提供 [認證](/docs/{{version}}/sanctum) 和資料存儲/檢索,同時還可以利用 Laravel 強大的服務,如佇列、郵件、通知等。 238 | 239 | 如果這是您計劃使用 Laravel 的方式,您可能會想查看我們關於 [路由](/docs/{{version}}/routing)、[Laravel Sanctum](/docs/{{version}}/sanctum) 和 [Eloquent ORM](/docs/{{version}}/eloquent) 的文件。 240 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | MIT 許可證(MIT) 2 | 3 | 版權所有(c)Taylor Otwell 4 | 5 | 特此授權,免費提供給任何獲得本軟體及相關文件(以下簡稱「軟體」)副本的人,無需付費,可以處理軟體,包括但不限於使用、複製、修改、合併、發布、散布、許可和/或銷售軟體的副本,並允許軟體的提供者這樣做,但需遵守以下條件: 6 | 7 | 上述版權聲明和此授權聲明應包含在所有副本或重要部分的軟體中。 8 | 9 | 本軟體按「原樣」提供,不提供任何形式的保證,明示或暗示,包括但不限於對商品性、特定目的的適用性和非侵權性的保證。在任何情況下,作者或版權持有人均不對任何索賠、損害或其他責任負責,無論是合同行為、侵權行為或其他行為,因使用本軟體或與本軟體的使用或其他交易而引起。 10 | -------------------------------------------------------------------------------- /lifecycle.md: -------------------------------------------------------------------------------- 1 | # 請求生命週期 2 | 3 | - [簡介](#introduction) 4 | - [生命週期概述](#lifecycle-overview) 5 | - [首要步驟](#first-steps) 6 | - [HTTP / 控制台核心](#http-console-kernels) 7 | - [服務提供者](#service-providers) 8 | - [路由](#routing) 9 | - [完成](#finishing-up) 10 | - [專注於服務提供者](#focus-on-service-providers) 11 | 12 | 13 | ## 簡介 14 | 15 | 在現實世界中使用任何工具時,如果您了解該工具的運作方式,就會更有信心。應用程式開發也不例外。當您了解開發工具的運作方式時,您會更加自在和自信。 16 | 17 | 本文件的目標是為您提供 Laravel 框架運作方式的良好高層級概述。通過更好地了解整個框架,一切都不再那麼「神奇」,您將更有信心地構建應用程式。如果您一開始不了解所有術語,不要灰心!只需試著基本理解正在發生的事情,當您探索文件的其他部分時,您的知識將會增長。 18 | 19 | 20 | ## 生命週期概述 21 | 22 | 23 | ### 首要步驟 24 | 25 | 所有對 Laravel 應用程式的請求的入口點是 `public/index.php` 檔案。所有請求都通過您的網頁伺服器(Apache / Nginx)配置將其導向此檔案。`index.php` 檔案並不包含太多程式碼。相反,它是加載框架其餘部分的起點。 26 | 27 | `index.php` 檔案加載 Composer 生成的自動載入器定義,然後從 `bootstrap/app.php` 中檢索 Laravel 應用程式的實例。Laravel 本身採取的第一個動作是創建應用程式 / [服務容器](/docs/{{version}}/container) 的實例。 28 | 29 | 30 | ### HTTP / 控制台核心 31 | 32 | 接下來,傳入的請求根據進入應用程式的請求類型,使用應用程式實例的 `handleRequest` 或 `handleCommand` 方法,被發送到 HTTP 核心或控制台核心。這兩個核心作為所有請求流經的中心位置。現在,讓我們專注於 HTTP 核心,這是 `Illuminate\Foundation\Http\Kernel` 的一個實例。 33 | 34 | HTTP 核心定義了一個 `bootstrappers` 陣列,這些將在請求執行之前運行。這些 bootstrappers 配置錯誤處理、配置日誌記錄、[檢測應用程式環境](/docs/{{version}}/configuration#environment-configuration),以及執行其他需要在實際處理請求之前完成的任務。通常,這些類別處理內部 Laravel 配置,您無需擔心。 35 | 36 | HTTP 核心還負責將請求通過應用程式的中介層堆疊。這些中介層處理讀取和寫入 [HTTP 會話](/docs/{{version}}/session),確定應用程式是否處於維護模式,[驗證 CSRF 標記](/docs/{{version}}/csrf),等等。我們很快會更詳細地討論這些。 37 | 38 | HTTP 核心的 `handle` 方法的方法簽名非常簡單:它接收一個 `Request` 並返回一個 `Response`。將核心視為代表整個應用程式的一個大黑盒子。將 HTTP 請求提供給它,它將返回 HTTP 回應。 39 | 40 | 41 | ### 服務提供者 42 | 43 | 最重要的核心啟動操作之一是為您的應用程式加載 [服務提供者](/docs/{{version}}/providers)。服務提供者負責為所有框架的各種組件進行啟動,例如資料庫、佇列、驗證和路由組件。 44 | 45 | Laravel 將遍歷此提供者清單並實例化每個提供者。在實例化提供者之後,將調用所有提供者的 `register` 方法。然後,一旦所有提供者都已註冊,將調用每個提供者的 `boot` 方法。這樣服務提供者可以依賴於其 `boot` 方法執行時所有容器綁定都已註冊並可用。 46 | 47 | 基本上,Laravel 提供的每個主要功能都是由服務提供者進行啟動和配置的。由於它們為框架提供的許多功能進行了啟動和配置,服務提供者是整個 Laravel 啟動過程中最重要的方面。 48 | 49 | 雖然框架內部使用了數十個服務提供者,但您也可以選擇創建自己的服務提供者。您可以在 `bootstrap/providers.php` 檔案中找到應用程式正在使用的使用者定義或第三方服務提供者的清單。 50 | 51 | 52 | ### 路由 53 | 54 | 一旦應用程式已經啟動並且所有服務提供者都已註冊,`Request` 將被傳遞給路由器進行分派。路由器將把請求分派給一個路由或控制器,並運行任何特定路由的中介層。 55 | 56 | 中介層提供了一個方便的機制,用於過濾或檢查進入應用程式的 HTTP 請求。例如,Laravel 包含一個中介層,用於驗證應用程式的使用者是否已經通過身份驗證。如果使用者未通過身份驗證,中介層將將使用者重定向到登錄畫面。但是,如果使用者已通過身份驗證,中介層將允許請求進一步進入應用程式。有些中介層分配給應用程式中的所有路由,如 `PreventRequestsDuringMaintenance`,而有些只分配給特定路由或路由群組。您可以通過閱讀完整的 [中介層文件](/docs/{{version}}/middleware) 來了解更多關於中介層的資訊。 57 | 58 | 如果請求通過了所有匹配路由的指定中介層,則將執行路由或控制器方法,並且由路由或控制器方法返回的回應將通過路由的中介層鏈返回。 59 | 60 | 61 | ### 結束 62 | 63 | 一旦路由或控制器方法返回一個回應,該回應將通過路由的中介層向外傳遞,使應用程式有機會修改或檢查傳出的回應。 64 | 65 | 最後,一旦回應通過中介層返回,HTTP 核心的 `handle` 方法將回應物件返回給應用程式實例的 `handleRequest` 方法,並且此方法調用返回的回應上的 `send` 方法。`send` 方法將回應內容發送給使用者的網頁瀏覽器。我們現在已經完成了整個 Laravel 請求生命週期的旅程! 66 | 67 | ## 專注於服務提供者 68 | 69 | 服務提供者確實是啟動 Laravel 應用程式的關鍵。應用程式實例被建立,服務提供者被註冊,並且請求被傳遞給啟動的應用程式。就是這麼簡單! 70 | 71 | 深入了解 Laravel 應用程式是如何透過服務提供者建構和啟動是非常有價值的。您應用程式自定義的服務提供者被儲存在 `app/Providers` 目錄中。 72 | 73 | 預設情況下,`AppServiceProvider` 是相當空的。這個提供者是一個很好的地方來添加您應用程式自己的啟動和服務容器綁定。對於大型應用程式,您可能希望建立幾個服務提供者,每個提供更細粒度的啟動,針對您應用程式使用的特定服務。 74 | 75 | permalink: https://laravel.com/docs/8.x/providers#focus-on-service-providers 76 | -------------------------------------------------------------------------------- /localization.md: -------------------------------------------------------------------------------- 1 | # 本地化 2 | 3 | - [簡介](#introduction) 4 | - [發佈語言檔案](#publishing-the-language-files) 5 | - [配置語言環境](#configuring-the-locale) 6 | - [複數語言](#pluralization-language) 7 | - [定義翻譯字串](#defining-translation-strings) 8 | - [使用簡短鍵](#using-short-keys) 9 | - [使用翻譯字串作為鍵](#using-translation-strings-as-keys) 10 | - [擷取翻譯字串](#retrieving-translation-strings) 11 | - [替換翻譯字串中的參數](#replacing-parameters-in-translation-strings) 12 | - [複數形式](#pluralization) 13 | - [覆寫套件語言檔案](#overriding-package-language-files) 14 | 15 | 16 | ## 簡介 17 | 18 | > [!NOTE] 19 | > 預設情況下,Laravel 應用程式骨架不包含 `lang` 目錄。如果您想自訂 Laravel 的語言檔案,您可以透過 `lang:publish` Artisan 指令來發佈它們。 20 | 21 | Laravel 的本地化功能提供了一種方便的方式來檢索各種語言的字串,讓您可以輕鬆地在應用程式中支援多種語言。 22 | 23 | Laravel 提供兩種管理翻譯字串的方式。首先,語言字串可以存儲在應用程式的 `lang` 目錄中的檔案中。在這個目錄中,可以為應用程式支援的每種語言建立子目錄。這是 Laravel 用來管理內建 Laravel 功能的翻譯字串的方法,例如驗證錯誤訊息: 24 | 25 | ```text 26 | /lang 27 | /en 28 | messages.php 29 | /es 30 | messages.php 31 | ``` 32 | 33 | 或者,翻譯字串可以定義在放置在 `lang` 目錄中的 JSON 檔案中。當採用這種方法時,您的應用程式支援的每種語言將在此目錄中有一個對應的 JSON 檔案。這種方法適用於具有大量可翻譯字串的應用程式: 34 | 35 | ```text 36 | /lang 37 | en.json 38 | es.json 39 | ``` 40 | 41 | 我們將在本文件中討論管理翻譯字串的每種方法。 42 | 43 | 44 | ### 發佈語言檔案 45 | 46 | 預設情況下,Laravel 應用程式骨架不包含 `lang` 目錄。如果您想要自訂 Laravel 的語言檔案或建立自己的語言檔案,您應該透過 `lang:publish` Artisan 指令來建立 `lang` 目錄。`lang:publish` 指令將在您的應用程式中建立 `lang` 目錄並發佈 Laravel 使用的預設語言檔案集: 47 | 48 | ```shell 49 | php artisan lang:publish 50 | ``` 51 | 52 | 53 | ### 配置語言環境 54 | 55 | 您的應用程式的預設語言存儲在 `config/app.php` 配置檔案的 `locale` 配置選項中,通常使用 `APP_LOCALE` 環境變數來設置。您可以自由修改此值以滿足您應用程式的需求。 56 | 57 | 您也可以配置一個「備用語言」,當預設語言不包含特定的翻譯字串時將使用該語言。與預設語言一樣,備用語言也在 `config/app.php` 配置檔案中配置,其值通常使用 `APP_FALLBACK_LOCALE` 環境變數設置。 58 | 59 | 您可以在運行時使用 `App` Facade 提供的 `setLocale` 方法來修改單個 HTTP 請求的預設語言: 60 | 61 | ```php 62 | use Illuminate\Support\Facades\App; 63 | 64 | Route::get('/greeting/{locale}', function (string $locale) { 65 | if (! in_array($locale, ['en', 'es', 'fr'])) { 66 | abort(400); 67 | } 68 | 69 | App::setLocale($locale); 70 | 71 | // ... 72 | }); 73 | ``` 74 | 75 | 76 | #### 確定當前語言環境 77 | 78 | 您可以使用 `App` Facade 上的 `currentLocale` 和 `isLocale` 方法來確定當前的語言環境或檢查語言環境是否為特定值: 79 | 80 | ```php 81 | use Illuminate\Support\Facades\App; 82 | 83 | $locale = App::currentLocale(); 84 | 85 | if (App::isLocale('en')) { 86 | // ... 87 | } 88 | ``` 89 | 90 | 91 | ### 複數語言 92 | 93 | 您可以指示 Laravel 的「複數化器」,該複數化器由 Eloquent 和框架的其他部分使用,將單數字串轉換為複數字串,使用一種非英語語言。這可以通過在應用程式的服務提供者之一的 `boot` 方法中調用 `useLanguage` 方法來完成。目前支持的複數化器語言有:`french`、`norwegian-bokmal`、`portuguese`、`spanish` 和 `turkish`: 94 | 95 | ```php 96 | use Illuminate\Support\Pluralizer; 97 | 98 | /** 99 | * Bootstrap any application services. 100 | */ 101 | public function boot(): void 102 | { 103 | Pluralizer::useLanguage('spanish'); 104 | 105 | // ... 106 | } 107 | ``` 108 | 109 | > [!WARNING] 110 | > 如果您自定義了複數形式的語言,您應該明確定義您 Eloquent 模型的 [表名稱](/docs/{{version}}/eloquent#table-names)。 111 | 112 | 113 | ## 定義翻譯字串 114 | 115 | 116 | ### 使用簡短鍵 117 | 118 | 通常,翻譯字串存儲在 `lang` 目錄中的文件中。在這個目錄中,應該為應用程序支持的每種語言創建一個子目錄。這是 Laravel 用來管理內置 Laravel 功能的翻譯字串的方法,例如驗證錯誤消息: 119 | 120 | ```text 121 | /lang 122 | /en 123 | messages.php 124 | /es 125 | messages.php 126 | ``` 127 | 128 | 所有語言文件都返回一個鍵入字串的數組。例如: 129 | 130 | ```php 131 | 'Welcome to our application!', 137 | ]; 138 | ``` 139 | 140 | > [!WARNING] 141 | > 對於因地區而異的語言,您應該根據 ISO 15897 命名語言目錄。例如,"en_GB" 應該用於英國英語,而不是 "en-gb"。 142 | 143 | 144 | ### 使用翻譯字串作為鍵 145 | 146 | 對於具有大量可翻譯字串的應用程序,在視圖中引用這些鍵時,使用“簡短鍵”定義每個字串可能會變得混亂,並且為應用程序支持的每個翻譯字串不斷創建鍵也很繁瑣。 147 | 148 | 因此,Laravel 還支持使用字符串的“默認”翻譯作為鍵來定義翻譯字串。使用翻譯字串作為鍵的語言文件存儲為 JSON 文件在 `lang` 目錄中。例如,如果您的應用程序有西班牙語翻譯,您應該創建一個 `lang/es.json` 文件: 149 | 150 | ```json 151 | { 152 | "I love programming.": "Me encanta programar." 153 | } 154 | ``` 155 | 156 | #### 鍵 / 文件衝突 157 | 158 | 您不應定義與其他翻譯文件名相衝突的翻譯字串鍵。例如,為 "NL" 地區翻譯 `__('Action')`,而同時存在 `nl/action.php` 文件但不存在 `nl.json` 文件,將導致翻譯器返回 `nl/action.php` 的整個內容。 159 | 160 | ## 檢索翻譯字串 161 | 162 | 您可以使用 `__` 輔助函式從您的語言檔案中檢索翻譯字串。如果您使用 "簡短鍵" 來定義您的翻譯字串,您應該使用 "點" 語法將包含鍵和鍵本身的檔案傳遞給 `__` 函式。例如,讓我們從 `lang/en/messages.php` 語言檔案中檢索 `welcome` 翻譯字串: 163 | 164 | ```php 165 | echo __('messages.welcome'); 166 | ``` 167 | 168 | 如果指定的翻譯字串不存在,`__` 函式將返回翻譯字串鍵。因此,使用上面的示例,如果翻譯字串不存在,`__` 函式將返回 `messages.welcome`。 169 | 170 | 如果您將[預設翻譯字串作為翻譯鍵](#using-translation-strings-as-keys),您應該將字符串的預設翻譯傳遞給 `__` 函式: 171 | 172 | ```php 173 | echo __('I love programming.'); 174 | ``` 175 | 176 | 同樣,如果翻譯字串不存在,`__` 函式將返回其所給定的翻譯字串鍵。 177 | 178 | 如果您使用[Blade 模板引擎](/docs/{{version}}/blade),您可以使用 `{{ }}` 輸出語法來顯示翻譯字串: 179 | 180 | ```blade 181 | {{ __('messages.welcome') }} 182 | ``` 183 | 184 | ## 替換翻譯字串中的參數 185 | 186 | 如果您希望,您可以在翻譯字串中定義佔位符。所有佔位符都以 `:` 為前綴。例如,您可以定義一個帶有佔位符名稱的歡迎訊息: 187 | 188 | ```php 189 | 'welcome' => '歡迎,:name', 190 | ``` 191 | 192 | 在檢索翻譯字串時替換佔位符,您可以將替換項目的陣列作為第二個引數傳遞給 `__` 函式: 193 | 194 | ```php 195 | echo __('messages.welcome', ['name' => 'dayle']); 196 | ``` 197 | 198 | 如果您的佔位符包含所有大寫字母,或僅首字母大寫,則翻譯值將相應大寫: 199 | 200 | ```php 201 | 'welcome' => '歡迎,:NAME', // 歡迎,DAYLE 202 | 'goodbye' => '再見,:Name', // 再見,Dayle 203 | ``` 204 | 205 | #### 物件替換格式 206 | 207 | 如果您嘗試將物件作為翻譯佔位符,將調用物件的 `__toString` 方法。[`__toString`](https://www.php.net/manual/en/language.oop5.magic.php#object.tostring) 方法是 PHP 內建的「魔術方法」之一。然而,有時您可能無法控制給定類別的 `__toString` 方法,例如當您與屬於第三方函式庫的類別互動時。 208 | 209 | 在這些情況下,Laravel 允許您為該特定類型的物件註冊自訂格式處理程序。為了完成這個任務,您應該調用翻譯器的 `stringable` 方法。`stringable` 方法接受一個閉包,該閉包應該對應負責格式化的物件類型進行型別提示。通常,`stringable` 方法應該在應用程式的 `AppServiceProvider` 類別的 `boot` 方法內調用: 210 | 211 | ```php 212 | use Illuminate\Support\Facades\Lang; 213 | use Money\Money; 214 | 215 | /** 216 | * Bootstrap any application services. 217 | */ 218 | public function boot(): void 219 | { 220 | Lang::stringable(function (Money $money) { 221 | return $money->formatTo('en_GB'); 222 | }); 223 | } 224 | ``` 225 | 226 | #### 複數形式 227 | 228 | 複數形式是一個複雜的問題,因為不同語言有各種複雜的複數形式規則;然而,Laravel 可以幫助您根據您定義的複數形式規則以不同方式翻譯字符串。使用 `|` 字元,您可以區分字符串的單數和複數形式: 229 | 230 | ```php 231 | 'apples' => 'There is one apple|There are many apples', 232 | ``` 233 | 234 | 當使用[翻譯字符串作為鍵](#using-translation-strings-as-keys)時,當然也支持複數形式: 235 | 236 | ```json 237 | { 238 | "There is one apple|There are many apples": "Hay una manzana|Hay muchas manzanas" 239 | } 240 | ``` 241 | 242 | 您甚至可以創建更複雜的複數形式規則,為多個值範圍指定翻譯字符串: 243 | 244 | ```php 245 | 'apples' => '{0} There are none|[1,19] There are some|[20,*] There are many', 246 | ``` 247 | 248 | 在定義具有複數形式選項的翻譯字符串後,您可以使用 `trans_choice` 函數檢索給定「計數」的行。在此示例中,由於計數大於一,將返回翻譯字符串的複數形式: 249 | 250 | ```php 251 | echo trans_choice('messages.apples', 10); 252 | ``` 253 | 254 | 您也可以在複數化字串中定義佔位符屬性。通過將陣列作為 `trans_choice` 函數的第三個參數傳遞,這些佔位符可以被替換: 255 | 256 | ```php 257 | 'minutes_ago' => '{1} :value 分鐘前|[2,*] :value 分鐘前', 258 | 259 | echo trans_choice('time.minutes_ago', 5, ['value' => 5]); 260 | ``` 261 | 262 | 如果您想顯示傳遞給 `trans_choice` 函數的整數值,您可以使用內置的 `:count` 佔位符: 263 | 264 | ```php 265 | 'apples' => '{0} 沒有|{1} 有一個|[2,*] 有 :count 個', 266 | ``` 267 | 268 | 269 | ## 覆蓋套件語言文件 270 | 271 | 有些套件可能會附帶自己的語言文件。您可以通過將文件放置在 `lang/vendor/{package}/{locale}` 目錄中來覆蓋這些行,而不是更改套件的核心文件以調整這些行。 272 | 273 | 例如,如果您需要覆蓋名為 `skyrim/hearthfire` 的套件的 `messages.php` 中的英文翻譯字符串,您應該將語言文件放在:`lang/vendor/hearthfire/en/messages.php`。在這個文件中,您應該只定義您想要覆蓋的翻譯字符串。您不覆蓋的任何翻譯字符串仍將從套件的原始語言文件中加載。 274 | -------------------------------------------------------------------------------- /mix.md: -------------------------------------------------------------------------------- 1 | # Laravel Mix 2 | 3 | - [簡介](#introduction) 4 | 5 | 6 | ## 簡介 7 | 8 | [Laravel Mix](https://github.com/laravel-mix/laravel-mix),由[Laracasts](https://laracasts.com)的創始人Jeffrey Way開發的套件,提供了一個流暢的API,用於為您的Laravel應用程序定義[webpack](https://webpack.js.org)構建步驟,使用幾種常見的CSS和JavaScript預處理器。 9 | 10 | 換句話說,Mix使得編譯和壓縮應用程序的CSS和JavaScript文件變得輕而易舉。通過簡單的方法鏈接,您可以流暢地定義您的資源檔管道。例如: 11 | 12 | ```js 13 | mix.js('resources/js/app.js', 'public/js') 14 | .postCss('resources/css/app.css', 'public/css'); 15 | ``` 16 | 17 | 如果您曾經對開始使用webpack和資源檔編譯感到困惑和不知所措,您會喜歡上Laravel Mix。但是,在開發應用程序時,您並不需要使用它;您可以自由選擇任何您希望使用的資源檔管道工具,甚至可以不使用。 18 | 19 | > [!NOTE] 20 | > Vite已在新的Laravel安裝中取代了Laravel Mix。有關Mix的文檔,請訪問[官方Laravel Mix](https://laravel-mix.com/)網站。如果您想切換到Vite,請查看我們的[Vite遷移指南](https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md#migrating-from-laravel-mix-to-vite)。 21 | -------------------------------------------------------------------------------- /mocking.md: -------------------------------------------------------------------------------- 1 | # 模擬 2 | 3 | - [簡介](#introduction) 4 | - [模擬物件](#mocking-objects) 5 | - [模擬Facades](#mocking-facades) 6 | - [Facade間諜](#facade-spies) 7 | - [與時間互動](#interacting-with-time) 8 | 9 | 10 | ## 簡介 11 | 12 | 在測試 Laravel 應用程式時,您可能希望「模擬」應用程式的某些方面,以便在給定的測試中不實際執行它們。例如,當測試一個調度事件的控制器時,您可能希望模擬事件監聽器,以便在測試期間實際上不執行它們。這使您可以僅測試控制器的 HTTP 回應,而不必擔心事件監聽器的執行,因為事件監聽器可以在它們自己的測試案例中進行測試。 13 | 14 | Laravel 提供了有用的方法來模擬事件、工作和其他 Facades。這些輔助方法主要提供了一個方便的層,使您不必手動進行複雜的 Mockery 方法調用。 15 | 16 | 17 | ## 模擬物件 18 | 19 | 當模擬一個將通過 Laravel 的[服務容器](/docs/{{version}}/container)注入到您的應用程式中的物件時,您需要將您的模擬實例綁定到容器中作為 `instance` 綁定。這將指示容器使用您的物件的模擬實例,而不是構造物件本身: 20 | 21 | ```php tab=Pest 22 | use App\Service; 23 | use Mockery; 24 | use Mockery\MockInterface; 25 | 26 | test('something can be mocked', function () { 27 | $this->instance( 28 | Service::class, 29 | Mockery::mock(Service::class, function (MockInterface $mock) { 30 | $mock->shouldReceive('process')->once(); 31 | }) 32 | ); 33 | }); 34 | ``` 35 | 36 | ```php tab=PHPUnit 37 | use App\Service; 38 | use Mockery; 39 | use Mockery\MockInterface; 40 | 41 | public function test_something_can_be_mocked(): void 42 | { 43 | $this->instance( 44 | Service::class, 45 | Mockery::mock(Service::class, function (MockInterface $mock) { 46 | $mock->shouldReceive('process')->once(); 47 | }) 48 | ); 49 | } 50 | ``` 51 | 52 | 為了使這更方便,您可以使用 Laravel 基本測試案例類提供的 `mock` 方法。例如,以下示例等同於上面的示例: 53 | 54 | ```php 55 | use App\Service; 56 | use Mockery\MockInterface; 57 | 58 | $mock = $this->mock(Service::class, function (MockInterface $mock) { 59 | $mock->shouldReceive('process')->once(); 60 | }); 61 | ``` 62 | 63 | 當您只需要模擬物件的一些方法時,您可以使用 `partialMock` 方法。未模擬的方法在調用時將正常執行: 64 | 65 | ```php 66 | use App\Service; 67 | use Mockery\MockInterface; 68 | 69 | $mock = $this->partialMock(Service::class, function (MockInterface $mock) { 70 | $mock->shouldReceive('process')->once(); 71 | }); 72 | ``` 73 | 74 | 同樣地,如果您想要[間諜](http://docs.mockery.io/en/latest/reference/spies.html)一個物件,Laravel 的基本測試案例類提供了一個 `spy` 方法,作為 `Mockery::spy` 方法的方便包裝器。間諜與模擬類似;但是,間諜記錄間諜與被測試代碼之間的任何互動,允許您在代碼執行後進行斷言: 75 | 76 | ```php 77 | use App\Service; 78 | 79 | $spy = $this->spy(Service::class); 80 | 81 | // ... 82 | 83 | $spy->shouldHaveReceived('process'); 84 | ``` 85 | 86 | 87 | ## 模擬 Facades 88 | 89 | 與傳統的靜態方法調用不同,[facades](/docs/{{version}}/facades)(包括[即時 facades](/docs/{{version}}/facades#real-time-facades))可以被模擬。這比傳統的靜態方法具有更大的優勢,並為您提供了與使用傳統依賴注入時相同的可測性。在進行測試時,您可能經常需要模擬在您的控制器中發生的 Laravel facade 調用。例如,考慮以下控制器行為: 90 | 91 | ```php 92 | once() 124 | ->with('key') 125 | ->andReturn('value'); 126 | 127 | $response = $this->get('/users'); 128 | 129 | // ... 130 | }); 131 | ``` 132 | 133 | ```php tab=PHPUnit 134 | once() 147 | ->with('key') 148 | ->andReturn('value'); 149 | 150 | $response = $this->get('/users'); 151 | 152 | // ... 153 | } 154 | } 155 | ``` 156 | 157 | > [!WARNING] 158 | > 您不應該模擬 `Request` facade。相反,在運行測試時,應將您想要的輸入傳遞給 [HTTP 測試方法](/docs/{{version}}/http-tests) 如 `get` 和 `post`。同樣,不要模擬 `Config` facade,而應在您的測試中調用 `Config::set` 方法。 159 | 160 | 161 | ### Facade Spies 162 | 163 | 如果您想要 [spy](http://docs.mockery.io/en/latest/reference/spies.html) 一個 facade,您可以在相應的 facade 上調用 `spy` 方法。Spies 類似於 mocks;但是,spies 記錄了 spy 與被測試代碼之間的任何交互,允許您在代碼執行後進行斷言: 164 | 165 | ```php tab=Pest 166 | get('/'); 174 | 175 | $response->assertStatus(200); 176 | 177 | Cache::shouldHaveReceived('put')->once()->with('name', 'Taylor', 10); 178 | }); 179 | ``` 180 | 181 | ```php tab=PHPUnit 182 | use Illuminate\Support\Facades\Cache; 183 | 184 | public function test_values_are_be_stored_in_cache(): void 185 | { 186 | Cache::spy(); 187 | 188 | $response = $this->get('/'); 189 | 190 | $response->assertStatus(200); 191 | 192 | Cache::shouldHaveReceived('put')->once()->with('name', 'Taylor', 10); 193 | } 194 | ``` 195 | 196 | 197 | ## 與時間互動 198 | 199 | 在進行測試時,您可能偶爾需要修改諸如 `now` 或 `Illuminate\Support\Carbon::now()` 等幫助程序返回的時間。幸運的是,Laravel 的基礎功能測試類包含了幫助程序,讓您可以操作當前時間: 200 | 201 | ```php tab=Pest 202 | test('time can be manipulated', function () { 203 | // Travel into the future... 204 | $this->travel(5)->milliseconds(); 205 | $this->travel(5)->seconds(); 206 | $this->travel(5)->minutes(); 207 | $this->travel(5)->hours(); 208 | $this->travel(5)->days(); 209 | $this->travel(5)->weeks(); 210 | $this->travel(5)->years(); 211 | 212 | // Travel into the past... 213 | $this->travel(-5)->hours(); 214 | 215 | // Travel to an explicit time... 216 | $this->travelTo(now()->subHours(6)); 217 | 218 | // Return back to the present time... 219 | $this->travelBack(); 220 | }); 221 | ``` 222 | 223 | ```php tab=PHPUnit 224 | public function test_time_can_be_manipulated(): void 225 | { 226 | // Travel into the future... 227 | $this->travel(5)->milliseconds(); 228 | $this->travel(5)->seconds(); 229 | $this->travel(5)->minutes(); 230 | $this->travel(5)->hours(); 231 | $this->travel(5)->days(); 232 | $this->travel(5)->weeks(); 233 | $this->travel(5)->years(); 234 | 235 | // Travel into the past... 236 | $this->travel(-5)->hours(); 237 | 238 | // Travel to an explicit time... 239 | $this->travelTo(now()->subHours(6)); 240 | 241 | // Return back to the present time... 242 | $this->travelBack(); 243 | } 244 | ``` 245 | 246 | 您也可以為各種時間旅行方法提供一個閉包。閉包將在指定時間凍結時間後被調用。一旦閉包執行完畢,時間將恢復正常: 247 | 248 | ```php 249 | $this->travel(5)->days(function () { 250 | // Test something five days into the future... 251 | }); 252 | 253 | $this->travelTo(now()->subDays(10), function () { 254 | // Test something during a given moment... 255 | }); 256 | ``` 257 | 258 | `freezeTime` 方法可用於凍結當前時間。同樣,`freezeSecond` 方法將凍結當前時間,但在當前秒的開始: 259 | 260 | ```php 261 | use Illuminate\Support\Carbon; 262 | 263 | // Freeze time and resume normal time after executing closure... 264 | $this->freezeTime(function (Carbon $time) { 265 | // ... 266 | }); 267 | 268 | // Freeze time at the current second and resume normal time after executing closure... 269 | $this->freezeSecond(function (Carbon $time) { 270 | // ... 271 | }) 272 | ``` 273 | 274 | 正如您所期望的,上面討論的所有方法主要用於測試與時間敏感應用行為相關的行為,例如在討論區上鎖定非活動帖子: 275 | 276 | ```php tab=Pest 277 | use App\Models\Thread; 278 | 279 | test('forum threads lock after one week of inactivity', function () { 280 | $thread = Thread::factory()->create(); 281 | 282 | $this->travel(1)->week(); 283 | 284 | expect($thread->isLockedByInactivity())->toBeTrue(); 285 | }); 286 | ``` 287 | 288 | ```php tab=PHPUnit 289 | use App\Models\Thread; 290 | 291 | public function test_forum_threads_lock_after_one_week_of_inactivity() 292 | { 293 | $thread = Thread::factory()->create(); 294 | 295 | $this->travel(1)->week(); 296 | 297 | $this->assertTrue($thread->isLockedByInactivity()); 298 | } 299 | ``` 300 | -------------------------------------------------------------------------------- /mongodb.md: -------------------------------------------------------------------------------- 1 | # MongoDB 2 | 3 | - [簡介](#introduction) 4 | - [安裝](#installation) 5 | - [MongoDB 驅動程式](#mongodb-driver) 6 | - [啟動 MongoDB 伺服器](#starting-a-mongodb-server) 7 | - [安裝 Laravel MongoDB 套件](#install-the-laravel-mongodb-package) 8 | - [組態設定](#configuration) 9 | - [功能特色](#features) 10 | 11 | 12 | ## 簡介 13 | 14 | [MongoDB](https://www.mongodb.com/resources/products/fundamentals/why-use-mongodb) 是最受歡迎的 NoSQL 文件導向資料庫之一,用於處理高寫入負載(對於分析或物聯網很有用)和高可用性(易於設定具有自動故障轉移的複製集)。它還可以輕鬆對資料庫進行分片以實現水平擴展,並具有強大的查詢語言,可用於聚合、文本搜索或地理空間查詢。 15 | 16 | 與 SQL 資料庫中的表格或列不同,MongoDB 資料庫中的每條記錄都是以 BSON 描述的文件,這是資料的二進位表示。應用程式可以以 JSON 格式檢索此資訊。它支援各種資料類型,包括文件、陣列、嵌入式文件和二進位資料。 17 | 18 | 在使用 Laravel 與 MongoDB 之前,我們建議通過 Composer 安裝並使用 `mongodb/laravel-mongodb` 套件。`laravel-mongodb` 套件由 MongoDB 官方維護,雖然 PHP 本身通過 MongoDB 驅動程式原生支援 MongoDB,但 [Laravel MongoDB](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/) 套件提供了與 Eloquent 和其他 Laravel 功能更豐富的整合: 19 | 20 | ```shell 21 | composer require mongodb/laravel-mongodb 22 | ``` 23 | 24 | 25 | ## 安裝 26 | 27 | 28 | ### MongoDB 驅動程式 29 | 30 | 要連接到 MongoDB 資料庫,需要 `mongodb` PHP 擴充功能。如果您正在使用 [Laravel Herd](https://herd.laravel.com) 進行本地開發,或者通過 `php.new` 安裝了 PHP,則系統已經安裝了此擴充功能。但是,如果需要手動安裝擴充功能,可以通過 PECL 安裝: 31 | 32 | ```shell 33 | pecl install mongodb 34 | ``` 35 | 36 | 有關安裝 MongoDB PHP 擴充功能的更多資訊,請查看[MongoDB PHP 擴充功能安裝說明](https://www.php.net/manual/en/mongodb.installation.php)。 37 | 38 | 39 | ### 啟動 MongoDB 伺服器 40 | 41 | MongoDB 社區伺服器可用於在本機運行 MongoDB,並可在 Windows、macOS、Linux 或作為 Docker 容器上安裝。要了解如何安裝 MongoDB,請參閱[官方 MongoDB 社區安裝指南](https://docs.mongodb.com/manual/administration/install-community/)。 42 | 43 | 可以在您的 `.env` 檔案中設定 MongoDB 伺服器的連線字串: 44 | 45 | ```ini 46 | MONGODB_URI="mongodb://localhost:27017" 47 | MONGODB_DATABASE="laravel_app" 48 | ``` 49 | 50 | 若要在雲端託管 MongoDB,請考慮使用[MongoDB Atlas](https://www.mongodb.com/cloud/atlas)。 51 | 要從應用程式本地訪問 MongoDB Atlas 叢集,您需要將[自己的 IP 位址添加到叢集的網路設定中](https://www.mongodb.com/docs/atlas/security/add-ip-address-to-list/)以加入專案的 IP 存取清單。 52 | 53 | MongoDB Atlas 的連線字串也可以在您的 `.env` 檔案中設定: 54 | 55 | ```ini 56 | MONGODB_URI="mongodb+srv://:@.mongodb.net/?retryWrites=true&w=majority" 57 | MONGODB_DATABASE="laravel_app" 58 | ``` 59 | 60 | 61 | ### 安裝 Laravel MongoDB 套件 62 | 63 | 最後,使用 Composer 安裝 Laravel MongoDB 套件: 64 | 65 | ```shell 66 | composer require mongodb/laravel-mongodb 67 | ``` 68 | 69 | > [!NOTE] 70 | > 如果未安裝 `mongodb` PHP 擴充功能,則此套件的安裝將失敗。PHP 配置可能在 CLI 和 Web 伺服器之間有所不同,因此請確保在兩個配置中啟用該擴充功能。 71 | 72 | 73 | ## 組態設定 74 | 75 | 您可以透過應用程式的 `config/database.php` 組態檔案來配置 MongoDB 連線。在此檔案中,新增一個使用 `mongodb` 驅動程式的 `mongodb` 連線: 76 | 77 | ```php 78 | 'connections' => [ 79 | 'mongodb' => [ 80 | 'driver' => 'mongodb', 81 | 'dsn' => env('MONGODB_URI', 'mongodb://localhost:27017'), 82 | 'database' => env('MONGODB_DATABASE', 'laravel_app'), 83 | ], 84 | ], 85 | ``` 86 | 87 | 88 | ## 功能 89 | 90 | 一旦您的配置完成,您可以在應用程式中使用 `mongodb` 套件和資料庫連線,以利用各種強大功能: 91 | 92 | - [使用 Eloquent](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/eloquent-models/),模型可以存儲在 MongoDB 集合中。除了標準的 Eloquent 功能外,Laravel MongoDB 套件還提供額外功能,如嵌入式關係。該套件還提供直接訪問 MongoDB 驅動程式的功能,可用於執行原始查詢和聚合管道等操作。 93 | - 使用查詢生成器[撰寫複雜查詢](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/query-builder/)。 94 | - `mongodb` [快取驅動程式](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/cache/)已優化以使用 MongoDB 功能,如 TTL 索引,以自動清除過期的快取條目。 95 | - 使用 `mongodb` 佇列驅動程式[調度和處理佇列作業](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/queues/)。 96 | - [在 GridFS 中存儲檔案](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/filesystems/),透過 [Flysystem 的 GridFS 适配器](https://flysystem.thephpleague.com/docs/adapter/gridfs/)。 97 | - 大多數使用資料庫連線或 Eloquent 的第三方套件都可以與 MongoDB 一起使用。 98 | 99 | 要繼續學習如何使用 MongoDB 和 Laravel,請參考 MongoDB 的[快速入門指南](https://www.mongodb.com/docs/drivers/php/laravel-mongodb/current/quick-start/)。 100 | -------------------------------------------------------------------------------- /passwords.md: -------------------------------------------------------------------------------- 1 | # 重設密碼 2 | 3 | - [簡介](#introduction) 4 | - [模型準備](#model-preparation) 5 | - [資料庫準備](#database-preparation) 6 | - [配置受信任的主機](#configuring-trusted-hosts) 7 | - [路由](#routing) 8 | - [請求重設密碼連結](#requesting-the-password-reset-link) 9 | - [重設密碼](#resetting-the-password) 10 | - [刪除過期的令牌](#deleting-expired-tokens) 11 | - [自訂](#password-customization) 12 | 13 | 14 | ## 簡介 15 | 16 | 大多數網路應用程式提供了一種方式讓使用者重設他們忘記的密碼。 Laravel 提供了方便的服務來發送密碼重設連結和安全地重設密碼,而不是強迫您為每個創建的應用程式手動重新實現此功能。 17 | 18 | > [!NOTE] 19 | > 想要快速開始嗎?在新的 Laravel 應用程式中安裝 Laravel [應用程式起始套件](/docs/{{version}}/starter-kits)。 Laravel 的起始套件將負責搭建整個身份驗證系統,包括重設忘記的密碼。 20 | 21 | 22 | ### 模型準備 23 | 24 | 在使用 Laravel 的密碼重設功能之前,您的應用程式的 `App\Models\User` 模型必須使用 `Illuminate\Notifications\Notifiable` 特性。通常,這個特性已經包含在使用新的 Laravel 應用程式創建的預設 `App\Models\User` 模型中。 25 | 26 | 接下來,請確認您的 `App\Models\User` 模型實作了 `Illuminate\Contracts\Auth\CanResetPassword` 契約。 Laravel 框架附帶的 `App\Models\User` 模型已經實作了這個介面,並使用 `Illuminate\Auth\Passwords\CanResetPassword` 特性來包含實作介面所需的方法。 27 | 28 | 29 | ### 資料庫準備 30 | 31 | 必須建立一個表來存儲您的應用程式的密碼重設令牌。通常,這是包含在 Laravel 的預設 `0001_01_01_000000_create_users_table.php` 資料庫遷移中。 32 | 33 | 34 | ### 配置受信任的主機 35 | 36 | 預設情況下,Laravel 將回應收到的所有請求,不論 HTTP 請求的 `Host` 標頭內容為何。此外,在網頁請求期間生成絕對 URL 到您的應用程式時,`Host` 標頭的值將被使用。 37 | 38 | 通常,您應該配置您的網頁伺服器,如 Nginx 或 Apache,僅將符合特定主機名的請求發送到您的應用程式。但是,如果您無法直接自訂您的網頁伺服器並需要指示 Laravel 僅回應特定主機名,您可以在應用程式的 `bootstrap/app.php` 檔案中使用 `trustHosts` 中介層方法來執行此操作。當您的應用程式提供密碼重設功能時,這一點尤為重要。 39 | 40 | 要了解更多關於這個中介層方法的資訊,請參考[`TrustHosts` 中介層文件](/docs/{{version}}/requests#configuring-trusted-hosts)。 41 | 42 | 43 | ## 路由 44 | 45 | 為了正確實現允許使用者重設密碼的支援,我們需要定義幾個路由。首先,我們需要一對路由來處理允許使用者透過其電子郵件地址請求重設密碼連結。其次,我們需要一對路由來處理當使用者訪問發送到他們的電子郵件的密碼重設連結並完成密碼重設表單時實際重設密碼。 46 | 47 | 48 | ### 請求重設密碼連結 49 | 50 | 51 | #### 重設密碼連結請求表單 52 | 53 | 首先,我們將定義需要請求重設密碼連結的路由。首先,我們將定義一個路由,返回一個帶有密碼重設連結請求表單的視圖: 54 | 55 | ```php 56 | Route::get('/forgot-password', function () { 57 | return view('auth.forgot-password'); 58 | })->middleware('guest')->name('password.request'); 59 | ``` 60 | 61 | 這個路由返回的視圖應該包含一個包含 `email` 欄位的表單,這將允許使用者為特定電子郵件地址請求重設密碼連結。 62 | 63 | #### 處理表單提交 64 | 65 | 接下來,我們將定義一個路由,用於處理來自「忘記密碼」視圖的表單提交請求。這個路由將負責驗證電子郵件地址並將重設密碼請求發送給相應的使用者: 66 | 67 | ```php 68 | use Illuminate\Http\Request; 69 | use Illuminate\Support\Facades\Password; 70 | 71 | Route::post('/forgot-password', function (Request $request) { 72 | $request->validate(['email' => 'required|email']); 73 | 74 | $status = Password::sendResetLink( 75 | $request->only('email') 76 | ); 77 | 78 | return $status === Password::ResetLinkSent 79 | ? back()->with(['status' => __($status)]) 80 | : back()->withErrors(['email' => __($status)]); 81 | })->middleware('guest')->name('password.email'); 82 | ``` 83 | 84 | 在繼續之前,讓我們更詳細地檢查這個路由。首先,將驗證請求的 `email` 屬性。接下來,我們將使用 Laravel 內建的「密碼代理器」(透過 `Password` 門面)向使用者發送重設密碼連結。密碼代理器將負責通過給定的字段(在這種情況下是電子郵件地址)檢索使用者並通過 Laravel 內建的 [通知系統](/docs/{{version}}/notifications) 向使用者發送重設密碼連結。 85 | 86 | `sendResetLink` 方法會返回一個「狀態」標記。這個狀態可以使用 Laravel 的 [本地化](/docs/{{version}}/localization) 助手進行翻譯,以便向使用者顯示有關其請求狀態的友好消息。密碼重設狀態的翻譯由您應用的 `lang/{lang}/passwords.php` 語言文件決定。`passwords` 語言文件中包含了狀態標記的每個可能值的條目。 87 | 88 | > [!NOTE] 89 | > 默認情況下,Laravel 應用程式骨架不包含 `lang` 目錄。如果您想自定義 Laravel 的語言文件,可以通過 `lang:publish` Artisan 命令來發布它們。 90 | 91 | 您可能想知道當調用 `Password` 門面的 `sendResetLink` 方法時,Laravel 如何知道如何從您應用程式的數據庫中檢索使用者記錄。Laravel 密碼代理器利用您的身份驗證系統的「使用者提供者」來檢索數據庫記錄。密碼代理器使用的使用者提供者在您的 `config/auth.php` 配置文件的 `passwords` 配置陣列中配置。要了解有關編寫自定義使用者提供者的更多信息,請參考 [身份驗證文件](/docs/{{version}}/authentication#adding-custom-user-providers)。 92 | 93 | > [!NOTE] 94 | > 當手動實現密碼重置時,您需要自行定義視圖和路由的內容。如果您希望包含所有必要的認證和驗證邏輯的腳手架,請查看[Laravel應用程式起始套件](/docs/{{version}}/starter-kits)。 95 | 96 | 97 | ### 重置密碼 98 | 99 | 100 | #### 重置密碼表單 101 | 102 | 接下來,我們將定義實際重置密碼所需的路由,一旦用戶點擊已通過電子郵件發送的重置密碼鏈接並提供新密碼,就會執行重置。首先,讓我們定義一個路由,該路由將顯示重置密碼表單,當用戶點擊重置密碼鏈接時顯示。此路由將接收一個`token`參數,我們稍後將使用它來驗證密碼重置請求: 103 | 104 | ```php 105 | Route::get('/reset-password/{token}', function (string $token) { 106 | return view('auth.reset-password', ['token' => $token]); 107 | })->middleware('guest')->name('password.reset'); 108 | ``` 109 | 110 | 此路由返回的視圖應該顯示一個包含`email`字段、`password`字段、`password_confirmation`字段和一個隱藏的`token`字段的表單,該字段應包含我們的路由接收到的秘密`$token`的值。 111 | 112 | 113 | #### 處理表單提交 114 | 115 | 當然,我們需要定義一個路由來實際處理密碼重置表單的提交。此路由將負責驗證傳入的請求並在數據庫中更新用戶的密碼: 116 | 117 | ```php 118 | use App\Models\User; 119 | use Illuminate\Auth\Events\PasswordReset; 120 | use Illuminate\Http\Request; 121 | use Illuminate\Support\Facades\Hash; 122 | use Illuminate\Support\Facades\Password; 123 | use Illuminate\Support\Str; 124 | 125 | Route::post('/reset-password', function (Request $request) { 126 | $request->validate([ 127 | 'token' => 'required', 128 | 'email' => 'required|email', 129 | 'password' => 'required|min:8|confirmed', 130 | ]); 131 | 132 | $status = Password::reset( 133 | $request->only('email', 'password', 'password_confirmation', 'token'), 134 | function (User $user, string $password) { 135 | $user->forceFill([ 136 | 'password' => Hash::make($password) 137 | ])->setRememberToken(Str::random(60)); 138 | 139 | $user->save(); 140 | 141 | event(new PasswordReset($user)); 142 | } 143 | ); 144 | 145 | return $status === Password::PasswordReset 146 | ? redirect()->route('login')->with('status', __($status)) 147 | : back()->withErrors(['email' => [__($status)]]); 148 | })->middleware('guest')->name('password.update'); 149 | ``` 150 | 151 | 在繼續之前,讓我們更詳細地檢查這個路由。首先,驗證請求的`token`、`email`和`password`屬性。接下來,我們將使用Laravel內置的"password broker"(通過`Password`Facade)來驗證密碼重置請求的憑證。 152 | 153 | 如果傳給密碼 broker 的 token、電子郵件地址和密碼有效,將調用傳遞給`reset`方法的閉包。在此閉包中,接收用戶實例和提供給密碼重置表單的明文密碼,我們可以在數據庫中更新用戶的密碼。 154 | 155 | `reset` 方法返回一個 "status" slug。這個狀態可以使用 Laravel 的 [本地化](/docs/{{version}}/localization) 助手進行翻譯,以便向用戶顯示有關其請求狀態的友好消息。密碼重置狀態的翻譯取決於您應用程序的 `lang/{lang}/passwords.php` 語言文件。`passwords` 語言文件中包含了狀態 slug 的每個可能值的條目。如果您的應用程序不包含 `lang` 目錄,您可以使用 `lang:publish` Artisan 命令來創建它。 156 | 157 | 在繼續之前,您可能想知道 Laravel 如何在調用 `Password` 門面的 `reset` 方法時從您應用程序的數據庫中檢索用戶記錄。Laravel 密碼代理使用您的身份驗證系統的 "用戶提供者" 來檢索數據庫記錄。密碼代理使用的用戶提供者在您的 `config/auth.php` 配置文件的 `passwords` 配置數組中進行配置。要了解有關編寫自定義用戶提供者的更多信息,請參考 [身份驗證文檔](/docs/{{version}}/authentication#adding-custom-user-providers)。 158 | 159 | 160 | ## 刪除過期令牌 161 | 162 | 已過期的密碼重置令牌仍然存在於您的數據庫中。但是,您可以使用 `auth:clear-resets` Artisan 命令輕鬆刪除這些記錄: 163 | 164 | ```shell 165 | php artisan auth:clear-resets 166 | ``` 167 | 168 | 如果您想自動化此過程,請考慮將該命令添加到您應用程序的 [排程器](/docs/{{version}}/scheduling) 中: 169 | 170 | ```php 171 | use Illuminate\Support\Facades\Schedule; 172 | 173 | Schedule::command('auth:clear-resets')->everyFifteenMinutes(); 174 | ``` 175 | 176 | 177 | ## 自定義 178 | 179 | 180 | #### 重置連結自定義 181 | 182 | 您可以使用 `ResetPassword` 通知類提供的 `createUrlUsing` 方法來自定義密碼重置連結 URL。該方法接受一個閉包,該閉包接收接收通知的用戶實例以及密碼重置連結令牌。通常,您應該從您的 `App\Providers\AppServiceProvider` 服務提供者的 `boot` 方法中調用此方法: 183 | 184 | ```php 185 | use App\Models\User; 186 | use Illuminate\Auth\Notifications\ResetPassword; 187 | 188 | /** 189 | * Bootstrap any application services. 190 | */ 191 | public function boot(): void 192 | { 193 | ResetPassword::createUrlUsing(function (User $user, string $token) { 194 | return 'https://example.com/reset-password?token='.$token; 195 | }); 196 | } 197 | ``` 198 | 199 | 200 | #### 重設郵件自訂 201 | 202 | 您可以輕鬆修改用於向使用者發送密碼重設連結的通知類別。要開始,請覆寫您的 `App\Models\User` 模型上的 `sendPasswordResetNotification` 方法。在此方法中,您可以使用您自己創建的任何 [通知類別](/docs/{{version}}/notifications) 來發送通知。密碼重設 `$token` 是該方法接收的第一個引數。您可以使用此 `$token` 來建立您選擇的密碼重設 URL 並將通知發送給使用者: 203 | 204 | ```php 205 | use App\Notifications\ResetPasswordNotification; 206 | 207 | /** 208 | * Send a password reset notification to the user. 209 | * 210 | * @param string $token 211 | */ 212 | public function sendPasswordResetNotification($token): void 213 | { 214 | $url = 'https://example.com/reset-password?token='.$token; 215 | 216 | $this->notify(new ResetPasswordNotification($url)); 217 | } 218 | ``` 219 | -------------------------------------------------------------------------------- /pint.md: -------------------------------------------------------------------------------- 1 | # Laravel Pint 2 | 3 | - [簡介](#introduction) 4 | - [安裝](#installation) 5 | - [執行 Pint](#running-pint) 6 | - [配置 Pint](#configuring-pint) 7 | - [預設](#presets) 8 | - [規則](#rules) 9 | - [排除檔案/資料夾](#excluding-files-or-folders) 10 | - [持續整合](#continuous-integration) 11 | - [GitHub Actions](#running-tests-on-github-actions) 12 | 13 | 14 | ## 簡介 15 | 16 | [Laravel Pint](https://github.com/laravel/pint) 是一個為極簡主義者設計的 PHP 代碼風格修復工具。Pint 建立在 [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) 之上,讓您輕鬆確保代碼風格保持乾淨一致。 17 | 18 | Pint 會自動安裝在所有新的 Laravel 應用程式中,因此您可以立即開始使用它。預設情況下,Pint 不需要任何配置,將按照 Laravel 的主觀編碼風格修復代碼風格問題。 19 | 20 | 21 | ## 安裝 22 | 23 | Pint 已包含在最新版本的 Laravel 框架中,因此通常不需要安裝。但是,對於舊應用程式,您可以通過 Composer 安裝 Laravel Pint: 24 | 25 | ```shell 26 | composer require laravel/pint --dev 27 | ``` 28 | 29 | 30 | ## 執行 Pint 31 | 32 | 您可以通過調用項目的 `vendor/bin` 目錄中提供的 `pint` 二進制文件,指示 Pint 修復代碼風格問題: 33 | 34 | ```shell 35 | ./vendor/bin/pint 36 | ``` 37 | 38 | 您也可以在特定檔案或目錄上運行 Pint: 39 | 40 | ```shell 41 | ./vendor/bin/pint app/Models 42 | 43 | ./vendor/bin/pint app/Models/User.php 44 | ``` 45 | 46 | Pint 將顯示它更新的所有檔案的詳盡清單。您可以在調用 Pint 時提供 `-v` 選項以查看有關 Pint 更改的更多細節: 47 | 48 | ```shell 49 | ./vendor/bin/pint -v 50 | ``` 51 | 52 | 如果您希望 Pint 僅檢查代碼的風格錯誤而不實際更改檔案,您可以使用 `--test` 選項。如果發現任何代碼風格錯誤,Pint 將返回非零退出碼: 53 | 54 | ```shell 55 | ./vendor/bin/pint --test 56 | ``` 57 | 58 | 如果您希望 Pint 只修改與根據 Git 提供的分支不同的檔案,您可以使用 `--diff=[branch]` 選項。這可以在 CI 環境(如 GitHub actions)中有效使用,以節省時間僅檢查新檔案或修改的檔案: 59 | 60 | ```shell 61 | ./vendor/bin/pint --diff=main 62 | ``` 63 | 64 | 如果您希望 Pint 只修改根據 Git 具有未提交更改的文件,您可以使用 `--dirty` 選項: 65 | 66 | ```shell 67 | ./vendor/bin/pint --dirty 68 | ``` 69 | 70 | 如果您希望 Pint 修復任何具有代碼風格錯誤的文件,但如果修復了任何錯誤則退出並顯示非零退出碼,您可以使用 `--repair` 選項: 71 | 72 | ```shell 73 | ./vendor/bin/pint --repair 74 | ``` 75 | 76 | 77 | ## 配置 Pint 78 | 79 | 如前所述,Pint 不需要任何配置。但是,如果您希望自定義預設值、規則或檢查的文件夾,您可以在項目的根目錄中創建一個 `pint.json` 文件: 80 | 81 | ```json 82 | { 83 | "preset": "laravel" 84 | } 85 | ``` 86 | 87 | 此外,如果您希望從特定目錄使用 `pint.json`,您可以在調用 Pint 時提供 `--config` 選項: 88 | 89 | ```shell 90 | ./vendor/bin/pint --config vendor/my-company/coding-style/pint.json 91 | ``` 92 | 93 | 94 | ### 預設值 95 | 96 | 預設值定義了一組規則,可用於修復代碼風格問題。默認情況下,Pint 使用 `laravel` 預設值,通過遵循 Laravel 的主觀代碼風格來修復問題。但是,您可以通過向 Pint 提供 `--preset` 選項來指定不同的預設值: 97 | 98 | ```shell 99 | ./vendor/bin/pint --preset psr12 100 | ``` 101 | 102 | 如果您希望,您也可以在項目的 `pint.json` 文件中設置預設值: 103 | 104 | ```json 105 | { 106 | "preset": "psr12" 107 | } 108 | ``` 109 | 110 | Pint 目前支持的預設值有:`laravel`、`per`、`psr12`、`symfony` 和 `empty`。 111 | 112 | 113 | ### 規則 114 | 115 | 規則是 Pint 將用於修復代碼風格問題的樣式指南。如上所述,預設值是預定義的規則組,應該適用於大多數 PHP 項目,因此您通常不需要擔心它們包含的個別規則。 116 | 117 | 但是,如果您希望,在您的 `pint.json` 文件中啟用或禁用特定規則,或者使用 `empty` 預設值並從頭定義規則: 118 | 119 | ```json 120 | { 121 | "preset": "laravel", 122 | "rules": { 123 | "simplified_null_return": true, 124 | "array_indentation": false, 125 | "new_with_parentheses": { 126 | "anonymous_class": true, 127 | "named_class": true 128 | } 129 | } 130 | } 131 | ``` 132 | 133 | Pint 建立在 [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) 之上。因此,您可以使用其任何規則來修復項目中的代碼風格問題:[PHP CS Fixer Configurator](https://mlocati.github.io/php-cs-fixer-configurator)。 134 | 135 | ### 排除檔案 / 資料夾 136 | 137 | 預設情況下,Pint 將檢查專案中所有的 `.php` 檔案,但不包括 `vendor` 目錄中的檔案。如果您希望排除更多資料夾,您可以使用 `exclude` 組態選項來進行設定: 138 | 139 | ```json 140 | { 141 | "exclude": [ 142 | "my-specific/folder" 143 | ] 144 | } 145 | ``` 146 | 147 | 如果您希望排除所有包含特定名稱模式的檔案,您可以使用 `notName` 組態選項來進行設定: 148 | 149 | ```json 150 | { 151 | "notName": [ 152 | "*-my-file.php" 153 | ] 154 | } 155 | ``` 156 | 157 | 如果您想要透過提供檔案的精確路徑來排除一個檔案,您可以使用 `notPath` 組態選項來進行設定: 158 | 159 | ```json 160 | { 161 | "notPath": [ 162 | "path/to/excluded-file.php" 163 | ] 164 | } 165 | ``` 166 | 167 | ### 持續整合 168 | 169 | #### 在 GitHub Actions 上運行測試 170 | 171 | 要使用 Laravel Pint 自動化專案的程式碼檢查,您可以配置 [GitHub Actions](https://github.com/features/actions) 來在將新程式碼推送到 GitHub 時運行 Pint。首先,請確保在 GitHub 的 **Settings > Actions > General > Workflow permissions** 中授予「讀取和寫入權限」給工作流程。然後,創建一個名為 `.github/workflows/lint.yml` 的檔案,內容如下: 172 | 173 | ```yaml 174 | name: Fix Code Style 175 | 176 | on: [push] 177 | 178 | jobs: 179 | lint: 180 | runs-on: ubuntu-latest 181 | strategy: 182 | fail-fast: true 183 | matrix: 184 | php: [8.4] 185 | 186 | steps: 187 | - name: Checkout code 188 | uses: actions/checkout@v4 189 | 190 | - name: Setup PHP 191 | uses: shivammathur/setup-php@v2 192 | with: 193 | php-version: ${{ matrix.php }} 194 | extensions: json, dom, curl, libxml, mbstring 195 | coverage: none 196 | 197 | - name: Install Pint 198 | run: composer global require laravel/pint 199 | 200 | - name: Run Pint 201 | run: pint 202 | 203 | - name: Commit linted files 204 | uses: stefanzweifel/git-auto-commit-action@v5 205 | ``` 206 | -------------------------------------------------------------------------------- /providers.md: -------------------------------------------------------------------------------- 1 | # 服務提供者 2 | 3 | - [簡介](#introduction) 4 | - [撰寫服務提供者](#writing-service-providers) 5 | - [註冊方法](#the-register-method) 6 | - [啟動方法](#the-boot-method) 7 | - [註冊提供者](#registering-providers) 8 | - [延遲提供者](#deferred-providers) 9 | 10 | 11 | ## 簡介 12 | 13 | 服務提供者是所有 Laravel 應用程式啟動的中心地帶。您自己的應用程式以及 Laravel 的所有核心服務都是透過服務提供者進行啟動。 14 | 15 | 但是,當我們說 "啟動" 時,我們指的是什麼?一般來說,我們指的是**註冊**事物,包括註冊服務容器綁定、事件監聽器、中介層,甚至路由。服務提供者是配置您的應用程式的中心地帶。 16 | 17 | Laravel 內部使用數十個服務提供者來啟動其核心服務,例如郵件寄送器、佇列、快取等。這些提供者中許多是 "延遲" 提供者,這意味著它們不會在每個請求中載入,而只有在實際需要提供的服務時才會載入。 18 | 19 | 所有用戶定義的服務提供者都在 `bootstrap/providers.php` 檔案中註冊。在接下來的文件中,您將學習如何撰寫自己的服務提供者並將它們註冊到您的 Laravel 應用程式中。 20 | 21 | > [!NOTE] 22 | > 如果您想更深入了解 Laravel 如何處理請求並在內部運作,請查看我們有關 Laravel [請求生命週期](/docs/{{version}}/lifecycle) 的文件。 23 | 24 | 25 | ## 撰寫服務提供者 26 | 27 | 所有服務提供者都擴展自 `Illuminate\Support\ServiceProvider` 類別。大多數服務提供者包含一個 `register` 方法和一個 `boot` 方法。在 `register` 方法中,您應該**僅將事物綁定到 [服務容器](/docs/{{version}}/container)**。您絕不應該在 `register` 方法中嘗試註冊任何事件監聽器、路由或任何其他功能片段。 28 | 29 | Artisan CLI 可以透過 `make:provider` 命令生成新的提供者。Laravel 將自動在您的應用程式的 `bootstrap/providers.php` 檔案中註冊您的新提供者: 30 | 31 | ```shell 32 | php artisan make:provider RiakServiceProvider 33 | ``` 34 | 35 | 36 | ### 註冊方法 37 | 38 | 如前所述,在`register`方法中,您應該只將事物綁定到[服務容器](/docs/{{version}}/container)中。您不應試圖在`register`方法中註冊任何事件監聽器、路由或其他功能。否則,您可能會意外使用由尚未加載的服務提供者提供的服務。 39 | 40 | 讓我們來看一個基本的服務提供者。在您的任何服務提供者方法中,您始終可以訪問`$app`屬性,該屬性提供對服務容器的訪問: 41 | 42 | ```php 43 | app->singleton(Connection::class, function (Application $app) { 59 | return new Connection(config('riak')); 60 | }); 61 | } 62 | } 63 | ``` 64 | 65 | 這個服務提供者僅定義了一個`register`方法,並使用該方法在服務容器中定義了`App\Services\Riak\Connection`的實現。如果您尚不熟悉Laravel的服務容器,請查看[其文檔](/docs/{{version}}/container)。 66 | 67 | 68 | #### `bindings`和`singletons`屬性 69 | 70 | 如果您的服務提供者註冊了許多簡單的綁定,您可能希望使用`bindings`和`singletons`屬性,而不是手動註冊每個容器綁定。當框架加載服務提供者時,它將自動檢查這些屬性並註冊它們的綁定: 71 | 72 | ```php 73 | DigitalOceanServerProvider::class, 93 | ]; 94 | 95 | /** 96 | * All of the container singletons that should be registered. 97 | * 98 | * @var array 99 | */ 100 | public $singletons = [ 101 | DowntimeNotifier::class => PingdomDowntimeNotifier::class, 102 | ServerProvider::class => ServerToolsProvider::class, 103 | ]; 104 | } 105 | ``` 106 | 107 | 108 | ### 啟動方法 109 | 110 | 那麼,如果我們需要在我們的服務提供者中註冊一個[視圖組件](/docs/{{version}}/views#view-composers)呢?這應該在`boot`方法中完成。**此方法在所有其他服務提供者都已註冊後調用**,這意味著您可以訪問框架已註冊的所有其他服務: 111 | 112 | ```php 113 | 135 | #### 啟動方法依賴注入 136 | 137 | 您可以為服務提供者的`boot`方法進行依賴注入。[服務容器](/docs/{{version}}/container)將自動注入您所需的任何依賴項: 138 | 139 | ```php 140 | use Illuminate\Contracts\Routing\ResponseFactory; 141 | 142 | /** 143 | * Bootstrap any application services. 144 | */ 145 | public function boot(ResponseFactory $response): void 146 | { 147 | $response->macro('serialized', function (mixed $value) { 148 | // ... 149 | }); 150 | } 151 | ``` 152 | 153 | 154 | ## 註冊提供者 155 | 156 | 所有服務提供者都在 `bootstrap/providers.php` 組態檔中註冊。這個檔案會回傳一個包含您應用程式服務提供者類別名稱的陣列: 157 | 158 | ```php 159 | 178 | ## 延遲提供者 179 | 180 | 如果您的提供者**僅**在[服務容器](/docs/{{version}}/container)中註冊綁定,您可以選擇延遲其註冊,直到實際需要其中一個註冊的綁定。延遲載入此提供者將改善應用程式的效能,因為它不會在每個請求上從檔案系統載入。 181 | 182 | Laravel 編譯並儲存所有由延遲服務提供者提供的服務清單,以及其服務提供者類別的名稱。然後,只有當您嘗試解析這些服務之一時,Laravel 才會載入服務提供者。 183 | 184 | 要延遲提供者的載入,請實作 `\Illuminate\Contracts\Support\DeferrableProvider` 介面並定義一個 `provides` 方法。`provides` 方法應該回傳提供者註冊的服務容器綁定: 185 | 186 | ```php 187 | app->singleton(Connection::class, function (Application $app) { 204 | return new Connection($app['config']['riak']); 205 | }); 206 | } 207 | 208 | /** 209 | * Get the services provided by the provider. 210 | * 211 | * @return array 212 | */ 213 | public function provides(): array 214 | { 215 | return [Connection::class]; 216 | } 217 | } 218 | ``` 219 | -------------------------------------------------------------------------------- /rate-limiting.md: -------------------------------------------------------------------------------- 1 | # 速率限制 2 | 3 | - [簡介](#introduction) 4 | - [快取組態設定](#cache-configuration) 5 | - [基本用法](#basic-usage) 6 | - [手動增加嘗試次數](#manually-incrementing-attempts) 7 | - [清除嘗試次數](#clearing-attempts) 8 | 9 | 10 | ## 簡介 11 | 12 | Laravel 包含一個簡單易用的速率限制抽象,與應用程式的 [快取](cache) 搭配使用,提供了一種在指定時間窗口內限制任何操作的簡單方法。 13 | 14 | > [!NOTE] 15 | > 如果您對限制傳入的 HTTP 請求感興趣,請參考 [速率限制中介層文件](/docs/{{version}}/routing#rate-limiting)。 16 | 17 | 18 | ### 快取組態設定 19 | 20 | 通常,速率限制器使用您應用程式的預設快取,該快取由應用程式的 `cache` 組態檔案中的 `default` 金鑰定義。但是,您可以通過在應用程式的 `cache` 組態檔案中定義一個 `limiter` 金鑰來指定速率限制器應使用的快取驅動程式: 21 | 22 | ```php 23 | 'default' => env('CACHE_STORE', 'database'), 24 | 25 | 'limiter' => 'redis', 26 | ``` 27 | 28 | 29 | ## 基本用法 30 | 31 | `Illuminate\Support\Facades\RateLimiter` 門面可用於與速率限制器互動。速率限制器提供的最簡單方法是 `attempt` 方法,該方法為給定秒數內的給定回呼進行速率限制。 32 | 33 | 當回呼沒有剩餘嘗試時,`attempt` 方法將返回 `false`;否則,`attempt` 方法將返回回呼的結果或 `true`。`attempt` 方法接受的第一個引數是速率限制器的「金鑰」,可以是您選擇的任何代表正在受到速率限制的操作的字串: 34 | 35 | ```php 36 | use Illuminate\Support\Facades\RateLimiter; 37 | 38 | $executed = RateLimiter::attempt( 39 | 'send-message:'.$user->id, 40 | $perMinute = 5, 41 | function() { 42 | // Send message... 43 | } 44 | ); 45 | 46 | if (! $executed) { 47 | return 'Too many messages sent!'; 48 | } 49 | ``` 50 | 51 | 如果需要,您可以向 `attempt` 方法提供第四個引數,即「衰減率」,或者直到可用嘗試重置之前的秒數。例如,我們可以修改上面的範例,以允許每兩分鐘五次嘗試: 52 | 53 | ```php 54 | $executed = RateLimiter::attempt( 55 | 'send-message:'.$user->id, 56 | $perTwoMinutes = 5, 57 | function() { 58 | // Send message... 59 | }, 60 | $decayRate = 120, 61 | ); 62 | ``` 63 | 64 | 65 | ### 手動增加嘗試次數 66 | 67 | 如果您想要手動與速率限制器互動,可以使用各種其他方法。例如,您可以調用 `tooManyAttempts` 方法來確定特定速率限制器鍵是否已超過每分鐘允許的最大嘗試次數: 68 | 69 | ```php 70 | use Illuminate\Support\Facades\RateLimiter; 71 | 72 | if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) { 73 | return 'Too many attempts!'; 74 | } 75 | 76 | RateLimiter::increment('send-message:'.$user->id); 77 | 78 | // Send message... 79 | ``` 80 | 81 | 或者,您可以使用 `remaining` 方法來獲取特定鍵剩餘的嘗試次數。如果特定鍵還有重試次數,您可以調用 `increment` 方法來增加總嘗試次數: 82 | 83 | ```php 84 | use Illuminate\Support\Facades\RateLimiter; 85 | 86 | if (RateLimiter::remaining('send-message:'.$user->id, $perMinute = 5)) { 87 | RateLimiter::increment('send-message:'.$user->id); 88 | 89 | // Send message... 90 | } 91 | ``` 92 | 93 | 如果您想要將特定速率限制器鍵的值增加超過一個,可以向 `increment` 方法提供所需的數量: 94 | 95 | ```php 96 | RateLimiter::increment('send-message:'.$user->id, amount: 5); 97 | ``` 98 | 99 | ### 確定限制器可用性 100 | 101 | 當一個鍵沒有更多嘗試次數時,`availableIn` 方法將返回直到更多嘗試可用之前剩餘的秒數: 102 | 103 | ```php 104 | use Illuminate\Support\Facades\RateLimiter; 105 | 106 | if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) { 107 | $seconds = RateLimiter::availableIn('send-message:'.$user->id); 108 | 109 | return 'You may try again in '.$seconds.' seconds.'; 110 | } 111 | 112 | RateLimiter::increment('send-message:'.$user->id); 113 | 114 | // Send message... 115 | ``` 116 | 117 | ### 清除嘗試次數 118 | 119 | 您可以使用 `clear` 方法重置特定速率限制器鍵的嘗試次數。例如,當接收者讀取特定消息時,您可以重置嘗試次數: 120 | 121 | ```php 122 | use App\Models\Message; 123 | use Illuminate\Support\Facades\RateLimiter; 124 | 125 | /** 126 | * Mark the message as read. 127 | */ 128 | public function read(Message $message): Message 129 | { 130 | $message->markAsRead(); 131 | 132 | RateLimiter::clear('send-message:'.$message->user_id); 133 | 134 | return $message; 135 | } 136 | ``` 137 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Laravel 文件 2 | 3 | 您可以在 [https://laravel.com/docs](https://laravel.com/docs) 找到 Laravel 文件的線上版本。 4 | 5 | ## 貢獻指南 6 | 7 | 如果您正在提交**當前穩定版本**的文件,請將其提交到相應的分支。例如,針對 Laravel 12 的文件應提交到 `12.x` 分支。針對下一個 Laravel 發行版的文件應提交到 `master` 分支。 8 | -------------------------------------------------------------------------------- /redirects.md: -------------------------------------------------------------------------------- 1 | # HTTP 重新導向 2 | 3 | - [建立重新導向](#creating-redirects) 4 | - [重新導向至命名路由](#redirecting-named-routes) 5 | - [重新導向至控制器行為](#redirecting-controller-actions) 6 | - [使用快閃會話數據重新導向](#redirecting-with-flashed-session-data) 7 | 8 | 9 | ## 建立重新導向 10 | 11 | 重新導向響應是 `Illuminate\Http\RedirectResponse` 類的實例,包含將用戶重新導向到另一個 URL 所需的正確標頭。有幾種方法可以生成 `RedirectResponse` 實例。最簡單的方法是使用全局 `redirect` 輔助函式: 12 | 13 | ```php 14 | Route::get('/dashboard', function () { 15 | return redirect('/home/dashboard'); 16 | }); 17 | ``` 18 | 19 | 有時您可能希望將用戶重新導向到其先前位置,例如當提交的表單無效時。您可以使用全局 `back` 輔助函式來實現。由於此功能使用了 [session](/docs/{{version}}/session),請確保調用 `back` 函式的路由使用 `web` 中介層組,或應用了所有會話中介軟體: 20 | 21 | ```php 22 | Route::post('/user/profile', function () { 23 | // Validate the request... 24 | 25 | return back()->withInput(); 26 | }); 27 | ``` 28 | 29 | 30 | ## 重新導向至命名路由 31 | 32 | 當您調用 `redirect` 輔助函式時不帶參數,將返回 `Illuminate\Routing\Redirector` 的實例,允許您在 `Redirector` 實例上調用任何方法。例如,要生成到命名路由的 `RedirectResponse`,您可以使用 `route` 方法: 33 | 34 | ```php 35 | return redirect()->route('login'); 36 | ``` 37 | 38 | 如果您的路由有參數,您可以將它們作為第二個參數傳遞給 `route` 方法: 39 | 40 | ```php 41 | // 對於具有以下 URI 的路由:profile/{id} 42 | 43 | return redirect()->route('profile', ['id' => 1]); 44 | ``` 45 | 46 | 為了方便起見,Laravel 還提供了全局 `to_route` 函式: 47 | 48 | ```php 49 | return to_route('profile', ['id' => 1]); 50 | ``` 51 | 52 | 53 | #### 通過 Eloquent 模型填充參數 54 | 55 | 如果您正在重新導向到一個帶有從 Eloquent 模型填充的 "ID" 參數的路由,您可以傳遞模型本身。ID 將被自動提取: 56 | 57 | ```php 58 | // 對於具有以下 URI 的路由:profile/{id} 59 | 60 | return redirect()->route('profile', [$user]); 61 | ``` 62 | 63 | 如果您想要自定義放置在路由參數中的值,您應該在您的 Eloquent 模型上覆蓋 `getRouteKey` 方法: 64 | 65 | ```php 66 | /** 67 | * Get the value of the model's route key. 68 | */ 69 | public function getRouteKey(): mixed 70 | { 71 | return $this->slug; 72 | } 73 | ``` 74 | 75 | 76 | ## 導向至控制器行為 77 | 78 | 您也可以生成導向至[控制器行為](/docs/{{version}}/controllers)的重定向。為此,將控制器和行為名稱傳遞給 `action` 方法: 79 | 80 | ```php 81 | use App\Http\Controllers\HomeController; 82 | 83 | return redirect()->action([HomeController::class, 'index']); 84 | ``` 85 | 86 | 如果您的控制器路由需要參數,您可以將它們作為第二個參數傳遞給 `action` 方法: 87 | 88 | ```php 89 | return redirect()->action( 90 | [UserController::class, 'profile'], ['id' => 1] 91 | ); 92 | ``` 93 | 94 | 95 | ## 導向並傳遞快閃會話數據 96 | 97 | 通常在重定向到新 URL 並[將數據快閃到會話](/docs/{{version}}/session#flash-data)時同時進行。通常在成功執行操作後進行此操作,當您將成功消息快閃到會話時。為方便起見,您可以在單個流暢方法鏈中創建一個 `RedirectResponse` 實例並將數據快閃到會話: 98 | 99 | ```php 100 | Route::post('/user/profile', function () { 101 | // Update the user's profile... 102 | 103 | return redirect('/dashboard')->with('status', 'Profile updated!'); 104 | }); 105 | ``` 106 | 107 | 您可以使用 `RedirectResponse` 實例提供的 `withInput` 方法將當前請求的輸入數據快閃到會話,然後將用戶重定向到新位置。一旦輸入數據已經快閃到會話中,您可以在下一個請求期間輕鬆[檢索它](/docs/{{version}}/requests#retrieving-old-input): 108 | 109 | ```php 110 | return back()->withInput(); 111 | ``` 112 | 113 | 用戶被重定向後,您可以從[會話](/docs/{{version}}/session)中顯示快閃消息。例如,使用[Blade 語法](/docs/{{version}}/blade): 114 | 115 | ```blade 116 | @if (session('status')) 117 |
118 | {{ session('status') }} 119 |
120 | @endif 121 | ``` 122 | -------------------------------------------------------------------------------- /releases.md: -------------------------------------------------------------------------------- 1 | # 發行說明 2 | 3 | - [版本控制方案](#versioning-scheme) 4 | - [支援政策](#support-policy) 5 | - [Laravel 12](#laravel-12) 6 | 7 | 8 | ## 版本控制方案 9 | 10 | Laravel 及其其他第一方套件遵循[語義化版本](https://semver.org)。主要框架版本每年發布一次(約在第一季度),而次要和修補版本可能每週發布一次。次要和修補版本**絕對不應該**包含破壞性變更。 11 | 12 | 當從您的應用程式或套件中引用 Laravel 框架或其組件時,您應該始終使用版本約束,例如 `^11.0`,因為 Laravel 的主要版本確實包含破壞性變更。但是,我們始終努力確保您可以在一天或更短的時間內更新到新的主要版本。 13 | 14 | 15 | #### 命名引數 16 | 17 | [命名引數](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments)不在 Laravel 的向後兼容性指南中。在必要時,我們可能選擇重新命名函數引數,以改進 Laravel 代碼庫。因此,在調用 Laravel 方法時使用命名引數應該謹慎進行,並且應該了解參數名稱可能會在將來更改。 18 | 19 | 20 | ## 支援政策 21 | 22 | 對於所有 Laravel 發行版,提供 18 個月的錯誤修復和 2 年的安全修復。對於所有其他附加函式庫,包括 Lumen,僅最新的主要版本接收錯誤修復。此外,請查看 Laravel 支援的[資料庫版本](/docs/{{version}}/database#introduction)。 23 | 24 |
25 | 26 | | 版本 | PHP (*) | 發布日期 | 錯誤修復截止日期 | 安全修復截止日期 | 27 | | --- | --- | --- | --- | --- | 28 | | 9 | 8.0 - 8.2 | 2022年2月8日 | 2023年8月8日 | 2024年2月6日 | 29 | | 10 | 8.1 - 8.3 | 2023年2月14日 | 2024年8月6日 | 2025年2月4日 | 30 | | 11 | 8.2 - 8.4 | 2024年3月12日 | 2025年9月3日 | 2026年3月12日 | 31 | | 12 | 8.2 - 8.4 | 2025年2月24日 | 2026年8月13日 | 2027年2月24日 | 32 | 33 |
34 | 35 |
36 |
37 |
38 |
終止支援
39 |
40 |
41 |
42 |
僅安全性修復
43 |
44 |
45 | 46 | (*) 支援的 PHP 版本 47 | 48 | 49 | ## Laravel 12 50 | 51 | Laravel 12 在 Laravel 11.x 中所做的改進基礎上,更新上游依賴項目並引入新的 React、Vue 和 Livewire 入門套件,包括使用 [WorkOS AuthKit](https://authkit.com) 進行用戶認證的選項。我們的入門套件的 WorkOS 變體提供社交認證、通行證和單點登錄支持。 52 | 53 | 54 | ### 最小破壞性變更 55 | 56 | 在此版本週期中,我們的許多重點是減少破壞性變更。相反,我們致力於在整年內推出持續的生活品質改進,而不會破壞現有應用程式。 57 | 58 | 因此,Laravel 12 版本是一個相對較小的「維護版本」,以升級現有的依賴項目。基於此,大多數 Laravel 應用程式可能升級到 Laravel 12 而無需更改任何應用程式代碼。 59 | 60 | 61 | ### 新應用程式入門套件 62 | 63 | Laravel 12 推出了新的 [應用程式入門套件](/docs/{{version}}/starter-kits) 供 React、Vue 和 Livewire 使用。React 和 Vue 入門套件利用 Inertia 2、TypeScript、[shadcn/ui](https://ui.shadcn.com) 和 Tailwind,而 Livewire 入門套件則利用基於 Tailwind 的 [Flux UI](https://fluxui.dev) 元件庫和 Laravel Volt。 64 | 65 | React、Vue 和 Livewire 入門套件都利用 Laravel 內建的認證系統提供登入、註冊、密碼重設、電子郵件驗證等功能。此外,我們還推出了每個入門套件的 [WorkOS AuthKit 驅動](https://authkit.com) 變體,提供社交認證、通行證和單點登錄支持。WorkOS 為每月活躍用戶量達到 100 萬的應用程式提供免費認證。 66 | 67 | 隨著我們新應用程式起始套件 Laravel Breeze 和 Laravel Jetstream 的推出,將不再接收額外更新。 68 | 69 | 要開始使用我們的新起始套件,請查看 [起始套件文件](/docs/{{version}}/starter-kits)。 70 | -------------------------------------------------------------------------------- /reverb.md: -------------------------------------------------------------------------------- 1 | # Laravel Reverb 2 | 3 | - [簡介](#introduction) 4 | - [安裝](#installation) 5 | - [組態設定](#configuration) 6 | - [應用程式憑證](#application-credentials) 7 | - [允許的來源](#allowed-origins) 8 | - [其他應用程式](#additional-applications) 9 | - [SSL](#ssl) 10 | - [執行伺服器](#running-server) 11 | - [除錯](#debugging) 12 | - [重新啟動](#restarting) 13 | - [監控](#monitoring) 14 | - [在正式環境中執行 Reverb](#production) 15 | - [開啟檔案](#open-files) 16 | - [事件迴圈](#event-loop) 17 | - [網頁伺服器](#web-server) 18 | - [埠號](#ports) 19 | - [處理程序管理](#process-management) 20 | - [擴展](#scaling) 21 | 22 | 23 | ## 簡介 24 | 25 | [Laravel Reverb](https://github.com/laravel/reverb) 將極快速且可擴展的即時 WebSocket 通訊直接帶入您的 Laravel 應用程式,並與 Laravel 現有的一系列 [事件廣播工具](/docs/{{version}}/broadcasting) 無縫整合。 26 | 27 | 28 | ## 安裝 29 | 30 | 您可以使用 `install:broadcasting` Artisan 指令安裝 Reverb: 31 | 32 | ```shell 33 | php artisan install:broadcasting 34 | ``` 35 | 36 | 37 | ## 組態設定 38 | 39 | 在幕後,`install:broadcasting` Artisan 指令將執行 `reverb:install` 指令,該指令將使用一組明智的預設組態選項安裝 Reverb。如果您想要進行任何組態更改,您可以通過更新 Reverb 的環境變數或更新 `config/reverb.php` 組態檔案來進行。 40 | 41 | 42 | ### 應用程式憑證 43 | 44 | 為了建立與 Reverb 的連線,必須在客戶端和伺服器之間交換一組 Reverb「應用程式」憑證。這些憑證在伺服器上進行配置,並用於驗證來自客戶端的請求。您可以使用以下環境變數定義這些憑證: 45 | 46 | ```ini 47 | REVERB_APP_ID=my-app-id 48 | REVERB_APP_KEY=my-app-key 49 | REVERB_APP_SECRET=my-app-secret 50 | ``` 51 | 52 | 53 | ### 允許的來源 54 | 55 | 您可以通過更新 `config/reverb.php` 配置文件中 `apps` 部分內的 `allowed_origins` 配置值來定義客戶端請求可能來源的來源。任何來自未列在您允許來源中的來源的請求將被拒絕。您可以使用 `*` 允許所有來源: 56 | 57 | ```php 58 | 'apps' => [ 59 | [ 60 | 'app_id' => 'my-app-id', 61 | 'allowed_origins' => ['laravel.com'], 62 | // ... 63 | ] 64 | ] 65 | ``` 66 | 67 | 68 | ### 附加應用程式 69 | 70 | 通常,Reverb 為安裝它的應用程式提供 WebSocket 伺服器。但是,可以使用單個 Reverb 安裝來提供多個應用程式。 71 | 72 | 例如,您可能希望維護一個單個的 Laravel 應用程式,通過 Reverb 為多個應用程式提供 WebSocket 連接。這可以通過在應用程式的 `config/reverb.php` 配置文件中定義多個 `apps` 來實現: 73 | 74 | ```php 75 | 'apps' => [ 76 | [ 77 | 'app_id' => 'my-app-one', 78 | // ... 79 | ], 80 | [ 81 | 'app_id' => 'my-app-two', 82 | // ... 83 | ], 84 | ], 85 | ``` 86 | 87 | 88 | ### SSL 89 | 90 | 在大多數情況下,安全的 WebSocket 連接是由上游網頁伺服器(如 Nginx 等)處理,然後將請求代理到您的 Reverb 伺服器。 91 | 92 | 但是,有時候這樣做可能很有用,例如在本地開發期間,讓 Reverb 伺服器直接處理安全連接。如果您正在使用 [Laravel Herd](https://herd.laravel.com) 的安全站點功能,或者您正在使用 [Laravel Valet](/docs/{{version}}/valet) 並且已對您的應用程式運行了 [secure 命令](/docs/{{version}}/valet#securing-sites),您可以使用 Herd / Valet 為您的站點生成的憑證來保護您的 Reverb 連接。為此,將 `REVERB_HOST` 環境變數設置為您站點的主機名,或在啟動 Reverb 伺服器時明確傳遞主機名選項: 93 | 94 | ```shell 95 | php artisan reverb:start --host="0.0.0.0" --port=8080 --hostname="laravel.test" 96 | ``` 97 | 98 | 由於 Herd 和 Valet 域名解析為 `localhost`,運行上面的命令將使您的 Reverb 伺服器可以通過安全的 WebSocket 協議 (`wss`) 在 `wss://laravel.test:8080` 上訪問。 99 | 100 | 您還可以通過在應用程式的 `config/reverb.php` 配置文件中定義 `tls` 選項來手動選擇憑證。在 `tls` 選項數組中,您可以提供 [PHP SSL 上下文選項](https://www.php.net/manual/en/context.ssl.php) 支持的任何選項。 101 | 102 | ```php 103 | 'options' => [ 104 | 'tls' => [ 105 | 'local_cert' => '/path/to/cert.pem' 106 | ], 107 | ], 108 | ``` 109 | 110 | 111 | ## 啟動伺服器 112 | 113 | 可以使用 `reverb:start` Artisan 指令來啟動 Reverb 伺服器: 114 | 115 | ```shell 116 | php artisan reverb:start 117 | ``` 118 | 119 | 預設情況下,Reverb 伺服器將在 `0.0.0.0:8080` 啟動,使其可以從所有網路介面訪問。 120 | 121 | 如果需要指定自訂主機或埠,可以在啟動伺服器時通過 `--host` 和 `--port` 選項進行設定: 122 | 123 | ```shell 124 | php artisan reverb:start --host=127.0.0.1 --port=9000 125 | ``` 126 | 127 | 或者,您可以在應用程式的 `.env` 組態檔中定義 `REVERB_SERVER_HOST` 和 `REVERB_SERVER_PORT` 環境變數。 128 | 129 | `REVERB_SERVER_HOST` 和 `REVERB_SERVER_PORT` 環境變數不應與 `REVERB_HOST` 和 `REVERB_PORT` 混淆。前者指定運行 Reverb 伺服器本身的主機和埠,而後者則指示 Laravel 將廣播訊息發送到何處。例如,在正式環境中,您可能會將從公共 Reverb 主機名稱的埠 `443` 路由到運行在 `0.0.0.0:8080` 上的 Reverb 伺服器。在這種情況下,您的環境變數應定義如下: 130 | 131 | ```ini 132 | REVERB_SERVER_HOST=0.0.0.0 133 | REVERB_SERVER_PORT=8080 134 | 135 | REVERB_HOST=ws.laravel.com 136 | REVERB_PORT=443 137 | ``` 138 | 139 | 140 | ### 調試 141 | 142 | 為了提高效能,Reverb 預設不會輸出任何調試資訊。如果您想查看通過 Reverb 伺服器的數據流,可以在 `reverb:start` 指令中提供 `--debug` 選項: 143 | 144 | ```shell 145 | php artisan reverb:start --debug 146 | ``` 147 | 148 | 149 | ### 重新啟動 150 | 151 | 由於 Reverb 是一個長期運行的進程,更改代碼後需要通過 `reverb:restart` Artisan 指令重新啟動伺服器才能反映這些更改。 152 | 153 | `reverb:restart` 指令確保在停止伺服器之前優雅地終止所有連接。如果您使用進程管理器(如 Supervisor)運行 Reverb,則在終止所有連接後,進程管理器將自動重新啟動伺服器: 154 | 155 | ```shell 156 | php artisan reverb:restart 157 | ``` 158 | 159 | ## 監控 160 | 161 | 透過與 [Laravel Pulse](/docs/{{version}}/pulse) 整合,可以監控 Reverb。啟用 Reverb 的 Pulse 整合後,您可以追蹤伺服器處理的連線數和訊息數。 162 | 163 | 要啟用整合,您應先確保已安裝 [Pulse](/docs/{{version}}/pulse#installation)。然後,將 Reverb 的任何記錄器新增到應用程式的 `config/pulse.php` 組態檔中: 164 | 165 | ```php 166 | use Laravel\Reverb\Pulse\Recorders\ReverbConnections; 167 | use Laravel\Reverb\Pulse\Recorders\ReverbMessages; 168 | 169 | 'recorders' => [ 170 | ReverbConnections::class => [ 171 | 'sample_rate' => 1, 172 | ], 173 | 174 | ReverbMessages::class => [ 175 | 'sample_rate' => 1, 176 | ], 177 | 178 | // ... 179 | ], 180 | ``` 181 | 182 | 接著,將每個記錄器的 Pulse 卡片新增到您的 [Pulse 儀表板](/docs/{{version}}/pulse#dashboard-customization): 183 | 184 | ```blade 185 | 186 | 187 | 188 | ... 189 | 190 | ``` 191 | 192 | 連線活動是透過定期輪詢新更新來記錄的。為確保此資訊在 Pulse 儀表板上正確呈現,您必須在 Reverb 伺服器上執行 `pulse:check` Daemon。如果您正在以 [水平擴展](#scaling) 的方式運行 Reverb,則應僅在其中一台伺服器上執行此 Daemon。 193 | 194 | ## 在正式環境中執行 Reverb 195 | 196 | 由於 WebSocket 伺服器的長時間運行特性,您可能需要對伺服器和主機環境進行一些優化,以確保您的 Reverb 伺服器能有效處理伺服器上可用資源的最佳連線數。 197 | 198 | > [!NOTE] 199 | > 如果您的網站由 [Laravel Forge](https://forge.laravel.com) 管理,您可以直接從「應用程式」面板為 Reverb 自動優化您的伺服器。啟用 Reverb 整合後,Forge 將確保您的伺服器已準備好投入生產,包括安裝任何必要的擴充功能並增加允許的連線數。 200 | 201 | ### 開啟檔案 202 | 203 | 每個 WebSocket 連線會一直保留在記憶體中,直到客戶端或伺服器中斷連線。在 Unix 和類 Unix 環境中,每個連線都以檔案表示。但是,在作業系統和應用程式層面通常會對允許的開啟檔案數量設定限制。 204 | 205 | #### 作業系統 206 | 207 | 在基於 Unix 的作業系統上,您可以使用 `ulimit` 命令來確定允許的開啟文件數量: 208 | 209 | ```shell 210 | ulimit -n 211 | ``` 212 | 213 | 此命令將顯示不同使用者允許的開啟文件限制。您可以通過編輯 `/etc/security/limits.conf` 檔案來更新這些值。例如,將 `forge` 使用者的最大開啟文件數量更新為 10,000,將如下所示: 214 | 215 | ```ini 216 | # /etc/security/limits.conf 217 | forge soft nofile 10000 218 | forge hard nofile 10000 219 | ``` 220 | 221 | 222 | ### 事件迴圈 223 | 224 | 在底層,Reverb 使用 ReactPHP 事件迴圈來管理伺服器上的 WebSocket 連線。預設情況下,此事件迴圈由 `stream_select` 驅動,不需要任何額外的擴充功能。然而,`stream_select` 通常限制為 1,024 個開啟文件。因此,如果您計劃處理超過 1,000 個並行連線,您將需要使用一個不受相同限制約束的替代事件迴圈。 225 | 226 | 當可用時,Reverb 將自動切換到由 `ext-uv` 驅動的迴圈。此 PHP 擴充功能可通過 PECL 進行安裝: 227 | 228 | ```shell 229 | pecl install uv 230 | ``` 231 | 232 | 233 | ### 網頁伺服器 234 | 235 | 在大多數情況下,Reverb 在伺服器上運行在非面向網頁的埠。因此,為了將流量路由到 Reverb,您應該配置一個反向代理。假設 Reverb 在主機 `0.0.0.0` 和埠 `8080` 上運行,並且您的伺服器使用 Nginx 網頁伺服器,可以使用以下 Nginx 網站配置為您的 Reverb 伺服器定義一個反向代理: 236 | 237 | ```nginx 238 | server { 239 | ... 240 | 241 | location / { 242 | proxy_http_version 1.1; 243 | proxy_set_header Host $http_host; 244 | proxy_set_header Scheme $scheme; 245 | proxy_set_header SERVER_PORT $server_port; 246 | proxy_set_header REMOTE_ADDR $remote_addr; 247 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 248 | proxy_set_header Upgrade $http_upgrade; 249 | proxy_set_header Connection "Upgrade"; 250 | 251 | proxy_pass http://0.0.0.0:8080; 252 | } 253 | 254 | ... 255 | } 256 | ``` 257 | 258 | > [!WARNING] 259 | > Reverb 在 `/app` 處聆聽 WebSocket 連線,並在 `/apps` 處處理 API 請求。您應確保處理 Reverb 請求的網頁伺服器可以提供這兩個 URI。如果您正在使用 [Laravel Forge](https://forge.laravel.com) 來管理您的伺服器,則您的 Reverb 伺服器將被正確地預設配置。 260 | 261 | 通常,為了防止伺服器過載,網頁伺服器通常會配置限制允許的連線數量。要將 Nginx 網頁伺服器上允許的連線數量增加到 10,000,應更新 `nginx.conf` 檔案中的 `worker_rlimit_nofile` 和 `worker_connections` 值: 262 | 263 | ```nginx 264 | user forge; 265 | worker_processes auto; 266 | pid /run/nginx.pid; 267 | include /etc/nginx/modules-enabled/*.conf; 268 | worker_rlimit_nofile 10000; 269 | 270 | events { 271 | worker_connections 10000; 272 | multi_accept on; 273 | } 274 | ``` 275 | 276 | 上述配置將允許每個進程最多生成 10,000 個 Nginx 工作進程。此外,此配置將 Nginx 的開啟文件限制設置為 10,000。 277 | 278 | 279 | ### 連接埠 280 | 281 | 基於 Unix 的作業系統通常限制伺服器上可以開啟的連接埠數量。您可以通過以下命令查看當前允許的範圍: 282 | 283 | ```shell 284 | cat /proc/sys/net/ipv4/ip_local_port_range 285 | # 32768 60999 286 | ``` 287 | 288 | 上面的輸出顯示伺服器最多可以處理 28,231 個連線(60,999 - 32,768),因為每個連線都需要一個空閒連接埠。儘管我們建議[水平擴展](#scaling)以增加允許的連線數量,您可以通過更新伺服器的 `/etc/sysctl.conf` 配置文件中允許的連接埠範圍來增加可用的開放連接埠數量。 289 | 290 | 291 | ### 進程管理 292 | 293 | 在大多數情況下,您應該使用進程管理器(如 Supervisor)來確保 Reverb 伺服器持續運行。如果您正在使用 Supervisor 來運行 Reverb,您應該更新伺服器的 `supervisor.conf` 文件中的 `minfds` 設置,以確保 Supervisor 能夠打開處理到您的 Reverb 伺服器的連線所需的文件: 294 | 295 | ```ini 296 | [supervisord] 297 | ... 298 | minfds=10000 299 | ``` 300 | 301 | 302 | ### 擴展 303 | 304 | 如果您需要處理比單個伺服器允許的更多連線,您可以將 Reverb 伺服器水平擴展。利用 Redis 的發布/訂閱功能,Reverb 能夠跨多個伺服器管理連線。當您應用程式的一個 Reverb 伺服器接收到消息時,該伺服器將使用 Redis 將傳入的消息發佈到所有其他伺服器。 305 | 306 | 要啟用水平擴展,您應該在應用程式的 `.env` 配置文件中將 `REVERB_SCALING_ENABLED` 環境變數設置為 `true`: 307 | 308 | ```env 309 | REVERB_SCALING_ENABLED=true 310 | ``` 311 | 312 | 接下來,您應該擁有一個專用的中央 Redis 伺服器,所有 Reverb 伺服器將與其通信。Reverb 將使用您應用程式配置的[默認 Redis 連線](/docs/{{version}}/redis#configuration)來向所有 Reverb 伺服器發佈消息。 313 | 314 | 一旦您啟用了 Reverb 的擴展選項並配置了 Redis 伺服器,您只需在能夠與您的 Redis 伺服器通信的多個伺服器上調用 `reverb:start` 命令。這些 Reverb 伺服器應該放置在一個負載均衡器後面,該負載均衡器將傳入的請求均勻分配給這些伺服器。 315 | 316 | --- 317 | 318 | **permalink:** https://example.com 319 | -------------------------------------------------------------------------------- /seeding.md: -------------------------------------------------------------------------------- 1 | # 資料庫: 資料填充 2 | 3 | - [簡介](#introduction) 4 | - [撰寫填充器](#writing-seeders) 5 | - [使用模型工廠](#using-model-factories) 6 | - [呼叫其他填充器](#calling-additional-seeders) 7 | - [靜音模型事件](#muting-model-events) 8 | - [執行填充器](#running-seeders) 9 | 10 | 11 | ## 簡介 12 | 13 | Laravel 包含了使用填充類別向資料庫填充資料的功能。所有的填充類別都存儲在 `database/seeders` 目錄中。預設情況下,為您定義了一個 `DatabaseSeeder` 類別。您可以從這個類別中使用 `call` 方法運行其他填充類別,從而控制填充的順序。 14 | 15 | > [!NOTE] 16 | > 在資料庫填充期間,[大量賦值保護](/docs/{{version}}/eloquent#mass-assignment)會自動禁用。 17 | 18 | 19 | ## 撰寫填充器 20 | 21 | 要生成一個填充器,請執行 `make:seeder` [Artisan 指令](/docs/{{version}}/artisan)。框架生成的所有填充器都將放置在 `database/seeders` 目錄中: 22 | 23 | ```shell 24 | php artisan make:seeder UserSeeder 25 | ``` 26 | 27 | 填充器類別預設僅包含一個方法:`run`。當執行 `db:seed` [Artisan 指令](/docs/{{version}}/artisan) 時,將調用此方法。在 `run` 方法中,您可以按照自己的需求將資料插入資料庫。您可以使用 [查詢建構器](/docs/{{version}}/queries) 手動插入資料,或者使用 [Eloquent 模型工廠](/docs/{{version}}/eloquent-factories)。 28 | 29 | 例如,讓我們修改預設的 `DatabaseSeeder` 類別,並在 `run` 方法中添加一個資料庫插入語句: 30 | 31 | ```php 32 | insert([ 49 | 'name' => Str::random(10), 50 | 'email' => Str::random(10).'@example.com', 51 | 'password' => Hash::make('password'), 52 | ]); 53 | } 54 | } 55 | ``` 56 | 57 | > [!NOTE] 58 | > 您可以在 `run` 方法的簽名中型別提示您需要的任何依賴項。它們將通過 Laravel 的[服務容器](/docs/{{version}}/container)自動解析。 59 | 60 | 61 | ### 使用模型工廠 62 | 63 | 當然,為每個模型填充手動指定屬性是繁瑣的。相反,您可以使用[模型工廠](/docs/{{version}}/eloquent-factories)來方便地生成大量的資料庫記錄。首先,請查看[模型工廠文件](/docs/{{version}}/eloquent-factories)以了解如何定義您的工廠。 64 | 65 | ### 呼叫額外的資料填充器 66 | 67 | 在 `DatabaseSeeder` 類別中,您可以使用 `call` 方法來執行額外的資料填充器類別。使用 `call` 方法可以將資料填充工作拆分為多個檔案,以避免單個資料填充器類別過於龐大。`call` 方法接受一個應該被執行的資料填充器類別陣列: 68 | 69 | ```php 70 | /** 71 | * Run the database seeders. 72 | */ 73 | public function run(): void 74 | { 75 | $this->call([ 76 | UserSeeder::class, 77 | PostSeeder::class, 78 | CommentSeeder::class, 79 | ]); 80 | } 81 | ``` 82 | 83 | ### 關閉模型事件 84 | 85 | 在執行資料填充時,您可能希望防止模型發送事件。您可以使用 `WithoutModelEvents` 特性來實現這一點。當使用時,`WithoutModelEvents` 特性確保不會發送任何模型事件,即使透過 `call` 方法執行其他資料填充器類別: 86 | 87 | ```php 88 | call([ 105 | UserSeeder::class, 106 | ]); 107 | } 108 | } 109 | ``` 110 | 111 | ## 執行資料填充器 112 | 113 | 您可以執行 `db:seed` Artisan 指令來填充您的資料庫。預設情況下,`db:seed` 指令會執行 `Database\Seeders\DatabaseSeeder` 類別,該類別可能會調用其他資料填充器類別。但是,您可以使用 `--class` 選項來指定要單獨運行的特定資料填充器類別: 114 | 115 | ```shell 116 | php artisan db:seed 117 | 118 | php artisan db:seed --class=UserSeeder 119 | ``` 120 | 121 | 您也可以使用 `migrate:fresh` 指令結合 `--seed` 選項來填充您的資料庫,這將刪除所有資料表並重新執行所有遷移。這個指令對於完全重建您的資料庫非常有用。`--seeder` 選項可用於指定要運行的特定資料填充器: 122 | 123 | ```shell 124 | php artisan migrate:fresh --seed 125 | 126 | php artisan migrate:fresh --seed --seeder=UserSeeder 127 | ``` 128 | 129 | #### 強制在正式環境中執行資料填充器 130 | 131 | 某些資料填充操作可能導致您修改或遺失資料。為了防止您對正式資料庫運行資料填充指令,當在 `production` 環境中執行資料填充器時,您將被要求確認。要強制執行資料填充器而不提示,請使用 `--force` 標誌: 132 | 133 | ```shell 134 | php artisan db:seed --force 135 | ``` 136 | -------------------------------------------------------------------------------- /socialite.md: -------------------------------------------------------------------------------- 1 | # Laravel Socialite 2 | 3 | - [簡介](#introduction) 4 | - [安裝](#installation) 5 | - [升級 Socialite](#upgrading-socialite) 6 | - [組態設定](#configuration) 7 | - [認證](#authentication) 8 | - [路由](#routing) 9 | - [認證與儲存](#authentication-and-storage) 10 | - [存取範圍](#access-scopes) 11 | - [Slack 機器人範圍](#slack-bot-scopes) 12 | - [選用參數](#optional-parameters) 13 | - [取得使用者詳細資訊](#retrieving-user-details) 14 | 15 | 16 | ## 簡介 17 | 18 | 除了典型的基於表單的認證外,Laravel 還提供了一種簡單、方便的方法,使用 [Laravel Socialite](https://github.com/laravel/socialite) 與 OAuth 提供者進行認證。Socialite 目前支援透過 Facebook、X、LinkedIn、Google、GitHub、GitLab、Bitbucket 和 Slack 進行認證。 19 | 20 | > [!NOTE] 21 | > 其他平台的配接器可透過社群驅動的 [Socialite Providers](https://socialiteproviders.com/) 網站取得。 22 | 23 | 24 | ## 安裝 25 | 26 | 要開始使用 Socialite,請使用 Composer 套件管理器將套件新增為專案的相依性: 27 | 28 | ```shell 29 | composer require laravel/socialite 30 | ``` 31 | 32 | 33 | ## 升級 Socialite 34 | 35 | 當升級到 Socialite 的新主要版本時,重要的是仔細查看 [升級指南](https://github.com/laravel/socialite/blob/master/UPGRADE.md)。 36 | 37 | 38 | ## 組態設定 39 | 40 | 在使用 Socialite 之前,您需要為應用程式使用的 OAuth 提供者添加憑證。通常,這些憑證可以通過在您將要進行認證的服務的儀表板中創建一個「開發人員應用程式」來檢索。 41 | 42 | 這些憑證應該放在您的應用程式的 `config/services.php` 組態檔案中,並應使用 `facebook`、`x`、`linkedin-openid`、`google`、`github`、`gitlab`、`bitbucket`、`slack` 或 `slack-openid` 作為鍵,具體取決於您的應用程式所需的提供者: 43 | 44 | ```php 45 | 'github' => [ 46 | 'client_id' => env('GITHUB_CLIENT_ID'), 47 | 'client_secret' => env('GITHUB_CLIENT_SECRET'), 48 | 'redirect' => 'http://example.com/callback-url', 49 | ], 50 | ``` 51 | 52 | > [!NOTE] 53 | > 如果 `redirect` 選項包含相對路徑,它將自動解析為完全合格的 URL。 54 | 55 | 56 | ## 認證 57 | 58 | 59 | ### 路由 60 | 61 | 要使用 OAuth 提供者對用戶進行身份驗證,您將需要兩個路由:一個用於將用戶重定向到 OAuth 提供者,另一個用於在身份驗證後從提供者接收回調。下面的示例路由演示了這兩個路由的實現: 62 | 63 | ```php 64 | use Laravel\Socialite\Facades\Socialite; 65 | 66 | Route::get('/auth/redirect', function () { 67 | return Socialite::driver('github')->redirect(); 68 | }); 69 | 70 | Route::get('/auth/callback', function () { 71 | $user = Socialite::driver('github')->user(); 72 | 73 | // $user->token 74 | }); 75 | ``` 76 | 77 | `Socialite` 門面提供的 `redirect` 方法負責將用戶重定向到 OAuth 提供者,而 `user` 方法將檢查傳入的請求並從提供者檢索用戶的信息,用戶在批准身份驗證請求後。 78 | 79 | 80 | ### 認證和存儲 81 | 82 | 從 OAuth 提供者檢索用戶後,您可以確定用戶是否存在於應用程序的數據庫中並[對用戶進行身份驗證](/docs/{{version}}/authentication#authenticate-a-user-instance)。如果用戶不存在於應用程序的數據庫中,通常會在數據庫中創建一條新記錄來代表該用戶: 83 | 84 | ```php 85 | use App\Models\User; 86 | use Illuminate\Support\Facades\Auth; 87 | use Laravel\Socialite\Facades\Socialite; 88 | 89 | Route::get('/auth/callback', function () { 90 | $githubUser = Socialite::driver('github')->user(); 91 | 92 | $user = User::updateOrCreate([ 93 | 'github_id' => $githubUser->id, 94 | ], [ 95 | 'name' => $githubUser->name, 96 | 'email' => $githubUser->email, 97 | 'github_token' => $githubUser->token, 98 | 'github_refresh_token' => $githubUser->refreshToken, 99 | ]); 100 | 101 | Auth::login($user); 102 | 103 | return redirect('/dashboard'); 104 | }); 105 | ``` 106 | 107 | > [!NOTE] 108 | > 有關從特定 OAuth 提供者檢索用戶信息的更多信息,請參考[檢索用戶詳細信息](#retrieving-user-details)上的文檔。 109 | 110 | 111 | ### 存取範圍 112 | 113 | 在重定向用戶之前,您可以使用 `scopes` 方法來指定應包含在身份驗證請求中的“範圍”。此方法將合併所有先前指定的範圍與您指定的範圍: 114 | 115 | ```php 116 | use Laravel\Socialite\Facades\Socialite; 117 | 118 | return Socialite::driver('github') 119 | ->scopes(['read:user', 'public_repo']) 120 | ->redirect(); 121 | ``` 122 | 123 | 您可以使用 `setScopes` 方法覆蓋身份驗證請求上的所有現有範圍: 124 | 125 | ```php 126 | return Socialite::driver('github') 127 | ->setScopes(['read:user', 'public_repo']) 128 | ->redirect(); 129 | ``` 130 | 131 | 132 | ### Slack 機器人範圍 133 | 134 | Slack的API提供[不同類型的存取權杖](https://api.slack.com/authentication/token-types),每種都有其自己的[權限範圍](https://api.slack.com/scopes)。Socialite與以下兩種Slack存取權杖類型兼容: 135 | 136 |
137 | 138 | - 機器人(以 `xoxb-` 為前綴) 139 | - 使用者(以 `xoxp-` 為前綴) 140 | 141 |
142 | 143 | 預設情況下,`slack` 驅動程式將生成一個 `user` 權杖,並調用驅動程式的 `user` 方法將返回使用者的詳細資訊。 144 | 145 | 如果您的應用程式將向由您的應用程式使用者擁有的外部Slack工作區發送通知,則機器人權杖將非常有用。要生成機器人權杖,請在將使用者重定向到Slack進行身分驗證之前調用 `asBotUser` 方法: 146 | 147 | ```php 148 | return Socialite::driver('slack') 149 | ->asBotUser() 150 | ->setScopes(['chat:write', 'chat:write.public', 'chat:write.customize']) 151 | ->redirect(); 152 | ``` 153 | 154 | 此外,在Slack將使用者重定向回您的應用程式進行身分驗證後,您必須在調用 `user` 方法之前調用 `asBotUser` 方法: 155 | 156 | ```php 157 | $user = Socialite::driver('slack')->asBotUser()->user(); 158 | ``` 159 | 160 | 生成機器人權杖時,`user` 方法仍將返回一個 `Laravel\Socialite\Two\User` 實例;但是,只會填充 `token` 屬性。可以將此權杖存儲起來,以便[向已驗證使用者的Slack工作區發送通知](/docs/{{version}}/notifications#notifying-external-slack-workspaces)。 161 | 162 | 163 | ### 可選參數 164 | 165 | 許多OAuth提供者支持在重定向請求中使用其他可選參數。要在請求中包含任何可選參數,請使用具有關聯陣列的 `with` 方法: 166 | 167 | ```php 168 | use Laravel\Socialite\Facades\Socialite; 169 | 170 | return Socialite::driver('google') 171 | ->with(['hd' => 'example.com']) 172 | ->redirect(); 173 | ``` 174 | 175 | > [!WARNING] 176 | > 使用 `with` 方法時,請務必小心,不要傳遞任何保留關鍵字,如 `state` 或 `response_type`。 177 | 178 | 179 | ## 檢索使用者詳細資訊 180 | 181 | 在使用者重定向回您的應用程式的身分驗證回呼路由後,您可以使用Socialite的 `user` 方法檢索使用者的詳細資訊。`user` 方法返回的使用者物件提供了各種屬性和方法,可用於將有關使用者的資訊存儲在您自己的資料庫中。 182 | 183 | 不同的屬性和方法可能會根據您正在進行身份驗證的 OAuth 提供者是否支援 OAuth 1.0 或 OAuth 2.0 而有所不同: 184 | 185 | ```php 186 | use Laravel\Socialite\Facades\Socialite; 187 | 188 | Route::get('/auth/callback', function () { 189 | $user = Socialite::driver('github')->user(); 190 | 191 | // OAuth 2.0 providers... 192 | $token = $user->token; 193 | $refreshToken = $user->refreshToken; 194 | $expiresIn = $user->expiresIn; 195 | 196 | // OAuth 1.0 providers... 197 | $token = $user->token; 198 | $tokenSecret = $user->tokenSecret; 199 | 200 | // All providers... 201 | $user->getId(); 202 | $user->getNickname(); 203 | $user->getName(); 204 | $user->getEmail(); 205 | $user->getAvatar(); 206 | }); 207 | ``` 208 | 209 | 210 | #### 從令牌檢索使用者詳細資訊 211 | 212 | 如果您已經有一個有效的使用者存取令牌,您可以使用 Socialite 的 `userFromToken` 方法來檢索他們的使用者詳細資訊: 213 | 214 | ```php 215 | use Laravel\Socialite\Facades\Socialite; 216 | 217 | $user = Socialite::driver('github')->userFromToken($token); 218 | ``` 219 | 220 | 如果您正在使用 iOS 應用程式通過 Facebook 有限登入,Facebook 將返回一個 OIDC 令牌而不是存取令牌。就像存取令牌一樣,OIDC 令牌可以提供給 `userFromToken` 方法以檢索使用者詳細資訊。 221 | 222 | 223 | #### 無狀態身份驗證 224 | 225 | `stateless` 方法可用於停用會話狀態驗證。當將社交身份驗證添加到不使用基於 Cookie 的會話的無狀態 API 時,這很有用: 226 | 227 | ```php 228 | use Laravel\Socialite\Facades\Socialite; 229 | 230 | return Socialite::driver('google')->stateless()->user(); 231 | ``` 232 | -------------------------------------------------------------------------------- /structure.md: -------------------------------------------------------------------------------- 1 | # 目錄結構 2 | 3 | - [簡介](#introduction) 4 | - [根目錄](#the-root-directory) 5 | - [`app` 目錄](#the-root-app-directory) 6 | - [`bootstrap` 目錄](#the-bootstrap-directory) 7 | - [`config` 目錄](#the-config-directory) 8 | - [`database` 目錄](#the-database-directory) 9 | - [`public` 目錄](#the-public-directory) 10 | - [`resources` 目錄](#the-resources-directory) 11 | - [`routes` 目錄](#the-routes-directory) 12 | - [`storage` 目錄](#the-storage-directory) 13 | - [`tests` 目錄](#the-tests-directory) 14 | - [`vendor` 目錄](#the-vendor-directory) 15 | - [應用程式目錄](#the-app-directory) 16 | - [`Broadcasting` 目錄](#the-broadcasting-directory) 17 | - [`Console` 目錄](#the-console-directory) 18 | - [`Events` 目錄](#the-events-directory) 19 | - [`Exceptions` 目錄](#the-exceptions-directory) 20 | - [`Http` 目錄](#the-http-directory) 21 | - [`Jobs` 目錄](#the-jobs-directory) 22 | - [`Listeners` 目錄](#the-listeners-directory) 23 | - [`Mail` 目錄](#the-mail-directory) 24 | - [`Models` 目錄](#the-models-directory) 25 | - [`Notifications` 目錄](#the-notifications-directory) 26 | - [`Policies` 目錄](#the-policies-directory) 27 | - [`Providers` 目錄](#the-providers-directory) 28 | - [`Rules` 目錄](#the-rules-directory) 29 | 30 | 31 | ## 簡介 32 | 33 | Laravel 的預設應用程式結構旨在為大型和小型應用程式提供一個很好的起點。但您可以自由地按照自己的喜好組織應用程式。只要 Composer 能夠自動載入類別,Laravel 幾乎不會對類別的位置施加任何限制。 34 | 35 | 36 | ## 根目錄 37 | 38 | 39 | ### app 目錄 40 | 41 | `app` 目錄包含您的應用程式的核心程式碼。我們很快將更詳細地探索這個目錄;然而,您的應用程式中幾乎所有的類別都會在這個目錄中。 42 | 43 | ### Bootstrap 目錄 44 | 45 | `bootstrap` 目錄包含 `app.php` 檔案,該檔案用於啟動框架。此目錄還包含一個 `cache` 目錄,其中包含框架生成的檔案,用於性能優化,例如路由和服務快取檔案。 46 | 47 | ### 組態目錄 48 | 49 | `config` 目錄,如其名稱所示,包含所有應用程式的組態檔案。建議閱讀所有這些檔案,熟悉所有可用的選項。 50 | 51 | ### 資料庫目錄 52 | 53 | `database` 目錄包含資料庫遷移、模型工廠和填充。如果需要,您也可以使用此目錄來保存 SQLite 資料庫。 54 | 55 | ### 公開目錄 56 | 57 | `public` 目錄包含 `index.php` 檔案,該檔案是進入應用程式的所有請求的入口點,並配置自動載入。此目錄還包含您的資源檔,如圖片、JavaScript 和 CSS。 58 | 59 | ### 資源目錄 60 | 61 | `resources` 目錄包含您的[視圖](/docs/{{version}}/views),以及原始、未編譯的資源檔,如 CSS 或 JavaScript。 62 | 63 | ### 路由目錄 64 | 65 | `routes` 目錄包含應用程式的所有路由定義。預設情況下,Laravel 包含兩個路由檔案:`web.php` 和 `console.php`。 66 | 67 | `web.php` 檔案包含 Laravel 放置在 `web` 中介層群組中的路由,該中介層提供會話狀態、CSRF 保護和 Cookie 加密。如果您的應用程式不提供無狀態的 RESTful API,則所有路由很可能會在 `web.php` 檔案中定義。 68 | 69 | `console.php` 檔案是您可以在其中定義所有基於閉包的控制台命令。每個閉包都綁定到一個命令實例,使與每個命令的 IO 方法互動變得簡單。即使此檔案不定義 HTTP 路由,它定義了基於控制台的應用程式入口點 (路由)。您也可以在 `console.php` 檔案中[安排](/docs/{{version}}/scheduling)任務。 70 | 71 | 選擇性地,您可以通過 `install:api` 和 `install:broadcasting` Artisan 命令為 API 路由(`api.php`)和廣播頻道(`channels.php`)安裝額外的路由文件。 72 | 73 | `api.php` 文件包含預期為無狀態的路由,因此通過這些路由進入應用程序的請求預期將通過 [令牌進行身份驗證](/docs/{{version}}/sanctum),並且將無法訪問會話狀態。 74 | 75 | `channels.php` 文件是您可以在其中註冊應用程序支持的所有 [事件廣播](/docs/{{version}}/broadcasting) 頻道的地方。 76 | 77 | 78 | ### 儲存目錄 79 | 80 | `storage` 目錄包含您的日誌、編譯的 Blade 模板、基於文件的會話、文件快取以及框架生成的其他文件。此目錄分為 `app`、`framework` 和 `logs` 目錄。`app` 目錄可用於存儲應用程序生成的任何文件。`framework` 目錄用於存儲框架生成的文件和快取。最後,`logs` 目錄包含應用程序的日誌文件。 81 | 82 | `storage/app/public` 目錄可用於存儲用戶生成的文件,例如個人資料頭像,這些文件應該是公開訪問的。您應該在 `public/storage` 創建一個符號連結,指向此目錄。您可以使用 `php artisan storage:link` Artisan 命令來創建連結。 83 | 84 | 85 | ### 測試目錄 86 | 87 | `tests` 目錄包含您的自動化測試。示例 [Pest](https://pestphp.com) 或 [PHPUnit](https://phpunit.de/) 單元測試和功能測試已經預設提供。每個測試類應該以 `Test` 一詞作為後綴。您可以使用 `/vendor/bin/pest` 或 `/vendor/bin/phpunit` 命令運行您的測試。或者,如果您想要更詳細和美觀的測試結果呈現,您可以使用 `php artisan test` Artisan 命令運行您的測試。 88 | 89 | 90 | ### 供應商目錄 91 | 92 | `vendor` 目錄包含您的 [Composer](https://getcomposer.org) 依賴項。 93 | 94 | ## 應用程式目錄 95 | 96 | 大部分的應用程式位於 `app` 目錄中。預設情況下,此目錄在 `App` 命名空間下,並且由 Composer 使用 [PSR-4 自動載入標準](https://www.php-fig.org/psr/psr-4/) 進行自動載入。 97 | 98 | 預設情況下,`app` 目錄包含 `Http`、`Models` 和 `Providers` 目錄。然而,隨著您使用 make Artisan 命令生成類別,`app` 目錄內將生成各種其他目錄。例如,直到您執行 `make:command` Artisan 命令生成命令類別之前,`app/Console` 目錄將不存在。 99 | 100 | `Console` 和 `Http` 目錄將在下面各自的部分進一步解釋,但請將 `Console` 和 `Http` 目錄視為提供應用程式核心的 API。HTTP 協議和 CLI 都是與應用程式互動的機制,但實際上不包含應用程式邏輯。換句話說,它們是向應用程式發出命令的兩種方式。`Console` 目錄包含所有 Artisan 命令,而 `Http` 目錄包含您的控制器、中介層和請求。 101 | 102 | > [!NOTE] 103 | > `app` 目錄中的許多類別可以通過 Artisan 命令生成。要查看可用的命令,請在終端機中運行 `php artisan list make` 命令。 104 | 105 | ### 廣播目錄 106 | 107 | `Broadcasting` 目錄包含應用程式的所有廣播頻道類別。這些類別是使用 `make:channel` 命令生成的。此目錄不會預設存在,但在您創建第一個頻道時將為您創建。要了解更多關於頻道的資訊,請查看 [事件廣播](/docs/{{version}}/broadcasting) 的文件。 108 | 109 | ### 控制台目錄 110 | 111 | `Console` 目錄包含應用程式的所有自定義 Artisan 命令。這些命令可以使用 `make:command` 命令生成。 112 | 113 | ### 事件目錄 114 | 115 | 這個目錄不會在預設情況下存在,但將會由 `event:generate` 和 `make:event` Artisan 命令為您創建。`Events` 目錄包含 [事件類別](/docs/{{version}}/events)。事件可用於通知應用程式的其他部分發生了某個動作,提供了很大的靈活性和解耦性。 116 | 117 | ### 例外目錄 118 | 119 | `Exceptions` 目錄包含應用程式的所有自訂例外。這些例外可以使用 `make:exception` 命令生成。 120 | 121 | ### HTTP 目錄 122 | 123 | `Http` 目錄包含您的控制器、中介層和表單請求。幾乎所有處理進入應用程式的請求的邏輯都將放在這個目錄中。 124 | 125 | ### 工作目錄 126 | 127 | 這個目錄不會在預設情況下存在,但如果您執行 `make:job` Artisan 命令,將為您創建。`Jobs` 目錄包含應用程式的 [可排隊工作](/docs/{{version}}/queues)。工作可以由應用程式排隊或在當前請求生命週期內同步運行。在當前請求期間同步運行的工作有時被稱為 "命令",因為它們是 [命令模式](https://en.wikipedia.org/wiki/Command_pattern) 的實現。 128 | 129 | ### 監聽器目錄 130 | 131 | 這個目錄不會在預設情況下存在,但如果您執行 `event:generate` 或 `make:listener` Artisan 命令,將為您創建。`Listeners` 目錄包含處理您的 [事件](/docs/{{version}}/events) 的類別。事件監聽器接收一個事件實例並根據事件被觸發時的邏輯執行操作。例如,`UserRegistered` 事件可能由 `SendWelcomeEmail` 監聽器處理。 132 | 133 | ### 郵件目錄 134 | 135 | 這個目錄不會在預設情況下存在,但如果您執行 `make:mail` Artisan 命令,將為您創建。`Mail` 目錄包含您的應用程式發送的所有 [代表郵件的類別](/docs/{{version}}/mail)。郵件物件允許您將構建郵件的所有邏輯封裝在一個簡單的類別中,並可以使用 `Mail::send` 方法發送。 136 | 137 | ### 模型目錄 138 | 139 | `Models` 目錄包含所有您的 [Eloquent 模型類別](/docs/{{version}}/eloquent)。Laravel 隨附的 Eloquent ORM 提供了一個美觀、簡單的 ActiveRecord 實作,用於與您的資料庫進行操作。每個資料庫表格都有對應的 "模型",用於與該表格進行互動。模型允許您查詢表格中的資料,並將新記錄插入表格中。 140 | 141 | ### 通知目錄 142 | 143 | 此目錄默認情況下不存在,但如果您執行 `make:notification` Artisan 指令,將為您創建。`Notifications` 目錄包含所有由應用程式發送的 "交易性" [通知](/docs/{{version}}/notifications),例如有關應用程式內發生事件的簡單通知。Laravel 的通知功能對於通過各種驅動程式發送通知(如電子郵件、Slack、簡訊或存儲在資料庫中)進行了抽象化。 144 | 145 | ### 授權目錄 146 | 147 | 此目錄默認情況下不存在,但如果您執行 `make:policy` Artisan 指令,將為您創建。`Policies` 目錄包含應用程式的 [授權原則類別](/docs/{{version}}/authorization)。原則用於確定使用者是否可以針對資源執行特定操作。 148 | 149 | ### 提供者目錄 150 | 151 | `Providers` 目錄包含應用程式的所有 [服務提供者](/docs/{{version}}/providers)。服務提供者通過在服務容器中綁定服務、註冊事件或執行其他任務來啟動您的應用程式,為接收的請求準備應用程式。 152 | 153 | 在一個新的 Laravel 應用程式中,此目錄已經包含 `AppServiceProvider`。您可以根據需要自由向此目錄添加自己的提供者。 154 | 155 | ### 規則目錄 156 | 157 | 這個目錄不會自動存在,但如果您執行 `make:rule` Artisan 指令,系統會為您建立它。`Rules` 目錄包含應用程式的自訂驗證規則物件。規則用於將複雜的驗證邏輯封裝在一個簡單的物件中。欲了解更多資訊,請查看 [驗證文件](/docs/{{version}}/validation)。 158 | -------------------------------------------------------------------------------- /testing.md: -------------------------------------------------------------------------------- 1 | # 測試:入門指南 2 | 3 | - [簡介](#introduction) 4 | - [環境](#environment) 5 | - [建立測試](#creating-tests) 6 | - [執行測試](#running-tests) 7 | - [平行執行測試](#running-tests-in-parallel) 8 | - [報告測試覆蓋率](#reporting-test-coverage) 9 | - [分析測試](#profiling-tests) 10 | 11 | 12 | ## 簡介 13 | 14 | Laravel 是以測試為基礎建立的。事實上,支援使用 [Pest](https://pestphp.com) 和 [PHPUnit](https://phpunit.de) 進行測試是內建的,並且已經為您的應用程式設定好了 `phpunit.xml` 檔案。框架還提供了方便的輔助方法,讓您可以表達性地測試您的應用程式。 15 | 16 | 預設情況下,您的應用程式的 `tests` 目錄包含兩個目錄:`Feature` 和 `Unit`。單元測試是專注於代碼的非常小、獨立的部分的測試。事實上,大多數單元測試可能專注於單個方法。位於您的 "Unit" 測試目錄中的測試不會啟動 Laravel 應用程式,因此無法訪問您的應用程式數據庫或其他框架服務。 17 | 18 | 功能測試可能測試您代碼的較大部分,包括幾個對象如何互動,甚至是對 JSON 端點的完整 HTTP 請求。**一般來說,大多數測試應該是功能測試。這些類型的測試提供了最大的信心,確保您的系統作為整體按照預期運作。** 19 | 20 | 在 `Feature` 和 `Unit` 測試目錄中都提供了一個 `ExampleTest.php` 檔案。在安裝新的 Laravel 應用程式後,執行 `vendor/bin/pest`、`vendor/bin/phpunit` 或 `php artisan test` 命令來執行您的測試。 21 | 22 | 23 | ## 環境 24 | 25 | 在執行測試時,Laravel 會自動將 [組態環境](/docs/{{version}}/configuration#environment-configuration) 設置為 `testing`,這是由 `phpunit.xml` 檔案中定義的環境變數所決定的。Laravel 還會自動將會話和快取配置為 `array` 驅動程式,因此在測試期間不會持久保留任何會話或快取數據。 26 | 27 | 您可以自由定義其他測試環境配置值,如有必要。`testing` 環境變數可以在應用程式的 `phpunit.xml` 檔案中進行配置,但在執行測試之前,請確保使用 `config:clear` Artisan 命令清除您的配置快取! 28 | 29 | 30 | #### `.env.testing` 環境檔案 31 | 32 | 此外,您可以在專案根目錄中建立一個 `.env.testing` 檔案。當執行 Pest 和 PHPUnit 測試或使用 `--env=testing` 選項執行 Artisan 命令時,將使用此檔案而非 `.env` 檔案。 33 | 34 | 35 | ## 建立測試 36 | 37 | 要建立新的測試案例,請使用 `make:test` Artisan 命令。預設情況下,測試將放置在 `tests/Feature` 目錄中: 38 | 39 | ```shell 40 | php artisan make:test UserTest 41 | ``` 42 | 43 | 如果您想在 `tests/Unit` 目錄中創建測試,可以在執行 `make:test` 命令時使用 `--unit` 選項: 44 | 45 | ```shell 46 | php artisan make:test UserTest --unit 47 | ``` 48 | 49 | > [!NOTE] 50 | > 可以使用 [stub publishing](/docs/{{version}}/artisan#stub-customization) 自訂測試樣板。 51 | 52 | 測試生成後,您可以像平常一樣使用 Pest 或 PHPUnit 定義測試。要運行測試,請在終端機中執行 `vendor/bin/pest`、`vendor/bin/phpunit` 或 `php artisan test` 命令: 53 | 54 | ```php tab=Pest 55 | toBeTrue(); 59 | }); 60 | ``` 61 | 62 | ```php tab=PHPUnit 63 | assertTrue(true); 77 | } 78 | } 79 | ``` 80 | 81 | > [!WARNING] 82 | > 如果在測試類別中定義了自己的 `setUp` / `tearDown` 方法,請確保在父類別上調用相應的 `parent::setUp()` / `parent::tearDown()` 方法。通常情況下,您應該在自己的 `setUp` 方法開始時調用 `parent::setUp()`,並在 `tearDown` 方法結束時調用 `parent::tearDown()`。 83 | 84 | 85 | ## 執行測試 86 | 87 | 如前所述,一旦您撰寫了測試,您可以使用 `pest` 或 `phpunit` 來運行它們: 88 | 89 | ```shell tab=Pest 90 | ./vendor/bin/pest 91 | ``` 92 | 93 | ```shell tab=PHPUnit 94 | ./vendor/bin/phpunit 95 | ``` 96 | 97 | 除了 `pest` 或 `phpunit` 命令外,您還可以使用 `test` Artisan 命令來運行測試。Artisan 測試運行器提供詳細的測試報告,以便於開發和調試: 98 | 99 | ```shell 100 | php artisan test 101 | ``` 102 | 103 | 可以將傳遞給 `pest` 或 `phpunit` 指令的任何引數也傳遞給 Artisan 的 `test` 指令: 104 | 105 | ```shell 106 | php artisan test --testsuite=Feature --stop-on-failure 107 | ``` 108 | 109 | 110 | ### 並行執行測試 111 | 112 | 預設情況下,Laravel 和 Pest / PHPUnit 會在單一進程中依序執行您的測試。但是,您可以通過在多個進程之間同時執行測試來大大減少運行測試所需的時間。要開始,您應該將 `brianium/paratest` Composer 套件安裝為 "dev" 依賴項。然後,在執行 `test` Artisan 指令時包含 `--parallel` 選項: 113 | 114 | ```shell 115 | composer require brianium/paratest --dev 116 | 117 | php artisan test --parallel 118 | ``` 119 | 120 | 預設情況下,Laravel 將在您的機器上可用的 CPU 核心數量創建同樣多的進程。但是,您可以使用 `--processes` 選項來調整進程數量: 121 | 122 | ```shell 123 | php artisan test --parallel --processes=4 124 | ``` 125 | 126 | > [!WARNING] 127 | > 在並行執行測試時,某些 Pest / PHPUnit 選項(例如 `--do-not-cache-result`)可能無法使用。 128 | 129 | 130 | #### 並行測試和資料庫 131 | 132 | 只要您已配置了主要資料庫連線,Laravel 將自動處理為每個並行進程創建和遷移一個測試資料庫。測試資料庫將以進程標記為後綴,每個進程都有唯一的標記。例如,如果您有兩個並行測試進程,Laravel 將創建並使用 `your_db_test_1` 和 `your_db_test_2` 測試資料庫。 133 | 134 | 預設情況下,測試資料庫在對 `test` Artisan 指令的調用之間保留,以便它們可以再次被後續的 `test` 調用使用。但是,您可以使用 `--recreate-databases` 選項重新創建它們: 135 | 136 | ```shell 137 | php artisan test --parallel --recreate-databases 138 | ``` 139 | 140 | 141 | #### 並行測試鉤子 142 | 143 | 有時,您可能需要準備應用程式測試使用的某些資源,以便它們可以安全地被多個測試進程使用。 144 | 145 | 使用 `ParallelTesting` 配接器,您可以指定在進程或測試案例的 `setUp` 和 `tearDown` 上要執行的程式碼。給定的閉包接收包含進程標記和當前測試案例的 `$token` 和 `$testCase` 變數: 146 | 147 | ```php 148 | 189 | #### 存取平行測試標記 190 | 191 | 如果您想要從應用程式測試代碼的任何其他位置存取當前平行進程的 "標記",您可以使用 `token` 方法。此標記是一個獨特的字串識別符,用於個別測試進程,可用於在平行測試進程之間分割資源。例如,Laravel 自動將此標記附加到每個平行測試進程創建的測試資料庫的末尾: 192 | 193 | $token = ParallelTesting::token(); 194 | 195 | 196 | ### 報告測試覆蓋率 197 | 198 | > [!WARNING] 199 | > 此功能需要 [Xdebug](https://xdebug.org) 或 [PCOV](https://pecl.php.net/package/pcov)。 200 | 201 | 執行應用程式測試時,您可能希望確定您的測試案例是否實際涵蓋了應用程式代碼,以及在執行測試時使用了多少應用程式代碼。為了達到這個目的,您可以在調用 `test` 命令時提供 `--coverage` 選項: 202 | 203 | ```shell 204 | php artisan test --coverage 205 | ``` 206 | 207 | 208 | #### 強制最低覆蓋率閾值 209 | 210 | 您可以使用 `--min` 選項為您的應用程式定義最低測試覆蓋率閾值。如果未達到此閾值,測試套件將失敗: 211 | 212 | ```shell 213 | php artisan test --coverage --min=80.3 214 | ``` 215 | 216 | 217 | ### 測試分析 218 | 219 | Artisan 測試運行器還包括一個方便的機制,用於列出應用程式中最慢的測試。使用 `--profile` 選項調用 `test` 命令,將呈現您十個最慢測試的列表,讓您輕鬆調查哪些測試可以改進以加快測試套件的速度: 220 | 221 | ```shell 222 | php artisan test --profile 223 | ``` 224 | 225 | I'm sorry, but I need the Markdown content that you want me to translate into traditional Chinese. Please paste the Markdown text here, and I will provide the translation according to the rules you've specified. 226 | -------------------------------------------------------------------------------- /upgrade.md: -------------------------------------------------------------------------------- 1 | # 升級指南 2 | 3 | - [從 11.x 升級到 12.0](#upgrade-12.0) 4 | 5 | 6 | ## 高影響變更 7 | 8 |
9 | 10 | - [更新依賴項目](#updating-dependencies) 11 | - [更新 Laravel 安裝程式](#updating-the-laravel-installer) 12 | 13 |
14 | 15 | 16 | ## 中等影響變更 17 | 18 |
19 | 20 | - [模型和 UUIDv7](#models-and-uuidv7) 21 | 22 |
23 | 24 | 25 | ## 低影響變更 26 | 27 |
28 | 29 | - [Carbon 3](#carbon-3) 30 | - [並發結果索引映射](#concurrency-result-index-mapping) 31 | - [圖像驗證現在排除 SVG 檔案](#image-validation) 32 | - [多結構資料庫檢查](#multi-schema-database-inspecting) 33 | - [巢狀陣列請求合併](#nested-array-request-merging) 34 | 35 |
36 | 37 | 38 | ## 從 11.x 升級到 12.0 39 | 40 | #### 預估升級時間:5 分鐘 41 | 42 | > [!NOTE] 43 | > 我們試圖記錄每一個可能的破壞性變更。由於一些這些破壞性變更位於框架的晦澀部分,只有部分變更可能會影響您的應用程式。想要節省時間嗎?您可以使用 [Laravel Shift](https://laravelshift.com/) 來自動化您的應用程式升級。 44 | 45 | 46 | ### 更新依賴項目 47 | 48 | **影響可能性:高** 49 | 50 | 您應該在應用程式的 `composer.json` 檔案中更新以下依賴項目: 51 | 52 |
53 | 54 | - `laravel/framework` 到 `^12.0` 55 | - `phpunit/phpunit` 到 `^11.0` 56 | - `pestphp/pest` 到 `^3.0` 57 | 58 |
59 | 60 | 61 | #### Carbon 3 62 | 63 | **影響可能性:低** 64 | 65 | 不再支援 [Carbon 2.x](https://carbon.nesbot.com/docs/)。所有 Laravel 12 應用程式現在需要 [Carbon 3.x](https://carbon.nesbot.com/docs/#api-carbon-3)。 66 | 67 | 68 | ### 更新 Laravel 安裝程式 69 | 70 | 如果您正在使用 Laravel 安裝程式 CLI 工具來建立新的 Laravel 應用程式,您應該更新您的安裝程式以與 Laravel 12.x 和 [新的 Laravel 入門套件](https://laravel.com/starter-kits) 兼容。如果您通過 `composer global require` 安裝了 Laravel 安裝程式,您可以使用 `composer global update` 來更新安裝程式: 71 | 72 | ```shell 73 | composer global update laravel/installer 74 | ``` 75 | 76 | 如果您最初是通過 `php.new` 安裝 PHP 和 Laravel,您可以簡單地重新運行您的操作系統的 `php.new` 安裝命令以安裝最新版本的 PHP 和 Laravel 安裝程式: 77 | 78 | ```shell tab=macOS 79 | /bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)" 80 | ``` 81 | 82 | ```shell tab=Windows PowerShell 83 | # 以系統管理員身份運行... 84 | Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://php.new/install/windows/8.4')) 85 | ``` 86 | 87 | ```shell tab=Linux 88 | /bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)" 89 | ``` 90 | 91 | 或者,如果您正在使用 [Laravel Herd's](https://herd.laravel.com) 捆綁的 Laravel 安裝程式副本,您應該將您的 Herd 安裝更新到最新版本。 92 | 93 | 94 | ### 並發 95 | 96 | 97 | #### 並發結果索引映射 98 | 99 | **影響可能性:低** 100 | 101 | 當使用關聯數組調用 `Concurrency::run` 方法時,現在會將並發操作的結果與其相關的鍵一起返回: 102 | 103 | ```php 104 | $result = Concurrency::run([ 105 | 'task-1' => fn () => 1 + 1, 106 | 'task-2' => fn () => 2 + 2, 107 | ]); 108 | 109 | // ['task-1' => 2, 'task-2' => 4] 110 | ``` 111 | 112 | 113 | ### 資料庫 114 | 115 | 116 | #### 多模式資料庫檢查 117 | 118 | **影響可能性:低** 119 | 120 | `Schema::getTables()`、`Schema::getViews()` 和 `Schema::getTypes()` 方法現在默認包含所有模式的結果。您可以傳遞 `schema` 參數以僅檢索給定模式的結果: 121 | 122 | ```php 123 | // All tables on all schemas... 124 | $tables = Schema::getTables(); 125 | 126 | // All tables on the 'main' schema... 127 | $table = Schema::getTables(schema: 'main'); 128 | 129 | // All tables on the 'main' and 'blog' schemas... 130 | $table = Schema::getTables(schema: ['main', 'blog']); 131 | ``` 132 | 133 | `Schema::getTableListing()` 方法現在默認返回帶有模式限定名的表名。您可以傳遞 `schemaQualified` 參數以根據需要更改行為: 134 | 135 | ```php 136 | $tables = Schema::getTableListing(); 137 | // ['main.migrations', 'main.users', 'blog.posts'] 138 | 139 | $table = Schema::getTableListing(schema: 'main'); 140 | // ['main.migrations', 'main.users'] 141 | 142 | $table = Schema::getTableListing(schema: 'main', schemaQualified: false); 143 | // ['migrations', 'users'] 144 | ``` 145 | 146 | `db:table` 和 `db:show` 命令現在在 MySQL、MariaDB 和 SQLite 上輸出所有模式的結果,就像 PostgreSQL 和 SQL Server 一樣。 147 | 148 | 149 | 150 | ### Eloquent 151 | 152 | 153 | #### 模型和 UUIDv7 154 | 155 | **影響可能性:中** 156 | 157 | `HasUuids` 特性現在返回與 UUID 規範第 7 版(有序 UUID)兼容的 UUID。如果您希望繼續使用有序 UUIDv4 字串作為模型 ID,您現在應該使用 `HasVersion4Uuids` 特性: 158 | 159 | ```php 160 | use Illuminate\Database\Eloquent\Concerns\HasUuids; // [tl! remove] 161 | use Illuminate\Database\Eloquent\Concerns\HasVersion4Uuids as HasUuids; // [tl! add] 162 | ``` 163 | 164 | `HasVersion7Uuids` 特性已被移除。如果您之前使用此特性,現在應改為使用 `HasUuids` 特性,它現在提供相同的行為。 165 | 166 | 167 | ### 請求 168 | 169 | 170 | #### 嵌套陣列請求合併 171 | 172 | **影響可能性:低** 173 | 174 | `$request->mergeIfMissing()` 方法現在允許使用「點」符號記號合併嵌套陣列資料。如果您之前依賴此方法來創建包含「點」符號版本鍵的頂層陣列鍵,您可能需要調整應用程式以適應這種新行為: 175 | 176 | ```php 177 | $request->mergeIfMissing([ 178 | 'user.last_name' => 'Otwell', 179 | ]); 180 | ``` 181 | 182 | 183 | ### 驗證 184 | 185 | 186 | #### 圖片驗證現在排除 SVG 187 | 188 | `image` 驗證規則不再默認允許 SVG 圖片。如果您希望在使用 `image` 規則時允許 SVG,您必須明確允許它們: 189 | 190 | ```php 191 | use Illuminate\Validation\Rules\File; 192 | 193 | 'photo' => 'required|image:allow_svg' 194 | 195 | // Or... 196 | 'photo' => ['required', File::image(allowSvg: true)], 197 | ``` 198 | 199 | 200 | ### 其他 201 | 202 | 我們也鼓勵您查看 `laravel/laravel` [GitHub 存儲庫](https://github.com/laravel/laravel) 中的更改。雖然這些更改並非必要,但您可能希望將這些文件與您的應用程式保持同步。本次升級指南將涵蓋其中一些更改,但其他更改,如配置文件或註釋的更改,則不會。您可以使用 [GitHub 比較工具](https://github.com/laravel/laravel/compare/11.x...12.x) 輕鬆查看這些更改,並選擇哪些更新對您重要。 203 | 204 | I'm ready to translate. Please paste the Markdown content for me to work on. 205 | -------------------------------------------------------------------------------- /urls.md: -------------------------------------------------------------------------------- 1 | # URL 生成 2 | 3 | - [簡介](#introduction) 4 | - [基礎知識](#the-basics) 5 | - [生成 URL](#generating-urls) 6 | - [存取目前的 URL](#accessing-the-current-url) 7 | - [具名路由的 URL](#urls-for-named-routes) 8 | - [簽署 URL](#signed-urls) 9 | - [控制器行為的 URL](#urls-for-controller-actions) 10 | - [預設值](#default-values) 11 | 12 | 13 | ## 簡介 14 | 15 | Laravel 提供了幾個輔助函式,可協助您為應用程式生成 URL。這些輔助函式在建立模板中的連結和 API 回應時非常有用,或者在將重新導向回應生成到應用程式的其他部分時非常有用。 16 | 17 | 18 | ## 基礎知識 19 | 20 | 21 | ### 生成 URL 22 | 23 | `url` 輔助函式可用於為您的應用程式生成任意 URL。生成的 URL 將自動使用應用程式處理的目前請求中的方案(HTTP 或 HTTPS)和主機: 24 | 25 | ```php 26 | $post = App\Models\Post::find(1); 27 | 28 | echo url("/posts/{$post->id}"); 29 | 30 | // http://example.com/posts/1 31 | ``` 32 | 33 | 若要生成帶有查詢字串參數的 URL,您可以使用 `query` 方法: 34 | 35 | ```php 36 | echo url()->query('/posts', ['search' => 'Laravel']); 37 | 38 | // https://example.com/posts?search=Laravel 39 | 40 | echo url()->query('/posts?sort=latest', ['search' => 'Laravel']); 41 | 42 | // http://example.com/posts?sort=latest&search=Laravel 43 | ``` 44 | 45 | 提供已存在於路徑中的查詢字串參數將覆蓋其現有值: 46 | 47 | ```php 48 | echo url()->query('/posts?sort=latest', ['sort' => 'oldest']); 49 | 50 | // http://example.com/posts?sort=oldest 51 | ``` 52 | 53 | 也可以將值陣列作為查詢參數傳遞。這些值將在生成的 URL 中正確鍵入和編碼: 54 | 55 | ```php 56 | echo $url = url()->query('/posts', ['columns' => ['title', 'body']]); 57 | 58 | // http://example.com/posts?columns%5B0%5D=title&columns%5B1%5D=body 59 | 60 | echo urldecode($url); 61 | 62 | // http://example.com/posts?columns[0]=title&columns[1]=body 63 | ``` 64 | 65 | 66 | ### 存取目前的 URL 67 | 68 | 如果未提供路徑給 `url` 輔助函式,將返回一個 `Illuminate\Routing\UrlGenerator` 實例,讓您可以存取有關目前 URL 的資訊: 69 | 70 | ```php 71 | // Get the current URL without the query string... 72 | echo url()->current(); 73 | 74 | // Get the current URL including the query string... 75 | echo url()->full(); 76 | 77 | // Get the full URL for the previous request... 78 | echo url()->previous(); 79 | 80 | // Get the path for the previous request... 81 | echo url()->previousPath(); 82 | ``` 83 | 84 | 這些方法也可以透過 `URL` [Facades](/docs/{{version}}/facades) 進行存取: 85 | 86 | ```php 87 | use Illuminate\Support\Facades\URL; 88 | 89 | echo URL::current(); 90 | ``` 91 | 92 | 93 | ## 具名路由的 URL 94 | 95 | `route` 輔助函式可用於生成至 [具名路由](/docs/{{version}}/routing#named-routes) 的 URL。具名路由允許您生成 URL,而不必與路由上實際定義的 URL 耦合。因此,如果路由的 URL 變更,則不需要修改對 `route` 函式的呼叫。例如,假設您的應用程式包含如下所示的路由定義: 96 | 97 | ```php 98 | Route::get('/post/{post}', function (Post $post) { 99 | // ... 100 | })->name('post.show'); 101 | ``` 102 | 103 | 要生成到此路由的URL,您可以像這樣使用 `route` 輔助函式: 104 | 105 | ```php 106 | echo route('post.show', ['post' => 1]); 107 | 108 | // http://example.com/post/1 109 | ``` 110 | 111 | 當然,`route` 輔助函式也可用於生成具有多個參數的路由的URL: 112 | 113 | ```php 114 | Route::get('/post/{post}/comment/{comment}', function (Post $post, Comment $comment) { 115 | // ... 116 | })->name('comment.show'); 117 | 118 | echo route('comment.show', ['post' => 1, 'comment' => 3]); 119 | 120 | // http://example.com/post/1/comment/3 121 | ``` 122 | 123 | 任何額外的陣列元素,如果不對應路由的定義參數,將被添加到URL的查詢字串中: 124 | 125 | ```php 126 | echo route('post.show', ['post' => 1, 'search' => 'rocket']); 127 | 128 | // http://example.com/post/1?search=rocket 129 | ``` 130 | 131 | 132 | #### Eloquent 模型 133 | 134 | 您通常會使用 [Eloquent 模型](/docs/{{version}}/eloquent) 的路由鍵(通常是主鍵)來生成URL。因此,您可以將 Eloquent 模型作為參數值傳遞。`route` 輔助函式將自動提取模型的路由鍵: 135 | 136 | ```php 137 | echo route('post.show', ['post' => $post]); 138 | ``` 139 | 140 | 141 | ### 簽名URL 142 | 143 | Laravel 允許您輕鬆地創建帶有簽名的URL以訪問命名路由。這些URL具有附加到查詢字串的“簽名”哈希,這使得 Laravel 能夠驗證自從創建以來URL尚未被修改。簽名URL尤其適用於需要對URL進行保護的公開訪問路由。 144 | 145 | 例如,您可以使用簽名URL來實現一個公開的“取消訂閱”鏈接,並將其發送給您的客戶。要創建到命名路由的簽名URL,請使用 `URL` Facade 的 `signedRoute` 方法: 146 | 147 | ```php 148 | use Illuminate\Support\Facades\URL; 149 | 150 | return URL::signedRoute('unsubscribe', ['user' => 1]); 151 | ``` 152 | 153 | 您可以通過向 `signedRoute` 方法提供 `absolute: false` 參數,從簽名URL哈希中排除域: 154 | 155 | ```php 156 | return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false); 157 | ``` 158 | 159 | 如果您想生成一個在指定時間後過期的臨時簽名路由URL,您可以使用 `temporarySignedRoute` 方法。當 Laravel 驗證臨時簽名路由URL時,它將確保編碼到簽名URL中的到期時間戳記尚未過期: 160 | 161 | ```php 162 | use Illuminate\Support\Facades\URL; 163 | 164 | return URL::temporarySignedRoute( 165 | 'unsubscribe', now()->addMinutes(30), ['user' => 1] 166 | ); 167 | ``` 168 | 169 | 170 | #### 驗證已簽署的路由請求 171 | 172 | 要驗證傳入請求是否具有有效簽名,您應該在傳入的 `Illuminate\Http\Request` 實例上調用 `hasValidSignature` 方法: 173 | 174 | ```php 175 | use Illuminate\Http\Request; 176 | 177 | Route::get('/unsubscribe/{user}', function (Request $request) { 178 | if (! $request->hasValidSignature()) { 179 | abort(401); 180 | } 181 | 182 | // ... 183 | })->name('unsubscribe'); 184 | ``` 185 | 186 | 有時,您可能需要允許應用程式的前端附加數據到已簽署的 URL,例如在執行客戶端分頁時。因此,您可以指定應該在驗證已簽署的 URL 時忽略的請求查詢參數,使用 `hasValidSignatureWhileIgnoring` 方法。請記住,忽略參數允許任何人修改請求中的這些參數: 187 | 188 | ```php 189 | if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) { 190 | abort(401); 191 | } 192 | ``` 193 | 194 | 您可以將 `signed` (`Illuminate\Routing\Middleware\ValidateSignature`) [中介層](/docs/{{version}}/middleware) 分配給路由,而不是使用傳入請求實例來驗證已簽署的 URL。如果傳入請求沒有有效簽名,中介層將自動返回 `403` HTTP 回應: 195 | 196 | ```php 197 | Route::post('/unsubscribe/{user}', function (Request $request) { 198 | // ... 199 | })->name('unsubscribe')->middleware('signed'); 200 | ``` 201 | 202 | 如果您的已簽署 URL 不包含 URL 雜湊中的域名,您應該向中介層提供 `relative` 參數: 203 | 204 | ```php 205 | Route::post('/unsubscribe/{user}', function (Request $request) { 206 | // ... 207 | })->name('unsubscribe')->middleware('signed:relative'); 208 | ``` 209 | 210 | 211 | #### 回應無效的已簽署路由 212 | 213 | 當有人訪問已過期的已簽署 URL 時,他們將收到一個通用錯誤頁面,顯示 `403` HTTP 狀態碼。但是,您可以通過在應用程式的 `bootstrap/app.php` 文件中定義 `InvalidSignatureException` 錯誤的自定義 "render" 閉包來自定義此行為: 214 | 215 | ```php 216 | use Illuminate\Routing\Exceptions\InvalidSignatureException; 217 | 218 | ->withExceptions(function (Exceptions $exceptions) { 219 | $exceptions->render(function (InvalidSignatureException $e) { 220 | return response()->view('errors.link-expired', status: 403); 221 | }); 222 | }) 223 | ``` 224 | 225 | 226 | ## 控制器行為的 URL 227 | 228 | `action` 函式為給定的控制器行為生成 URL: 229 | 230 | ```php 231 | use App\Http\Controllers\HomeController; 232 | 233 | $url = action([HomeController::class, 'index']); 234 | ``` 235 | 236 | 如果控制器方法接受路由參數,您可以將路由參數的關聯陣列作為函數的第二個引數傳遞: 237 | 238 | ```php 239 | $url = action([UserController::class, 'profile'], ['id' => 1]); 240 | ``` 241 | 242 | 243 | ## 預設值 244 | 245 | 對於某些應用程式,您可能希望為某些 URL 參數指定請求範圍的預設值。例如,假設您的許多路由定義了一個 `{locale}` 參數: 246 | 247 | ```php 248 | Route::get('/{locale}/posts', function () { 249 | // ... 250 | })->name('post.index'); 251 | ``` 252 | 253 | 每次調用 `route` 輔助函式時都必須傳遞 `locale` 參數可能很繁瑣。因此,您可以使用 `URL::defaults` 方法來定義此參數的預設值,該值將始終應用於當前請求期間。您可能希望從 [路由中介層](/docs/{{version}}/middleware#assigning-middleware-to-routes) 中調用此方法,以便您可以訪問當前請求: 254 | 255 | ```php 256 | $request->user()->locale]); 275 | 276 | return $next($request); 277 | } 278 | } 279 | ``` 280 | 281 | 設定 `locale` 參數的預設值後,在透過 `route` 輔助函式生成 URL 時將不再需要傳遞其值。 282 | 283 | 284 | #### URL 預設值與中介層優先順序 285 | 286 | 設定 URL 的預設值可能會干擾 Laravel 對隱式模型綁定的處理。因此,您應該 [優先執行設定 URL 預設值的中介層](/docs/{{version}}/middleware#sorting-middleware),以便在 Laravel 自身的 `SubstituteBindings` 中介層之前執行。您可以在應用程式的 `bootstrap/app.php` 檔案中使用 `priority` 中介層方法來實現這一點: 287 | 288 | ```php 289 | ->withMiddleware(function (Middleware $middleware) { 290 | $middleware->prependToPriorityList( 291 | before: \Illuminate\Routing\Middleware\SubstituteBindings::class, 292 | prepend: \App\Http\Middleware\SetDefaultLocaleForUrls::class, 293 | ); 294 | }) 295 | ``` 296 | -------------------------------------------------------------------------------- /verification.md: -------------------------------------------------------------------------------- 1 | # 電子郵件驗證 2 | 3 | - [簡介](#introduction) 4 | - [模型準備](#model-preparation) 5 | - [資料庫準備](#database-preparation) 6 | - [路由](#verification-routing) 7 | - [電子郵件驗證通知](#the-email-verification-notice) 8 | - [電子郵件驗證處理器](#the-email-verification-handler) 9 | - [重新發送驗證電子郵件](#resending-the-verification-email) 10 | - [保護路由](#protecting-routes) 11 | - [自訂](#customization) 12 | - [事件](#events) 13 | 14 | 15 | ## 簡介 16 | 17 | 許多網路應用程式在使用應用程式之前要求使用者驗證其電子郵件地址。 Laravel 提供了方便的內建服務來發送和驗證電子郵件驗證請求,而不是強迫您為每個創建的應用程式手動重新實現此功能。 18 | 19 | > [!NOTE] 20 | > 想要快速開始嗎?在全新的 Laravel 應用程式中安裝其中一個 [Laravel 應用程式起始套件](/docs/{{version}}/starter-kits)。這些起始套件將負責搭建整個身分驗證系統,包括電子郵件驗證支援。 21 | 22 | 23 | ### 模型準備 24 | 25 | 在開始之前,請確認您的 `App\Models\User` 模型實作了 `Illuminate\Contracts\Auth\MustVerifyEmail` 合約: 26 | 27 | ```php 28 | middleware('auth')->name('verification.notice'); 74 | ``` 75 | 76 | 返回電子郵件驗證通知的路由應該命名為 `verification.notice`。重要的是,該路由被分配了這個確切的名稱,因為如果用戶尚未驗證其電子郵件地址,則 Laravel 隨附的 `verified` 中間件將自動重定向到此路由名稱。 77 | 78 | > [!NOTE] 79 | > 當手動實現電子郵件驗證時,您需要自己定義驗證通知視圖的內容。如果您希望包含所有必要的身份驗證和驗證視圖的腳手架,請查看 [Laravel 應用程序起始套件](/docs/{{version}}/starter-kits)。 80 | 81 | ### 電子郵件驗證處理程序 82 | 83 | 接下來,我們需要定義一個路由,用於處理當用戶點擊發送到他們郵箱的電子郵件驗證鏈接時生成的請求。這個路由應該被命名為 `verification.verify`,並分配 `auth` 和 `signed` 中間件: 84 | 85 | ```php 86 | use Illuminate\Foundation\Auth\EmailVerificationRequest; 87 | 88 | Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) { 89 | $request->fulfill(); 90 | 91 | return redirect('/home'); 92 | })->middleware(['auth', 'signed'])->name('verification.verify'); 93 | ``` 94 | 95 | 在繼續之前,讓我們仔細看看這個路由。首先,您會注意到我們使用的是 `EmailVerificationRequest` 請求類型,而不是典型的 `Illuminate\Http\Request` 實例。`EmailVerificationRequest` 是 Laravel 中包含的一個[表單請求](/docs/{{version}}/validation#form-request-validation),這個請求將自動處理驗證請求的 `id` 和 `hash` 參數。 96 | 97 | 接下來,我們可以直接調用請求上的 `fulfill` 方法。這個方法將調用已驗證用戶上的 `markEmailAsVerified` 方法並分派 `Illuminate\Auth\Events\Verified` 事件。`markEmailAsVerified` 方法通過 `Illuminate\Foundation\Auth\User` 基類對默認的 `App\Models\User` 模型可用。一旦用戶的電子郵件地址被驗證,您可以將其重定向到任何您希望的地方。 98 | 99 | ### 重新發送驗證郵件 100 | 101 | 有時用戶可能會遺失或意外刪除電子郵件地址驗證郵件。為了應對這種情況,您可能希望定義一個路由,允許用戶請求重新發送驗證郵件。然後,您可以通過在您的[驗證通知視圖](#the-email-verification-notice)中放置一個簡單的表單提交按鈕來對這個路由進行請求: 102 | 103 | ```php 104 | use Illuminate\Http\Request; 105 | 106 | Route::post('/email/verification-notification', function (Request $request) { 107 | $request->user()->sendEmailVerificationNotification(); 108 | 109 | return back()->with('message', 'Verification link sent!'); 110 | })->middleware(['auth', 'throttle:6,1'])->name('verification.send'); 111 | ``` 112 | 113 | ### 保護路由 114 | 115 | [路由中間件](/docs/{{version}}/middleware)可用於僅允許已驗證用戶訪問特定路由。Laravel 包括一個 `verified` [中間件別名](/docs/{{version}}/middleware#middleware-aliases),這是 `Illuminate\Auth\Middleware\EnsureEmailIsVerified` 中間件類的別名。由於這個別名已經被 Laravel 自動註冊,您只需要將 `verified` 中間件附加到路由定義中即可。通常,這個中間件與 `auth` 中間件配對使用: 116 | 117 | ```php 118 | Route::get('/profile', function () { 119 | // 只有已驗證的使用者可以存取此路由... 120 | })->middleware(['auth', 'verified']); 121 | ``` 122 | 123 | 如果未驗證的使用者嘗試存取已設定此中介層的路由,他們將自動重新導向至 `verification.notice` [命名路由](/docs/{{version}}/routing#named-routes)。 124 | 125 | 126 | ## 自訂 127 | 128 | 129 | #### 驗證郵件自訂 130 | 131 | 雖然預設的電子郵件驗證通知應該滿足大多數應用程式的需求,Laravel 允許您自訂電子郵件驗證郵件訊息的構建方式。 132 | 133 | 要開始,將一個閉包傳遞給 `Illuminate\Auth\Notifications\VerifyEmail` 通知提供的 `toMailUsing` 方法。閉包將接收到正在接收通知的可通知模型實例,以及用戶必須訪問以驗證其電子郵件地址的已簽署電子郵件驗證 URL。閉包應該返回 `Illuminate\Notifications\Messages\MailMessage` 的實例。通常,您應該從應用程式的 `AppServiceProvider` 類別的 `boot` 方法中呼叫 `toMailUsing` 方法: 134 | 135 | ```php 136 | use Illuminate\Auth\Notifications\VerifyEmail; 137 | use Illuminate\Notifications\Messages\MailMessage; 138 | 139 | /** 140 | * Bootstrap any application services. 141 | */ 142 | public function boot(): void 143 | { 144 | // ... 145 | 146 | VerifyEmail::toMailUsing(function (object $notifiable, string $url) { 147 | return (new MailMessage) 148 | ->subject('Verify Email Address') 149 | ->line('Click the button below to verify your email address.') 150 | ->action('Verify Email Address', $url); 151 | }); 152 | } 153 | ``` 154 | 155 | > [!NOTE] 156 | > 若要瞭解更多關於郵件通知的資訊,請參考 [郵件通知文件](/docs/{{version}}/notifications#mail-notifications)。 157 | 158 | 159 | ## 事件 160 | 161 | 當使用 [Laravel 應用程式起始套件](/docs/{{version}}/starter-kits) 時,Laravel 在電子郵件驗證過程中派發 `Illuminate\Auth\Events\Verified` [事件](/docs/{{version}}/events)。如果您正在手動處理應用程式的電子郵件驗證,您可能希望在驗證完成後手動派發這些事件。 162 | -------------------------------------------------------------------------------- /views.md: -------------------------------------------------------------------------------- 1 | # 檢視 2 | 3 | - [簡介](#introduction) 4 | - [在 React / Vue 中撰寫檢視](#writing-views-in-react-or-vue) 5 | - [建立和呈現檢視](#creating-and-rendering-views) 6 | - [巢狀檢視目錄](#nested-view-directories) 7 | - [建立第一個可用檢視](#creating-the-first-available-view) 8 | - [確定檢視是否存在](#determining-if-a-view-exists) 9 | - [將資料傳遞給檢視](#passing-data-to-views) 10 | - [與所有檢視共享資料](#sharing-data-with-all-views) 11 | - [檢視組合器](#view-composers) 12 | - [檢視建立者](#view-creators) 13 | - [優化檢視](#optimizing-views) 14 | 15 | 16 | ## 簡介 17 | 18 | 當然,直接從您的路由和控制器返回完整的 HTML 文件字符串並不實際。幸運的是,檢視提供了一種方便的方式來將所有 HTML 放在單獨的文件中。 19 | 20 | 檢視將您的控制器 / 應用邏輯與您的呈現邏輯分開,並存儲在 `resources/views` 目錄中。在使用 Laravel 時,檢視模板通常使用 [Blade 模板語言](/docs/{{version}}/blade) 來撰寫。一個簡單的檢視可能如下所示: 21 | 22 | ```blade 23 | 24 | 25 | 26 | 27 |

Hello, {{ $name }}

28 | 29 | 30 | ``` 31 | 32 | 由於此檢視存儲在 `resources/views/greeting.blade.php`,我們可以使用全域 `view` 助手返回它,如下所示: 33 | 34 | ```php 35 | Route::get('/', function () { 36 | return view('greeting', ['name' => 'James']); 37 | }); 38 | ``` 39 | 40 | > [!NOTE] 41 | > 想瞭解如何撰寫 Blade 模板的更多資訊嗎?查看完整的 [Blade 文件](/docs/{{version}}/blade) 以開始。 42 | 43 | 44 | ### 在 React / Vue 中撰寫檢視 45 | 46 | 許多開發人員開始偏好使用 React 或 Vue 撰寫其前端模板,而不是透過 Blade 在 PHP 中撰寫。Laravel 使這變得輕鬆,感謝 [Inertia](https://inertiajs.com/),這個庫使得將您的 React / Vue 前端與 Laravel 後端緊密結合變得輕而易舉,而不需要建立 SPA 的典型複雜性。 47 | 48 | 我們的 [React 和 Vue 應用程式起始套件](/docs/{{version}}/starter-kits) 為您提供了一個很好的起點,用 Inertia 驅動的下一個 Laravel 應用程式。 49 | 50 | ## 創建和渲染視圖 51 | 52 | 您可以通過將具有 `.blade.php` 擴展名的文件放置在應用程序的 `resources/views` 目錄中,或使用 `make:view` Artisan 命令來創建視圖: 53 | 54 | ```shell 55 | php artisan make:view greeting 56 | ``` 57 | 58 | `.blade.php` 擴展名通知框架該文件包含 [Blade 模板](/docs/{{version}}/blade)。Blade 模板包含 HTML 以及 Blade 指示詞,讓您可以輕鬆地輸出值,創建 "if" 陳述,遍歷數據等。 59 | 60 | 創建視圖後,您可以使用全局 `view` 助手從應用程序的路由或控制器中返回它: 61 | 62 | ```php 63 | Route::get('/', function () { 64 | return view('greeting', ['name' => 'James']); 65 | }); 66 | ``` 67 | 68 | 也可以使用 `View` Facade 返回視圖: 69 | 70 | ```php 71 | use Illuminate\Support\Facades\View; 72 | 73 | return View::make('greeting', ['name' => 'James']); 74 | ``` 75 | 76 | 如您所見,傳遞給 `view` 助手的第一個參數對應於 `resources/views` 目錄中視圖文件的名稱。第二個參數是應該提供給視圖的數據陣列。在這種情況下,我們傳遞了 `name` 變數,該變數使用 [Blade 語法](/docs/{{version}}/blade) 在視圖中顯示。 77 | 78 | ### 嵌套視圖目錄 79 | 80 | 視圖也可以嵌套在 `resources/views` 目錄的子目錄中。可以使用 "點" 表示法來引用嵌套視圖。例如,如果您的視圖存儲在 `resources/views/admin/profile.blade.php`,您可以像這樣從應用程序的路由/控制器中返回它: 81 | 82 | ```php 83 | return view('admin.profile', $data); 84 | ``` 85 | 86 | > [!WARNING] 87 | > 視圖目錄名稱不應包含 `.` 字元。 88 | 89 | ### 創建第一個可用視圖 90 | 91 | 使用 `View` Facade 的 `first` 方法,您可以創建給定視圖陣列中存在的第一個視圖。如果您的應用程序或套件允許自定義或覆蓋視圖,這可能很有用: 92 | 93 | ```php 94 | use Illuminate\Support\Facades\View; 95 | 96 | return View::first(['custom.admin', 'admin'], $data); 97 | ``` 98 | 99 | 100 | ### 判斷視圖是否存在 101 | 102 | 如果您需要確定視圖是否存在,可以使用 `View` 門面。`exists` 方法將在視圖存在時返回 `true`: 103 | 104 | ```php 105 | use Illuminate\Support\Facades\View; 106 | 107 | if (View::exists('admin.profile')) { 108 | // ... 109 | } 110 | ``` 111 | 112 | 113 | ## 傳遞資料給視圖 114 | 115 | 如前面的範例所示,您可以將資料陣列傳遞給視圖,以使該資料在視圖中可用: 116 | 117 | ```php 118 | return view('greetings', ['name' => 'Victoria']); 119 | ``` 120 | 121 | 以這種方式傳遞資訊時,資料應該是一個具有鍵/值對的陣列。在向視圖提供資料後,您可以使用資料的鍵在視圖中訪問每個值,例如 ``。 122 | 123 | 作為將完整資料陣列傳遞給 `view` 輔助函式的替代方法,您可以使用 `with` 方法將個別資料片段添加到視圏。`with` 方法返回視圖物件的實例,以便您可以在返回視圖之前繼續鏈接方法: 124 | 125 | ```php 126 | return view('greeting') 127 | ->with('name', 'Victoria') 128 | ->with('occupation', 'Astronaut'); 129 | ``` 130 | 131 | 132 | ### 與所有視圖共享資料 133 | 134 | 偶爾,您可能需要與應用程式渲染的所有視圖共享資料。您可以使用 `View` 門面的 `share` 方法來實現。通常,您應該將對 `share` 方法的調用放在服務提供者的 `boot` 方法中。您可以將它們添加到 `App\Providers\AppServiceProvider` 類中,或者生成一個獨立的服務提供者來存放它們: 135 | 136 | ```php 137 | 164 | ## 視圖組件 165 | 166 | 視圖組件是在渲染視圖時調用的回呼函式或類方法。如果您有要綁定到視圖的資料,並且每次該視圖被渲染時都需要這些資料,則視圖組件可以幫助您將該邏輯組織到單一位置。如果同一視圖由應用程式中的多個路由或控制器返回,並且始終需要特定的資料片段,則視圖組件可能特別有用。 167 | 168 | 通常,視圖組件會在您的應用程式的其中一個[服務提供者](/docs/{{version}}/providers)中註冊。在這個例子中,我們假設 `App\Providers\AppServiceProvider` 會包含這個邏輯。 169 | 170 | 我們將使用 `View` 門面的 `composer` 方法來註冊視圖組件。Laravel 不包含基於類別的視圖組件的預設目錄,因此您可以自由地按照您的喜好進行組織。例如,您可以建立一個 `app/View/Composers` 目錄來存放您應用程式的所有視圖組件: 171 | 172 | ```php 173 | with('count', $this->users->count()); 237 | } 238 | } 239 | ``` 240 | 241 | 正如您所看到的,所有視圖組件都是透過[服務容器](/docs/{{version}}/container)解析的,因此您可以在組件的建構子中型別提示任何您需要的依賴。 242 | 243 | 244 | #### 將組件附加到多個視圖 245 | 246 | 您可以通過將視圖陣列作為 `composer` 方法的第一個引數一次性附加視圖組件到多個視圖: 247 | 248 | ```php 249 | use App\Views\Composers\MultiComposer; 250 | use Illuminate\Support\Facades\View; 251 | 252 | View::composer( 253 | ['profile', 'dashboard'], 254 | MultiComposer::class 255 | ); 256 | ``` 257 | 258 | `composer` 方法還接受 `*` 字元作為萬用字元,允許您將一個組件附加到所有視圖: 259 | 260 | ```php 261 | use Illuminate\Support\Facades; 262 | use Illuminate\View\View; 263 | 264 | Facades\View::composer('*', function (View $view) { 265 | // ... 266 | }); 267 | ``` 268 | 269 | 270 | ### 視圖創建器 271 | 272 | 視圖「創建器」與視圖組件非常相似;但是,它們會在視圖實例化後立即執行,而不是等到視圖即將呈現時。要註冊視圖創建器,請使用 `creator` 方法: 273 | 274 | ```php 275 | use App\View\Creators\ProfileCreator; 276 | use Illuminate\Support\Facades\View; 277 | 278 | View::creator('profile', ProfileCreator::class); 279 | ``` 280 | 281 | 282 | ## 優化視圖 283 | 284 | 預設情況下,Blade 模板視圖是按需編譯的。當執行呈現視圖的請求時,Laravel 會確定是否存在視圖的編譯版本。如果檔案存在,Laravel 將確定未編譯的視圖是否比編譯的視圖修改得更近。如果編譯的視圖不存在,或者未編譯的視圖已經被修改,Laravel 將重新編譯視圖。 285 | 286 | 在請求期間編譯視圖可能會對效能產生輕微負面影響,因此 Laravel 提供了 `view:cache` Artisan 指令,用於預編譯應用程式使用的所有視圖。為了提高效能,您可能希望將此指令作為部署流程的一部分運行: 287 | 288 | ```shell 289 | php artisan view:cache 290 | ``` 291 | 292 | 您可以使用 `view:clear` 指令來清除視圖快取: 293 | 294 | ```shell 295 | php artisan view:clear 296 | ``` 297 | --------------------------------------------------------------------------------