前言
一直都用別人的 package,也該是時候自己寫了吧!
平常的開發總是離不開 Composer ,雖然 Laravel 的套件豐富,但還是會有需要自己開發的時候
以下會整理出如何建立出一個 Laravel package,從本機開發、自動化測試到發布
需求分析
以一個簡單的 OTP 功能為例,預期會有以下功能
- 產生 OTP 並存到 Database
- 檢查 OTP 是否有效
開發 Package
初始化套件
以 otp 作為範例
1 2 3
| mkdir otp cd otp composer init
|
接下來會有多個問題建立套件的基本資訊,可視情況填寫
完成後會產生初始化的 composer.json 檔案
另外是要建立 Laravel 的套件,為了方便開發會需要安裝 testbench
1
| composer require --dev "orchestra/testbench"
|
- 專案架構
- src
- 通常會將 source code 放在這裡,記得要符合 PSR-4
- tests
功能實作
建立 OtpService
大致內容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<?php
namespace Hellojie\LaravelOtp;
class OtpService {
public function generate(): string { return $token; }
public function validate(): bool { return true; }
}
|
測試
因為此套件會需要使用 Laravel Eloquent 進行測試,需要透過 TestBench
協助
可以建立對應的 migration file 還有 factory
TestCase 也需要做點調整
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php
namespace Hellojie\LaravelOtp\Tests;
use Illuminate\Database\Eloquent\Factories\Factory; use Orchestra\Testbench\TestCase as BaseTestCase;
class TestCase extends BaseTestCase { public function setUp(): void { parent::setUp();
$this->loadMigrationsFrom('./src/database/migrations');
Factory::guessFactoryNamesUsing( fn (string $modelName) => 'Hellojie\\LaravelOtp\\Database\\Factories\\'.class_basename($modelName).'Factory' ); } }
|
設定好後就可以使用 phpunit
了
整合 Laravel Service Provider
為了讓 Laravel 可以方便使用套件,需要建立一個 Service Provider
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <?php
namespace Hellojie\LaravelOtp;
use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider;
class LaravelOtpServiceProvider extends ServiceProvider implements DeferrableProvider {
public function boot() { $this->publishes([$this->migrationPath() => database_path('migrations')]); }
public function register() { $this->app->singleton(OtpService::class, function ($app) { return new OtpService(); }); }
public function provides() { return [OtpService::class]; }
private function migrationPath() { return __DIR__ . '/database/migrations'; } }
|
Laravel Auto Discovery
為了讓 Laravel 可以自動發現這個套件,需要在 composer.json
中進行設定,可在適當的地方加上以下內容
1 2 3 4 5 6 7 8 9
| ... "extra": { "laravel": { "providers": [ "Hellojie\\LaravelOtp\\LaravelOtpServiceProvider" ] } }
|
本機測試
先建立新的 Laravel Project 進行測試,確認可不可以使用套件
1 2 3 4 5 6
| cd ../ composer create-project laravel/laravel test-laravel-otp cd test-laravel-otp
composer config repositories.laravel-otp path ../laravel-otp composer require hellojie/laravel-otp:dev-main
|
安裝後可以在專案內使用指令,並根據互動提示輸入對應的數字,匯入套件內的檔案
1
| php artisan vendor:publish
|
自動化
Github Action
利用 Github Action 自動化發起任務,可以進行自動化測試或者部署,這裡先使用自動化測試為範例,其他可視實際情況調整
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| name: PHP Composer
on: push: branches: [ "main" ] pull_request: branches: [ "main" ]
permissions: contents: read
jobs: build:
runs-on: ubuntu-latest
steps: - uses: actions/checkout@v3
- name: Validate composer.json and composer.lock run: composer validate --strict
- name: Cache Composer packages id: composer-cache uses: actions/cache@v3 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | ${{ runner.os }}-php-
- name: Install dependencies run: composer install --prefer-dist --no-progress
- name: Run test suite run: composer run-script test
|
發佈
packagist
到 https://packagist.org/ 註冊帳號
登入後,點選右上方的 submit
開始發布套件
填入套件的 GitHub Repository url
送出後可能會看到一個提示
1
| This package is not auto-updated. Please set up the GitHub Hook for Packagist so that it gets updated whenever you push!
|
為了讓 packagist 可以自動更新,需要到 GitHub 設定 webhook,讓 packagist 在每次更新 Repository 時都可以抓取最新資訊
步驟:
- 到 packagist 取的 api token
- 到 github repository 新增 webhook,讓套件有更新時可以自動通知 packagist 抓取
主要填寫內容如下:
1 2 3
| Payload URL: https://packagist.org/api/github?username=packagist的使用者帳號 Content type: application/json Secret: packagist 的 token
|
可參考 https://packagist.org/about
這時就可以透過 composer 安裝套件了
1
| composer require hellojie/laravel-otp:dev-main
|
注意:
如果還沒有發布正式版記得要加上:dev-main
正式版本號可參考相關規範 https://semver.org/lang/zh-TW/
1 2 3 4 5 6
| 版本格式:主版號.次版號.修訂號,版號遞增規則如下:
主版號:當你做了不相容的 API 修改, 次版號:當你做了向下相容的功能性新增, 修訂號:當你做了向下相容的問題修正。 先行版號及版本編譯資訊可以加到「主版號.次版號.修訂號」的後面,作為延伸。
|
Reference
以上程式碼可以參考
https://github.com/Rjiegit/laravel-otp