---
# System prepended metadata

title: Laravel 製作套件
tags: [php, Laravel]

---

# Laravel 製作套件
###### tags: `Laravel`、`php`

## 環境
在 laravel 根目錄上建立 packages/venderName/packageName
> src 目錄將包含所有 PHP 代碼
```
root
├── packages
│   └── gcreate
│       └──line_notify 
│           ├── src
```

cd 進入 packages/gcreate/line_notify
下指令 composer init
    
```=json
# 輸入套件命名
Package name (<vendor>/<name>) [user/test]: gcreate/line-notify
# 輸入套件描述
Description []: use line notify plugin.
# 輸入作者訊息
Author [gcreate <service@gcreate.com.tw>, n to skip]:
# 輸入最低穩定版本，ex: stable, RC, beta, alpha, dev
Minimum Stability []: dev
# 輸入套件類型
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
# 輸入授權類型
License []: MIT

Define your dependencies.

# 是否需要定義依賴套件
Would you like to define your dependencies (require) interactively [yes]? yes
# 以 php 為例
Search for a package: php
Info from https://repo.packagist.org: #StandWithUkraine
# 輸入此依賴套件最低需求版本（或留白取最新版本）
Enter the version constraint to require (or leave blank to use the latest version): >=7.4.3
# 如需多個依賴則重複上述步驟
Search for a package:
......

# 是否需要定義 require-dev
Would you like to define your dev dependencies (require-dev) interactively [yes]? no
# 是否支援 PSR-4 自動載入（對應命名空間名稱與檔案目錄名稱）
Add PSR-4 autoload mapping? Maps namespace "Packages\Test" to the entered relative path. [src/, n to skip]:
{
    "name": "gcreate/line_notify",
    "description": "use line notify plugin",
    "type": "library",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "Gcreate\\LineNotify\\": "src/"
        }
    },
    "authors": [
        {
            "name": "gcreate",
            "email": "service@gcreate.com.tw"
        }
    ],
    "minimum-stability": "dev",
    "require": {
        "php": ">=7.4.3"
    },
    "require-dev": {
        "gcreate/line-notify": "*"
    }
}

# 是否照以上資訊生成 composer.json
Do you confirm generation [yes]? yes

# 是否要現在安裝依賴套件
Would you like to install dependencies now [yes]? no

PSR-4 autoloading configured. Use "namespace Gcreate\LineNotify;" in src/
Include the Composer autoloader with: require 'vendor/autoload.php';
```

## 建立 Provider
在 src 資料夾新增 Service Provider，可以使用 php artisan make:provider XXXServiceProvider 指令新增，並搬遷到我們預計要做的套件 src/ 底下
    
順便在***根目錄*** config/app 內，加入自己做的套件 ( Provider )
```php!
...
'providers' => [
    Gcreate\LineNotify\LineNotifyServiceProvider::class,
]
```
因為我們要直接用，直接檢查會不會跑不用另外安裝下來做
在 root composer.json，psr-4 這個是 composer 會抓取路徑名稱要下好，完成後要把這裡修改
```json!
...
    
"autoload": {
    "psr-4": {
        ...
        "Gcreate\\LineNotify\\": "packages/gcreate/line_notify/src/"
    },
    ...
},
...
```

在根目錄上執行 `composer dump-autoload` 就可以直接操作

### ServiceProvider 建立和專案 config 與 migration 複製或合併
需要把專案 users table 欄位調整和加入一個 config 檔案，這兩個檔是要使用者下指令產生
```
root
├── packages
│   └── gcreate
│       └──line_notify 
│           ├── src
│           │    ├── config
│           │    │     └── line-notify.php
│           │    ├── database  
│           │    │      └──add_line_token_column_and_line_state_column_to_users_table.php 
│           │    └── LineNotifyServiceProvider.php
│           ├── vendor 
│           └── composer.json 
```

### src/LineNotifyServiceProvider.php
```=php
<?php

namespace Gcreate\LineNotify;    // 這邊一定要寫好

use Illuminate\Support\ServiceProvider;

class LineNotifyServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        // 如果 root 有 config 設定檔就合併，沒有就產生 config 設定檔，來源在 src/config
        $this->mergeConfigFrom( __DIR__ . '/config/line-notify.php', 'line-notify');
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot(): void
    {
        // 發佈 config 設定檔
        // php artisan vendor:publish --tag=line-notify-config
        $source = realpath($raw = __DIR__ . '/config/line-notify.php') ?: $raw;
        $this->publishes([
            $source => config_path('line-notify.php'),
        ],'line-notify-config');

        // 發佈 migration
        // php artisan vendor:publish --tag=line-notify-migration
        $timestamp = date('Y_m_d_His');
        $this->publishes([
            __DIR__.'/database/migrations/add_line_token_column_and_line_state_column_to_users_table.php' => database_path('migrations/'.$timestamp.'_add_line_token_column_and_line_state_token_to_users_table.php'),
        ],'line-notify-migration');

    }
}
```

#### src/config
建立檔案 line-notify.php
在 .env 上也需要有對應的 key
```php!
<?php

return [
    'client_id' => env('LineNotifyClientID'),
    'client_secret' => env('LineNotifyClientSecret'),
    'CALLBACK_URL' => env('LineNotifyCallbackUrl'),
];
```

#### src/database/migrations
建立檔案 add_line_token_column_and_line_state_column_to_users_table.php
我們 provider 加入時間戳複製到 migration 就會和我們下 migration 是一樣的
> 這裡也是先下完 php artisan make:migration xxxxxx_tables 在搬遷到 src 底下作業
> 要注意去除時間戳
```php!
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddLineTokenColumnAndLineStateTokenToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('line_notify_access_token');
            $table->string('line_notify_state');

        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('line_notify_access_token');
            $table->dropColumn('line_notify_state');
        });
    }
}
```

## Line Notify
需要有 controller、route ( callback 用 )
資料夾格式如下
```
root
├── packages
│   └── gcreate
│       └──line_notify 
│           ├── src
│           │    ├── Controllers
│           │    │     └── LineNotifyController.php
│           │    ├── config
│           │    │     └── line-notify.php
│           │    ├── routes
│           │    │     └── web.php
│           │    ├── database  
│           │    │      └──add_line_token_column_and_line_state_column_to_users_table.php 
│           │    └── LineNotifyServiceProvider.php
│           ├── vendor 
│           └── composer.json 
```
### src/Controllers/LineNotifyController.php
```php!
<?php

namespace Gcreate\LineNotify\Controllers;    // 這裡很重要

use Illuminate\Http\Request;
// 需要繼承原來 laravel 的方法
use App\Http\Controllers\Controller;

class LineNotifyController extends Controller
{
    // ... 需要的方法
}
```

### src/routes/web.php
```php!
<?php

use Gcreate\LineNotify\Controllers\LineNotifyController;
use Illuminate\Support\Facades\Route;

// if env isn't setting callback URL, default is "line/callbackURL"
Route::any( config('line-notify.CALLBACK_URL', 'line/callbackURL' ), [LineNotifyController::class, 'getAuthLineCallback'] );
```


## 上傳套件

## 建立Git Hub 專案
![](https://hackmd.io/_uploads/r1vK-IePn.png)
> 注意 license 要 MIT
> Add a README file 要勾

:::info
上傳的時候不要帶 vender
:::

### 以 Packagist 為例 (public)
到 Packagist 使用 GitHub 登入帳號，點擊 Submit，直接輸入 repository 的網址，然後 Submit Package 就完成了。


### 連動 github
Profile 有自己的 API TOKE
進入自己發布的 github 專案 > Settings > Webhooks > Edit ( 如果沒有 Add webhook ) > Secret > 填入自己的 API TOKE > 存檔




