|
| 1 | +# Codeigniter4-Roadrunner |
| 2 | + |
| 3 | +<p align="center"> |
| 4 | + <img src="https://i.imgur.com/sCjeSTo.png" alt="logo" width="500" /> |
| 5 | +</p> |
| 6 | + |
| 7 | +[](//packagist.org/packages/sdpmlab/codeigniter4-roadrunner) [](//packagist.org/packages/sdpmlab/codeigniter4-roadrunner) [](//packagist.org/packages/sdpmlab/codeigniter4-roadrunner) [](//packagist.org/packages/sdpmlab/codeigniter4-roadrunner) |
| 8 | + |
| 9 | +Codeigniter4-RoadRunner 提供的是 Roadrunner-Worker 與 Codeigniter4 在 Request 與 Response 物件上的同步,因為 Codeigniter4 並沒有完整實作 [PSR-7 規範](https://codeigniter.tw/user_guide/intro/psr.html)。所以你需要使用這個程式庫才能讓你的 Codeigniter4 專案透過 RoadRunner Server 運作。 |
| 10 | + |
| 11 | +> 這個程式庫目前處於開發版,功能尚未穩定。請不要將它運用在正式環境中。 |
| 12 | +
|
| 13 | +## 安裝 |
| 14 | + |
| 15 | +### 需求 |
| 16 | +1. CodeIgniter Framework 4.* |
| 17 | +2. Composer |
| 18 | +3. 安裝並開啟 php-curl 擴充套件 |
| 19 | +4. 安裝並開啟 php-zip 擴充套件 |
| 20 | + |
| 21 | +### Composer 安裝 |
| 22 | + |
| 23 | +於專案根目錄下,使用 Composer 下載程式庫與其所需之依賴。 |
| 24 | + |
| 25 | +``` |
| 26 | +composer require sdpmlab/codeigniter4-roadrunner "v1.0.0-beta.2" |
| 27 | +``` |
| 28 | + |
| 29 | +使用程式庫提供的內建指令初始化 Roadrunner 與其所需的檔案。 |
| 30 | + |
| 31 | +``` |
| 32 | +php spark ciroad:init |
| 33 | +``` |
| 34 | + |
| 35 | +## 運作伺服器 |
| 36 | + |
| 37 | +你可以選擇使用不同的指令在專案根目錄中運作 RoadRunner Server: |
| 38 | + |
| 39 | +1. 使用 Codeigniter4 spark 指令 |
| 40 | + ``` |
| 41 | + php spark ciroad:start -v -d |
| 42 | + ``` |
| 43 | +2. 在 Windows-cmd 中直使用 RoadRunner 指令 |
| 44 | + ``` |
| 45 | + rr.exe serve -v -d |
| 46 | + ``` |
| 47 | +3. 在 MacOS/Linux 中直接使用 RoadRunner 指令 |
| 48 | + ``` |
| 49 | + ./rr serve -v -d |
| 50 | + ``` |
| 51 | + |
| 52 | +## 伺服器組態設定 |
| 53 | + |
| 54 | +伺服器組態設定應置於專案根目錄下,並命名為 `.rr.yaml` 。程式庫初始化後產出的預設檔案看起來會像這樣子: |
| 55 | + |
| 56 | +```yaml |
| 57 | +http: |
| 58 | + address: 0.0.0.0:8080 |
| 59 | + workers: |
| 60 | + command: "php psr-worker.php" |
| 61 | + # pool: |
| 62 | + # numWorkers: 50 |
| 63 | + # maxJobs: 10 |
| 64 | + |
| 65 | +static: |
| 66 | + enable: true |
| 67 | + dir: "public" |
| 68 | + forbid: [".php", ".htaccess"] |
| 69 | +``` |
| 70 | +
|
| 71 | +當然,你可以參考 [Roadrunner 手冊](https://roadrunner.dev/docs/intro-config) 建立符合專案需求的組態設定檔。 |
| 72 | +
|
| 73 | +## 開發建議 |
| 74 | +
|
| 75 | +### 自動重新載入 |
| 76 | +
|
| 77 | +RoadRunner 預設的情況下,必須在每次修改 php 檔案後重啟伺服器,你所做的修改才會生效,這在開發上似乎不那麼友善。 |
| 78 | +
|
| 79 | +你可以修改你的 `.rr.yaml` 組態設定檔案,加入以下設定後以 `-v -d` 開發模式啟動 RoadRunner Server,它將會自動偵測 PHP 檔案是否修改,並即時重新載入 Worker 。 |
| 80 | + |
| 81 | +```yaml |
| 82 | +# reload can reset rr servers when files change |
| 83 | +reload: |
| 84 | + # refresh interval (default 1s) |
| 85 | + interval: 1s |
| 86 | + # file extensions to watch, defaults to [.php] |
| 87 | + patterns: [".php"] |
| 88 | +``` |
| 89 | + |
| 90 | +`reload` 是非常耗費資源的,請不要在正式環境中打開這個選項。 |
| 91 | + |
| 92 | +### 使用 Codeigniter4 Request 與 Response 物件 |
| 93 | + |
| 94 | +Codeigniter4 並沒有實作完整的 [HTTP message 介面](https://www.php-fig.org/psr/psr-7/),所以這個程式庫著重於 `PSR-7 介面` 與 `Codeigniter4 HTTP 介面` 的同步。 |
| 95 | + |
| 96 | +基於上述原因,在開發上,你應該使用 Codeigniter4 所提供的 `$this->request` 或是使用全域函數 `\Config\Services::('request')` 取得正確的 request 物件;使用 `$this->response` 或是 `\Config\Services::('response')` 取得正確的 response 物件。 |
| 97 | + |
| 98 | +請注意,在建構給予使用者的響應時,不論是 `header` 或 `set-cookies` 應該避免使用 PHP 內建的方法進行設定。而是使用 [Codeigniter4 響應物件](https://codeigniter.tw/user_guide/outgoing/response.html) 提供的 `setHeader()` 與 `setCookie()` 進行設定。 |
| 99 | + |
| 100 | +### 以 return 結束控制器邏輯 |
| 101 | + |
| 102 | +在 Controller 中,盡量使用 return 結束程式邏輯,不論是視圖的響應或是 API 響應,減少使用 `echo` 輸出內容可以避免很多錯誤,就像這個樣子。 |
| 103 | + |
| 104 | +```php |
| 105 | +<?php namespace App\Controllers; |
| 106 | +
|
| 107 | +use CodeIgniter\API\ResponseTrait; |
| 108 | +
|
| 109 | +class Home extends BaseController |
| 110 | +{ |
| 111 | + use ResponseTrait; |
| 112 | +
|
| 113 | + public function index() |
| 114 | + { |
| 115 | + //Don't use : |
| 116 | + //echo view('welcome_message'); |
| 117 | + return view('welcome_message'); |
| 118 | + } |
| 119 | +
|
| 120 | + /** |
| 121 | + * send header |
| 122 | + */ |
| 123 | + public function sendHeader() |
| 124 | + { |
| 125 | + $this->response->setHeader("X-Set-Auth-Token",uniqid()); |
| 126 | + return $this->respond(["status"=>true]); |
| 127 | + } |
| 128 | +
|
| 129 | +} |
| 130 | +``` |
| 131 | + |
| 132 | +### 使用內建 Session 程式庫 |
| 133 | + |
| 134 | +我們只針對 Codeigniter4 內建 [Session 程式庫](https://codeigniter.tw/user_guide/libraries/sessions.html) 進行支援,並不保證使用 `session_start()` 與 `$_SESSION` 是否能照常運作。所以,你應該避免使用 PHP 內建的 Session 方法,而是以 Codeigniter4 框架內建的程式庫為主。 |
| 135 | + |
| 136 | +### 在只有一個 Worker 的環境中開發與除錯 |
| 137 | + |
| 138 | +因為 RoadRunner 與其他伺服器軟體(Nginx、Apache)有著根本上的不同,每個 Codeigniter4 將會以 Worker 的形式持久化於記憶體中,HTTP 的請求會重複利用到這些 Worker 進行處裡。所以,我們最好在只有單個 Worker 的情況下開發軟體並測試是否穩定,以證明在多個 Woker 的實際環境中能正常運作。 |
| 139 | + |
| 140 | +你可以參考以下 `.rr.yaml` 設定將 Worker 的數量降到最低: |
| 141 | + |
| 142 | +```yaml |
| 143 | +http: |
| 144 | + address: 0.0.0.0:8080 |
| 145 | + workers: |
| 146 | + command: "php psr-worker.php" |
| 147 | + pool: |
| 148 | + numWorkers: 1 |
| 149 | + maxJobs: 1 |
| 150 | +``` |
| 151 | + |
| 152 | +## 全域方法 |
| 153 | + |
| 154 | +我們提供了一些全域方法,幫助你更加順利地開發你的專案。 |
| 155 | + |
| 156 | +### 處裡檔案上傳 |
| 157 | + |
| 158 | +因為 RoadRunner Worker 無法傳遞正確的 `$_FILES` 內容,所以 Codeingiter4 的 [檔案上傳類別](https://codeigniter.tw/user_guide/libraries/uploaded_files.html) 將無法正確運作。對此,我們提供了符合 PSR-7 規範的檔案上傳類別,讓你可以正確地在 RoadRunner 中處理檔案上傳。就算你將專案切換到了其他伺服器環境(spark serve、Apache、Nginx)運作,這個類別依舊可以正常使用,並且不需要修改任何程式碼。 |
| 159 | + |
| 160 | +你可以在控制器(或任何地方),以 `SDPMlab\Ci4Roadrunner\UploadedFileBridge::getPsr7UploadedFiles()` 取得使用者上傳的檔案。這個方法將回傳以 Uploaded File 物件組成的陣列。此物件可用的方法與 [PSR-7 Uploaded File Interface](https://www.php-fig.org/psr/psr-7/#36-psrhttpmessageuploadedfileinterface) 中規範的一樣。 |
| 161 | + |
| 162 | +```php |
| 163 | +<?php namespace App\Controllers; |
| 164 | +
|
| 165 | +use CodeIgniter\API\ResponseTrait; |
| 166 | +use SDPMlab\Ci4Roadrunner\UploadedFileBridge; |
| 167 | +
|
| 168 | +class FileUploadTest extends BaseController |
| 169 | +{ |
| 170 | + use ResponseTrait; |
| 171 | +
|
| 172 | + protected $format = "json"; |
| 173 | + /** |
| 174 | + * form-data |
| 175 | + */ |
| 176 | + public function fileUpload(){ |
| 177 | + $files = UploadedFileBridge::getPsr7UploadedFiles(); |
| 178 | + $data = []; |
| 179 | + foreach ($files as $file) { |
| 180 | + $fileEx = array_pop( |
| 181 | + explode('.', $file->getClientFilename()) |
| 182 | + ); |
| 183 | + $newFileName = uniqid(rand()).".".$fileEx; |
| 184 | + $newFilePath = WRITEPATH.'uploads'.DIRECTORY_SEPARATOR.$newFileName; |
| 185 | + $file->moveTo($newFilePath); |
| 186 | + $data[$file->getClientFilename()] = md5_file($newFilePath); |
| 187 | + } |
| 188 | + return $this->respondCreated($data); |
| 189 | + } |
| 190 | +
|
| 191 | + /** |
| 192 | + * form-data multiple upload |
| 193 | + */ |
| 194 | + public function fileMultipleUpload(){ |
| 195 | + $files = UploadedFileBridge::getPsr7UploadedFiles()["data"]; |
| 196 | + $data = []; |
| 197 | + foreach ($files as $file) { |
| 198 | + $fileEx = array_pop( |
| 199 | + explode('.', $file->getClientFilename()) |
| 200 | + ); |
| 201 | + $newFileName = uniqid(rand()).".".$fileEx; |
| 202 | + $newFilePath = WRITEPATH.'uploads'.DIRECTORY_SEPARATOR.$newFileName; |
| 203 | + $file->moveTo($newFilePath); |
| 204 | + $data[$file->getClientFilename()] = md5_file($newFilePath); |
| 205 | + } |
| 206 | + return $this->respondCreated($data); |
| 207 | + } |
| 208 | +``` |
| 209 | + |
| 210 | +### 處理錯誤拋出 |
| 211 | + |
| 212 | +如果你在 `-v -d` 開發模式中碰到了一些需要確認的變數、或物件內容,無論在程式的何處,你都可以使用全域函數 `dump()` 來將錯誤拋出到終端機上。 |
| 213 | + |
| 214 | +```php |
| 215 | + /** |
| 216 | + * Dump given value into target output. |
| 217 | + * |
| 218 | + * @param mixed $value Variable |
| 219 | + * @param string $target Possible options: OUTPUT, RETURN, ERROR_LOG, LOGGER. |
| 220 | + * @return string|null |
| 221 | + */ |
| 222 | +function dump($value,string $target = "ERROR_LOG") : ?string; |
| 223 | +``` |
| 224 | + |
| 225 | +## 可用指令 |
| 226 | + |
| 227 | +### ciroad:init |
| 228 | + |
| 229 | +初始化 Roadrunner 與其所需的檔案。 |
| 230 | + |
| 231 | +* Use |
| 232 | + ``` |
| 233 | + $ php spark ciroad:init |
| 234 | + ``` |
| 235 | + |
| 236 | +### ciroad:start |
| 237 | + |
| 238 | +啟動 RoadRunner 伺服器。 |
| 239 | + |
| 240 | +* Use |
| 241 | + ``` |
| 242 | + $ php spark ciroad:start [Options] |
| 243 | + ``` |
| 244 | + |
| 245 | +* Options: |
| 246 | + ``` |
| 247 | + -d 在除錯模式中執行,HTTP 請求詳情將會羅列在終端機。 |
| 248 | + -b 在背景中執行。 |
| 249 | + -v 輸出詳細資料。 |
| 250 | + ``` |
| 251 | + |
| 252 | +### ciroad:stop |
| 253 | + |
| 254 | +停止在背景運作的 RoadRunner 伺服器。 |
| 255 | + |
| 256 | +* Use |
| 257 | + ``` |
| 258 | + $ php spark ciroad:stop |
| 259 | + ``` |
| 260 | + |
| 261 | +### ciraod:reset |
| 262 | + |
| 263 | +強制重新載入所有 HTTP Worker。 |
| 264 | + |
| 265 | +* Use |
| 266 | + ``` |
| 267 | + $ php spark ciroad:reset |
| 268 | + ``` |
| 269 | + |
| 270 | +### ciroad:status |
| 271 | + |
| 272 | +查閱目前 Worker 運作狀態。 |
| 273 | + |
| 274 | +* Use |
| 275 | + ``` |
| 276 | + $ php spark ciroad:status [Options] |
| 277 | + ``` |
| 278 | + |
| 279 | +* Options: |
| 280 | + ``` |
| 281 | + -i 每秒持續輸出狀態。 |
| 282 | + ``` |
0 commit comments