2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel11】LINEでの勤怠管理を実装する

Last updated at Posted at 2025-01-01

はじめに

社内のプロジェクトで、実施未定のものがあり、その下調べをしようとしたらドツボにはまったので、これで命を削る人がひとりでも減るように、ここに記録しようと思いました。

なんせ、情報が少ない。

Laravelが11になってガラッと変わってしまって、以前参考にしていた先人の記事では追い付かなくなってしまいました。そこで、調べまくった結果をここに残しておこうと思います。
初めての投稿なので、変なところがあったらご指摘ください。

環境は、2025.1.5現在
Windows 11
PHP 8.3
Laravel 11.5.0
docker desktop 4.37.1
Visual Studio Code 1.96.2
また、Laravel公式だと「php~」ではなく「sail~」で書かれているので、この記事ではsailで押し通します。

LINE側の準備

すみません。
あまりに項目が多いので、テキストだけで説明させてください。
不親切ですみません。

  • まず、LINE Developersで、LINE Buisiness IDでアカウントを作成、ログインする。
  • プロバイダーを作成。
  • 新規チャネル作成で、Messaging APIを選択する。
  • LINE公式アカウントを作成する。
  • LINE Official Accountに飛ぶ。
  • ここで、LINE公式アカウントの作成をする。項目を埋めていく。
  • 認証リクエストするか、後で認証するか、選べる(はず)
  • 同意画面が2つ出るので、同意する。 この時点で、LINE Offical Account Managerにいるはず。
  • チャットタブを選択すると、「チャットがオフに設定されています」と出るので、「応答設定に移動」を選択する。
  • 左の設定のうち、Messaging APIを選択する。
  • Messaging APIを利用するボタンを押す。
  • プロバイダーを作成、または選択する。同意する。
  • プライバシーポリシー、利用規約は任意。
  • Channel ID、Channel secretが表示される。Channel secretは、後で使用するので控えておく。あとで.envに書く。
  • Webhook URLを入力する。
  • ここは、httpsでなければならない。例えば、https://xxxxx.xxx/webhook とか、実URLにwebhookなどをくっつけて入力しておく。(後で、rouitingで使う)
  • ローカル環境を公開するには、ngrokを使うといい。(一位番下に、おまけとして書いておきました)
  • 左の設定の応答設定を選択して、応答機能で、WebhookをONにする。 (Messaging APIで設定をした後でないと、ここはONにできない)
  • 「応答メッセージ」はOFFにする。(ここはお好みで)
  • LINE Developersに移動して、作成したチャネルを選択する。
  • Messaging API設定タブを選択する。
  • ここで、ボットのベーシックIDと、QRコードを得られる。
  • 一番下の、チャネルアクセストークン(長期)を発行する。 これも控えておく。あとで.envに書く。

Laravelでの実装の前に

aliasの設定

~/.bash_aliasesファイルを作り、下記の行を入れておくといいです。(もちろん、.bashrcでもいいです)

alias sail='./vendor/bin/sail'

編集したら、.bashrcの実行か、めんどくさかったら新しいウインドウを開くのがいいです。

php-xml、php-domのインストール

どうも、php関連で標準ではインストールされないものがあるようです。
念のためインストールされているか確認してみます。

php -m | grep xml

これでxmlの項目が表示されていれば有効なようです。
logを見ると、~.xml、~.domがない、と言われることがあります。
この場合、以下のコマンドを実行してください。

sudo apt update
sudo apt install php-xml
sudo apt install php-dom

VSCodeの用意

以下の拡張機能をインストールしておきます。
・Japanese Language Pack
・Laravel Snippets
(それ以外にも、お好みで。良いものがあったら教えてください。)
以下、ファイル・フォルダの新規作成・編集などは、VSCode上で行います。
(というか、今後使えって言われちゃった笑)

Laravelプロジェクトの作成

プロジェクトを作りたいディレクトリで実行します。

curl -s https://laravel.build/Attendance | bash
cd Attendance
sail up -d
code .

VSCodeが起動するので、まず「.env」ファイルを編集します。

APP_TIMEZONE=Asia/Tokyo
...
APP_LOCALE=jp
APP_FALLBACK_LOCALE=jp
APP_FAKER_LOCALE=ja_JP

以下を追加します。

LINE_CHANNEL_SECRET=xxxxxxxxxxxxxxx(上記、Channel secret)
LINE_CHANNEL_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxx(上記チャネルアクセストークン(長期))

とりあえず、ここだけ。
MySQLでのユーザー名は、sailになります。

tailwindcssのインストール

Laravelでは、tailwindcssを使用しているので、下記を実行してインストールしておきます。

sudo npm install -D tailwindcss
sudo npx tailwindcss init

npmがないと言われたら、先にインストールします。

sudo apt update
sudo apt install npm

LINE Messaging APIを利用するために、下記を実行します。

composer require linecorp/line-bot-sdk:^7.6

もしcomposerがないなんて言われたら、先に

sudo apt install composer

を実行します。
ここでなぜline-bot-sdkのバージョンを指定しているかというと、最新版(2025.1.5現在)は10っぽいのですが、それでは使い方がわからず、あえてバージョンを落として使ってます。(バージョン8とか9でもダメでした…)

Laravelでの実装(webhook部分の実装)

  1. ルート設定(1)
  2. routes/web.phpに以下を追加します。
    use App\Http\Controllers\LineWebhookController;
    
    Route::post('/webhook', [LineWebhookController::class, 'handle']);
    
  3. コントローラ作成(1)
  4. sail artisan make:controller LineWebhookController
    

    LineWebhookControllerのコードを以下のように変更します。

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use LINE\LINEBot;
    use LINE\LINEBot\HTTPClient\CurlHTTPClient;
    use LINE\LINEBot\MessageBuilder\TextMessageBuilder;
    use App\Models\Attendance;
    
    class LineWebhookController extends Controller
    {
        private $bot;
    
        public function __construct()
        {
            $httpClient = new CurlHTTPClient(env('LINE_CHANNEL_ACCESS_TOKEN'));
            $this->bot = new LINEBot($httpClient, ['channelSecret' => env('LINE_CHANNEL_SECRET')]);
        }
    
        public function handle(Request $request)
        {
            $events = $request->input('events', []);
    
            foreach ($events as $event) {
                if ($event['type'] === 'message' && $event['message']['type'] === 'text') {
                    $replyToken = $event['replyToken'];
                    $userId = $event['source']['userId'];
                    $messageText = $event['message']['text'];
    
                    $this->processAttendance($userId, $messageText, $replyToken);
                }
            }
    
            return response()->json(['status' => 'ok'], 200);
        }
    
        private function processAttendance($userId, $messageText, $replyToken)
        {
            if (strtolower($messageText) === '出勤') {
                Attendance::create([
                    'user_id' => $userId,
                    'type' => 'clock_in',
                    'timestamp' => now(),
                ]);
                $message = new TextMessageBuilder('出勤を記録しました。');
            } elseif (strtolower($messageText) === '退勤') {
                Attendance::create([
                    'user_id' => $userId,
                    'type' => 'clock_out',
                    'timestamp' => now(),
                ]);
                $message = new TextMessageBuilder('退勤を記録しました。');
            } else {
                $message = new TextMessageBuilder('「出勤」または「退勤」と入力してください。');
            }
    
            $this->bot->replyMessage($replyToken, $message);
        }
    }
    
  5. モデルとマイグレーション作成
  6. sail artisan make:model Attendance -m
    

    マイグレーションファイル
    database/migrations/xxxx_xx_xx_xxxxxx_create_attendances_table.phpを編集します。
    (upのほうだけ)

    public function up()
    {
        Schema::create('attendances', function (Blueprint $table) {
            $table->id();
            $table->string('user_id');
            $table->enum('type', ['clock_in', 'clock_out']);
            $table->timestamp('timestamp');
            $table->timestamps();
        });
    }
    

    このあたりで、セッションテーブルも作っておきます。

    sail artisan make:session-table
    

    マイグレーションを実行してみます。

    sail artisan migrate
    

    ただ単に「すでにある」といわれて終わるならいいのですが、「テーブルがすでにある」といわれてエラーするときがあります。(実際は英語ですが)
    その時は、

    sail mysql
    mysql>show tables;
    

    して、エラーで「すでにある」といわれているテーブルを、例えば、

    mysql>drop table attendances;
    

    とかして削除します。
    mysqlから抜けるには、

    mysql>exit;
    

    などとしてください。
    まだmysqlサービスが起動していないとかの場合は、この手は使えないので、思い切って、

    sail down(または、sail stop)して、
    docker desktopでコンテナを削除、
    sail up -d
    

    という手もあります。

  7. モデルの編集
  8. app/Models/Attendance.phpを以下のように編集します。
    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    
    class Attendance extends Model
    {
        use HasFactory;
    
        protected $fillable = ['user_id', 'type', 'timestamp'];
    }
    
  9. CSRF除外設定
  10. bootstrap/app.phpを、下記のように変更します。
    use Illuminate\Foundation\Application;
    use Illuminate\Foundation\Configuration\Exceptions;
    use Illuminate\Foundation\Configuration\Middleware;
     
    return Application::configure(basePath: dirname(__DIR__))
        ->withRouting(
            web: __DIR__.'/../routes/web.php',
            // api: __DIR__.'/../routes/api.php',
            commands: __DIR__.'/../routes/console.php',
            // channels: __DIR__.'/../routes/channels.php',
            health: '/up',
        )
        ->withMiddleware(function (Middleware $middleware) {
            // CSRF除外
            $middleware->validateCsrfTokens(except: [
                '/webhook',
            ]);
        })
        ->withExceptions(function (Exceptions $exceptions) {
            //
        })->create();
    

    この変更をしたら、configをクリアしておきます。(この段階では、まだ必要ないかもしれませんが、一応)

    sail artisan config:clear
    

    Laravelでの実装(勤怠データ表示部分の実装)

  11. ルート設定(2)
  12. routes/web.phpに以下を追加します。
    use App\Http\Controllers\AttendanceController;
    
    Route::get('/attendance', [AttendanceController::class, 'index']);
    
  13. コントローラ作成(2)
  14. 下記を実行
    sail artisan make:controller AttendanceController
    

    app/Http/Controller/AttendanceControllerを以下のように編集します。

    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use App\Models\Attendance;
    
    class AttendanceController extends Controller
    {
        public function index()
        {
            $attendances = Attendance::all();
    
            return view('attendance.index', compact('attendances'));
        }
    }
    
  15. ビューの作成
  16. resources/views/attendance/index.blade.phpを作成します。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>勤怠履歴</title>
    </head>
    <body>
        <h1>勤怠履歴</h1>
        <table border="1">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>ユーザーID</th>
                    <th>タイプ</th>
                    <th>タイムスタンプ</th>
                </tr>
            </thead>
            <tbody>
                @foreach ($attendances as $attendance)
                <tr>
                    <td>{{ $attendance->id }}</td>
                    <td>{{ $attendance->user_id }}</td>
                    <td>{{ $attendance->type }}</td>
                    <td>{{ $attendance->timestamp }}</td>
                </tr>
                @endforeach
            </tbody>
        </table>
    </body>
    </html>
    
  17. 動作確認
  18. 友達登録をして、「出勤」とLINEすると「出勤を記録しました。」と答え、「退勤」とLINEすると「退勤を記録しました。」と答え、どちらでもなければ『「出勤」または「退勤」と入力してください。』と返事をします。 また、ブラウザのほうで、勤怠記録が表示されることを確認します。

ローカル環境を外部から参照するためにngrokをお使いの方は、

ngrok http 80

(ポート番号はお好みで)して出てくるURLをコピーし、LINE Developersで開発中のチャネルを選択し Messaging API タブを選ぶと一番下に「Webhook URL」を指定するところがあるので、ここを編集してURLをペーストして、後ろに「/webhook」をつけてから実行します。
おそらく、ngrokを起動するたびにURLが変わるので、ご注意ください。
友達登録するには、同ページにあるQRコードを使うといいです。

固定IPの場合や、デプロイした後の検証はしていないので、そのあたりの情報もあったら追記したいです。

以上です。

(おまけ)
ngrokのインストール。
https://download.ngrok.com
で log in します。
ここから、「linux用の」ngrokをインストールします。
左の「Serup and installastion」が選ばれていると思うので、右側のコマンドをコピペして実行します。
次に、その下にある

ngrok config add-authtoken xxxxxxxxxx

をコピペして実行します。

【更新履歴】
2025.01.10 エラーする部分などの検証・追記。ngrokのインストールも追記。
2025.01.09 一部文章の追記。
2025.01.05 バグ修正(CSRF除外設定のところ。ごめんなさい)ngrok起動とwebhookのURLについての記述追加。微調整。
2025.01.03 微調整
2025.01.01 初版

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?