前言

最近突然心血來潮看到這篇 Laravel new 的 post: https://laravel-news.com/building-your-own-laravel-packages

於是起心動念開始寫一個 package來玩一玩。 詳細程式碼在這裡:https://github.com/r567tw/laravel-package-practice

首先,要有composer

既然要寫一個自己的客製package,當然要先有composer.json呀 於是讓我們先composer init起來!或者你要手動建立composer.json也是可以

總之,你composer.json 裡面的內容應該要包含以下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
    "name": "{你的名稱}/{你的套件名稱}",
    "type": "library",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "{你的名稱}\\{你的套件名稱}": "src/"
        }
    },
    "require": {
        "php": "^8.1",
        "illuminate/support": "^9.23"
    },
    "extra": {
        "laravel": {
            "providers": [
                "{你的名稱}\\{你的套件名稱}\\Providers\\PackageServiceProvider"
            ]
        }
    }
}
  • extra 是給laravel 看的,laravel在某個版本之後啟用autoload service provider,「粉方便」
  • 主要要require illuminate/support這個套件
  • 通常我們會使用src這個資料夾,但如果你想特立獨行也是可以拉
  • 要寫一個 serviceprovider 檔,如果之後有機會來記錄筆記一下Laravel這個service provider 這個東西,一定可以學到很多!

寫一個service provider

我這個套件的目標很簡單,就是弄出一個artisan 的指令來helloworld一下就好,所以這邊我在src/Providers裡面建立PackageServiceProvider.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
declare(strict_types=1);
 
namespace Fang\LaravelPackagePractice\Providers;
 
use Illuminate\Support\ServiceProvider;
use Fang\LaravelPackagePractice\Console\Commands\FirstPackageCommand;
 
final class PackageServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->commands(
                commands: [
                    FirstPackageCommand::class,
                ],
            );
        }
    }
}

如果你想弄別的其實也可以參考他自家文件,很清楚:https://laravel.com/docs/9.x/packages

準備FirstPackageCommand

如果你是想弄別的,這一步可以略過弄你的版本即可,我以我自己練習用的為例 firstPackageCommand 裡面其實就這樣

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
namespace Fang\LaravelPackagePractice\Console\Commands;
 
use Illuminate\Console\Command;
 
final class FirstPackageCommand extends Command
{
    protected $signature = "practice";
 
    protected $description = "just say helloworld";

    public function handle()
    {
        $this->info("it's practice package");
    }
}

於是你的套件完成了!

單元測試

我個人比較雞婆一點,想要弄一個簡單的單元測試。 所以使用到一個套件orchestra/testbench 於是我的composer.json 就增加以下這段

1
2
3
4
    "require-dev": {
        "orchestra/testbench": "^7.6",
        "phpunit/phpunit": "^9.5"
    }

至於我的案例呢?我只是簡單寫一下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

namespace Fang\LaravelPackagePractice\Tests\Unit;

use \Orchestra\Testbench\TestCase;
use \Fang\LaravelPackagePractice\Providers\PackageServiceProvider;

class FirstPackageCommandTest extends TestCase
{
    protected function getPackageProviders($app): array
    {
        return [
            PackageServiceProvider::class,
        ];
    }

    /** @test */
    function the_command_will_info_message()
    {
        $command = $this->artisan('practice');
        $command->expectsOutput("it's practice package");
    }
}
  • 這裡很重要,請記得要寫getPackageProviders這個function 注入你的service provider! 我這裡卡關卡很久…

於是下vendor/bin/phpunit就可以試看看有沒有過啊!

終端測試一下

如果你想要公開給別人用,可以弄到packagist,但我!不!想。

所以你可以更簡單一點在你新的laravel專案底下composer.json加上這一段

1
2
3
4
5
"repositories": [
        {
            "type": "vcs",
        }
    ]

然後呢? 執行composer require {你的名稱}/{你的套件名稱} 就好

以我這個案例為例:執行php artisan practice 就會看到我的成果:it's practice package

小君曰:寫 pakcage 給別人玩吧!