diff --git a/README.md b/README.md index a8848a0..e65de3b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,16 @@ # CodeIgniter4-Burner +
+ + + +
+ Burner is an out-of-the-box library for CodeIgniter4 that supports [RoadRunner](https://roadrunner.dev/), [Workerman](https://github.com/walkor/workerman), and [OpenSwoole](https://openswoole.com/) high-performance web servers. All you need to do is open a few php extensions to dramatically speed up your CodeIgniter4 applications, allowing them to handle higher loads and more connections at the same time. -[正體中文說明書](README_zh-TW.md) +[English Document](https://burner.monken.tw/en/introduction) + +[正體中文簡介](README_zh-TW.md) ## Install @@ -52,144 +60,3 @@ Run the command in the root directory of your project: ``` php spark burner:start ``` -## Development Suggestions - -### Using Codeigniter4 Request and Response object - -Codeigniter4 does not implement the complete [HTTP message interface](https://www.php-fig.org/psr/psr-7/), hence this library focuses on the synchronize of `PSR-7 interface` and `Codeigniter4 HTTP interface`. - -Base on the reasons above, You should use `$this->request`, provided by Codeigniter4, or the global function `/Config/Services::('request')` to fetch the correct request object; Use `$this->response` or `/Config/Services::('response')` to fetch the correct response object. - -Please be noticed, while constructing response for the users during developing, you should prevent using PHP built-in methods to conduct `header` or `set-cookies` settings. Using the `setHeader()` and `setCookie()`, provided by the [Codeigniter4 Response Object](https://codeigniter.com/user_guide/outgoing/response.html), to conduct setting. - -### Use return to stop controller logic - -Inside the Controller, try using return to stop the controller logic. No matter the response of view or API, reduce the `echo` output usage can avoid lets of errors, just like this: - -```php -namespace App\Controllers; - -use CodeIgniter\API\ResponseTrait; - -class Home extends BaseController -{ - use ResponseTrait; - - public function index() - { - // Don't use: - // echo view('welcome_message'); - return view('welcome_message'); - } - - /** - * send header - */ - public function sendHeader() - { - $this->response->setHeader("X-Set-Auth-Token", uniqid()); - return $this->respond(["status" => true]); - } -} -``` - -### Use the built-in Session library - -We only focus on supporting the Codeigniter4 built-in [Session library](https://codeigniter.com/user_guide/libraries/sessions.html), and do not guarantee if using `session_start()` and `$_SEEEION` can work as normal. So, you should avoid using the PHP built-in Session method, change to the Codeigniter4 framework built-in library. - -### External Connections - -We only focus on supporting the Codeigniter4 built-in [Database Library](https://codeigniter.com/user_guide/database/index.html) and [Cache Library](https://codeigniter.com/user_guide/libraries/caching.html), hence we do not guarantee if using the PHP -built-in method should work as normal. Therefore, you should avoid using the PHP built-in method but -pick the Codeigniter4 framework built-in library. - -By default, Worker's DB and Cache should be persistent and try to reconnect once the connection fails. -Every request into the Worker is using the same connection instance. If you don't want this default setting but want every request to use the reconnected connection instance. -You can adjust these settings in `Config/Burner.php`. - -```php -public $dbAutoClose = true; -public $cacheAutoClose = true; -``` - -### CodeIgniter Services - -CodeIgniter4 allows you to write any class to be managed as a Services Class, and your class will remain as a single instance in the Service Class. - -After the HTTP response, Burner automatically initializes all instances in the service in case the already used singleton affects the next request. If your service does not need to be initialized, then declaring the service name in the `skipInitServices` string array in `Config/Burner.php` will make the service persistent and reusable in the Worker. - -```php -public $skipInitServices = [ - 'your', - 'service', - 'name' -]; -``` - -### Developing and debugging in a environment with only one Worker - -Since the RoadRunner, OpenSwoole and Workerman has fundamentally difference with other server software(i.e. Nginx, Apache), every Codeigniter4 will persist inside RAMs as the form of Worker, HTTP requests will reuse these Workers to process. Hence, we have better develop and test stability under the circumstance with only one Worker to prove it can also work properly under serveral Workers in the formal environment. - -# Global Methods - -We offer some Global methods to help you develop your projects more smoothly. - -### Dealing with the file uploading - -Since the RoadRunner and Workerman Worker can not transfer the correct `$_FILES` context, the Codeigniter4 file upload class will not be able to work properly. To solve this, we offered a file upload class corresponding the PSR-7 standard for you to deal with file uploading correctly within RoadRunner. Even if you switched your project to another server environment(i.e. spark serve, Apache, Nginx), this class can still work properly, and doesn't need any code modification. - -You can fetch the uploaded files by means of `SDPMlab\Ci4Roadrunner\UploadedFileBridge::getPsr7UploadedFiles()` in the controller (or any other places). This method will return an array, consist of Uploaded File objects. The available methods of this object is identical as the regulation of [PSR-7 Uploaded File Interface](https://www.php-fig.org/psr/psr-7/#36-psrhttpmessageuploadedfileinterface). - -```php -namespace App\Controllers; - -use CodeIgniter\API\ResponseTrait; -use SDPMlab\Ci4Roadrunner\UploadedFileBridge; - -class FileUploadTest extends BaseController -{ - use ResponseTrait; - - protected $format = "json"; - - /** - * form-data - */ - public function fileUpload() - { - $files = UploadedFileBridge::getPsr7UploadedFiles(); - $data = []; - foreach ($files as $file) { - $fileNameArr = explode('.', $file->getClientFilename()); - $fileEx = array_pop($fileNameArr); - $newFileName = uniqid(rand()) . "." . $fileEx; - $newFilePath = WRITEPATH . 'uploads' . DIRECTORY_SEPARATOR . $newFileName; - $file->moveTo($newFilePath); - $data[$file->getClientFilename()] = md5_file($newFilePath); - } - return $this->respondCreated($data); - } - - /** - * form-data multiple upload - */ - public function fileMultipleUpload() - { - $files = UploadedFileBridge::getPsr7UploadedFiles()["data"]; - $data = []; - foreach ($files as $file) { - $fileNameArr = explode('.', $file->getClientFilename()); - $fileEx = array_pop($fileNameArr); - $newFileName = uniqid(rand()) . "." . $fileEx; - $newFilePath = WRITEPATH . 'uploads' . DIRECTORY_SEPARATOR . $newFileName; - $file->moveTo($newFilePath); - $data[$file->getClientFilename()] = md5_file($newFilePath); - } - return $this->respondCreated($data); - } -} -``` - -### Dealing with thrown errors - -If you encountered some variables or object content that needed to be confirmed in `-d` development mode, you can use the global function `dump()` to throw errors onto the terminal no matter where the program is. diff --git a/README_zh-TW.md b/README_zh-TW.md index 21c8326..40bfcb7 100644 --- a/README_zh-TW.md +++ b/README_zh-TW.md @@ -1,7 +1,15 @@ # Codeigniter4-Burner ++ + + +
+ Burner 是一款專屬於 CodeIgniter4 的開箱即用的程式庫,它支援 [RoadRunner](https://roadrunner.dev/) , [Workerman](https://github.com/walkor/workerman) 與 , [OpenSwoole](https://openswoole.com/) 高效能網頁伺服器。你只需要開啟一些 php 擴充套件,即可大幅度地加速你的 CodeIgniter4 應用程式,使其能承受更高的負載並同時處理更多的連線。 +[正體中文文件](https://burner.monken.tw/zh_TW/introduction) + ## 安裝 ### 需求 @@ -51,141 +59,3 @@ php spark burner:init [RoadRunner, Workerman, OpenSwoole] ``` php spark burner:start ``` -## 開發建議 - -### 使用 Codeigniter4 Request 與 Response 物件 - -Codeigniter4 並沒有實作完整的 [HTTP message 介面](https://www.php-fig.org/psr/psr-7/),所以這個程式庫著重於 `PSR-7 介面` 與 `Codeigniter4 HTTP 介面` 的同步。 - -基於上述原因,在開發上,你應該使用 Codeigniter4 所提供的 `$this->request` 或是使用全域函數 `\Config\Services::('request')` 取得正確的 request 物件;使用 `$this->response` 或是 `\Config\Services::('response')` 取得正確的 response 物件。 - -請注意,在建構給予使用者的響應時,不論是 `header` 或 `set-cookies` 應該避免使用 PHP 內建的方法進行設定。而是使用 [Codeigniter4 響應物件](https://codeigniter.tw/user_guide/outgoing/response.html) 提供的 `setHeader()` 與 `setCookie()` 進行設定。 - -### 以 return 結束控制器邏輯 - -在 Controller 中,盡量使用 return 結束程式邏輯,不論是視圖的響應或是 API 響應,減少使用 `echo` 輸出內容可以避免很多錯誤,就像這個樣子。 - -```php -namespace App\Controllers; - -use CodeIgniter\API\ResponseTrait; - -class Home extends BaseController -{ - use ResponseTrait; - - public function index() - { - // Don't use: - // echo view('welcome_message'); - return view('welcome_message'); - } - - /** - * send header - */ - public function sendHeader() - { - $this->response->setHeader("X-Set-Auth-Token", uniqid()); - return $this->respond(["status" => true]); - } -} -``` - -### 使用內建 Session 程式庫 - -我們只針對 Codeigniter4 內建 [Session 程式庫](https://codeigniter.tw/user_guide/libraries/sessions.html) 進行支援,並不保證使用 `session_start()` 與 `$_SESSION` 是否能照常運作。所以,你應該避免使用 PHP 內建的 Session 方法,而是以 Codeigniter4 框架內建的程式庫為主。 - - -### 外部連線 - -我們只針對 Codeigniter4 內建的 [Database 程式庫](https://codeigniter.tw/user_guide/database/index.html) 與 [快取程式庫](https://codeigniter.tw/user_guide/libraries/caching.html) 進行支援,並不保證 PHP 內建的方法是否能照常運作。所以,你應該避免使用內建的 PHP 方法,而是以 Codeigniter4 框架內建的程式庫為主。 - -預設的情況下,在 Worker 中的連線是持久的,並會在連線失效時自動重新連線。所有進入 Worker 的 Request 都使用同一個連線實體。如果你不想要這個預設設定,希望每個進入 Worker 的 Request 都使用重新連線的 DB 或 Cache 連線實體。你調整 `Config/Burner.php` 中的下列設定: - -```php -public $dbAutoClose = true; -public $cacheAutoClose = true; -``` - -### CodeIgniter Services - -CodeIgniter4 允許你使用 Services 來管理你所撰寫的類別,你的類別將以單例的方式留存在 Services 類別中。 - -在 HTTP 響應後,Burner 會自動初始化 Services 類別中的所有實體,防止已經使用過的單例實體影響到下一個請求。如果你所撰寫的 Service 不需要被初始化,那麼請在 `Config/Burner.php` 中的 `skipInitServices` 字串陣列宣告這些 Service 的名字。這將使你所宣告的 Service 在 Worker 中持久化,並被所有請求重複使用。 - -```php -public $skipInitServices = [ - 'your', - 'service', - 'name' -]; -``` - -### 在只有一個 Worker 的環境中開發與除錯 - -因為 RoadRunner、OpenSwoole 與 Workerman 與其他伺服器軟體(Nginx、Apache)有著根本上的不同,每個 Codeigniter4 將會以 Worker 的形式持久化於記憶體中,HTTP 的請求會重複利用到這些 Worker 進行處裡。所以,我們最好在只有單個 Worker 的情況下開發軟體並測試是否穩定,以證明在多個 Woker 的實際環境中能正常運作。 - -## 全域方法 - -我們提供了一些全域方法,幫助你更加順利地開發你的專案。 - -### 處裡檔案上傳 - -因為 RoadRunner 與 Workerman Worker 無法傳遞正確的 `$_FILES` 內容,所以 Codeingiter4 的 [檔案上傳類別](https://codeigniter.tw/user_guide/libraries/uploaded_files.html) 將無法正確運作。對此,我們提供了符合 PSR-7 規範的檔案上傳類別,讓你可以正確地在 RoadRunner 中處理檔案上傳。就算你將專案切換到了其他伺服器環境(spark serve、Apache、Nginx)運作,這個類別依舊可以正常使用,並且不需要修改任何程式碼。 - -你可以在控制器(或任何地方),以 `SDPMlab\Ci4Roadrunner\UploadedFileBridge::getPsr7UploadedFiles()` 取得使用者上傳的檔案。這個方法將回傳以 Uploaded File 物件組成的陣列。此物件可用的方法與 [PSR-7 Uploaded File Interface](https://www.php-fig.org/psr/psr-7/#36-psrhttpmessageuploadedfileinterface) 中規範的一樣。 - -```php -namespace App\Controllers; - -use CodeIgniter\API\ResponseTrait; -use SDPMlab\Ci4Roadrunner\UploadedFileBridge; - -class FileUploadTest extends BaseController -{ - use ResponseTrait; - - protected $format = "json"; - - /** - * form-data - */ - public function fileUpload() - { - $files = UploadedFileBridge::getPsr7UploadedFiles(); - $data = []; - foreach ($files as $file) { - $fileNameArr = explode('.', $file->getClientFilename()); - $fileEx = array_pop($fileNameArr); - $newFileName = uniqid(rand()) . "." . $fileEx; - $newFilePath = WRITEPATH . 'uploads' . DIRECTORY_SEPARATOR . $newFileName; - $file->moveTo($newFilePath); - $data[$file->getClientFilename()] = md5_file($newFilePath); - } - return $this->respondCreated($data); - } - - /** - * form-data multiple upload - */ - public function fileMultipleUpload() - { - $files = UploadedFileBridge::getPsr7UploadedFiles()["data"]; - $data = []; - foreach ($files as $file) { - $fileNameArr = explode('.', $file->getClientFilename()); - $fileEx = array_pop($fileNameArr); - $newFileName = uniqid(rand()) . "." . $fileEx; - $newFilePath = WRITEPATH . 'uploads' . DIRECTORY_SEPARATOR . $newFileName; - $file->moveTo($newFilePath); - $data[$file->getClientFilename()] = md5_file($newFilePath); - } - return $this->respondCreated($data); - } -} -``` - -### 處理錯誤拋出 - -如果你在開發環境中碰到了一些需要確認的變數、或物件內容,無論在程式的何處,你都可以使用全域函數 `dump()` 來將錯誤拋出到終端機上。 diff --git a/src/Bridge/ResponseBridge.php b/src/Bridge/ResponseBridge.php index fb57860..f77dd5f 100644 --- a/src/Bridge/ResponseBridge.php +++ b/src/Bridge/ResponseBridge.php @@ -131,6 +131,8 @@ private function createBody(\CodeIgniter\HTTP\Response $ci4Response): StreamInte $html = $ci4Response->getBody(); if ($html instanceof StreamInterface) { return $html; + } else if(is_null($html)) { + $html = ''; } $body = new Stream('php://temp', 'wb+'); $body->write($html);