LoginSignup
10
9

More than 3 years have passed since last update.

Dockerで構築したLaravelにgRPCを導入してfirestoreにデータを書き込む方法

Posted at

LaravelをAPIサーバーとして使い、Laravelからwebsocketなどではなく、firestoreでチャットやプッシュ通知などリアルタイム通信させたいときがあります。
公式( https://firebase.google.com/docs/firestore/quickstart?hl=ja )によれば、
PHPの場合、gRPCのインストールが必要です。
dockerでのインストールの情報が皆無なので書いておきます。

gRPCのインストール

dockerfileの修正(docker-compose で制御する場合の参考)

docker/php/Dockerfile

FROM php:7-fpm

ENV DEBIAN_FRONTEND noninteractive

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt-get -y install git autoconf zlib1g-dev libicu-dev libonig-dev libzip-dev unzip &&\
    apt-get clean && \
    pecl install grpc && \
    pecl install protobuf && \
    rm -rf /var/lib/apt/lists/* &&\
    docker-php-ext-install pdo_mysql &&\
    composer config -g process-timeout 3600 && \
    mkdir -p /app
COPY ./docker/php/php.ini /usr/local/etc/php/php.ini

WORKDIR /app

この中で、gRPCのインストールに関係する部分は、

docker/php/Dockerfile
autoconf zlib1g-dev

でpeclをインストールし、

docker/php/Dockerfile

pecl install grpc && \
pecl install protobuf && \

でgrpc本体をインストールという流れです。
protobufはgrpcのパフォーマンスを向上させるライブラリのようです。

php.iniの修正

dockerfile書くときにphp.iniも書いていると思いますので、
そこに以下を追記

docker/php/php.ini
extension=grpc.so
extension=protobuf.so

そして、composer.jsonファイルの
"require"に

composer.json
"grpc/grpc": "^1.27.0",

を追記してください。
バージョンは公式(https://cloud.google.com/php/grpc?hl=ja)で最新版を確認してください。

そのうえで、再ビルドすればgRPCの導入完了です。
(ただし、gRPCのインストールはめちゃくちゃ時間がかかります。。。)

laravelからfirestoreへのsetができるようにする

ライブラリの導入

コマンドでライブラリのインストール

command
composer require google/cloud-firestore
composer require kreait/laravel-firebase

config/app.phpに追記

config/app.php
return [
    // ...
    'providers' => [
        // ... これを追記
        Kreait\Laravel\Firebase\ServiceProvider::class
    ]
    // ...
];

次に、firebaseのコンソールで、歯車 > サービスアカウント > FIrebase Admin SDK > 新しい秘密鍵の生成
をクリックしてください。

2021-01-25_14h31_21.png

ダウンロードされたファイル名を
firebase_credentials.json
に変えて、プロジェクト直下に設置し、
秘匿情報なので、
gitignoreに
firebase_credentials.json
を追記しておきましょう。

もし本番環境がECS fargateの場合、本番環境ではsshログインできませんので、codebuildのときにs3からコピーするように処理を追記しておきましょう

.env
FIREBASE_CREDENTIALS=firebase_credentials.json

そして、コマンドでconfigファイルを作っておきましょう。

command
php artisan vendor:publish --provider="Kreait\Laravel\Firebase\ServiceProvider" --tag=config

firestoreへのデータのセット等はいろんな箇所で使うことが多いと思うので、サービス化しておきましょう。

以下、サービス化(知っている方、必要ない方は読み飛ばしてください。)

app/Providers/FirebaseApiServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\Application;
use App\Services\FirestoreApiService;

class FirestoreApiServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('FirestoreApi', function(Application $app){
            return new FirestoreApiService();
        });
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}


app/Facades/FirestoreApiFacade.php
<?php

namespace App\Facades;
use Illuminate\Support\Facades\Facade;

class FirestoreApiFacade extends Facade
{
  protected static function getFacadeAccessor()
  {
    return 'FirestoreApi';
  }
}

config/app.php

// providersに追記
        App\Providers\FirestoreApiServiceProvider::class,

// aliasesに追記
        'FirestoreApi' => App\Facades\FirestoreApiFacade::class,

これでサービス化は完了です。

そしていよいよfirestoreへのデータset,update,deleteです。

app/Services/FirestoreApiService.php
<?php
namespace App\Services;

use Google\Cloud\Firestore\FieldValue;

class FirestoreApiService
{
    protected $db;

    public function __construct()
    {
        $this->db = app('firebase.firestore')->database();
    }

    /**
     * firestoreへのデータset
     * @param sender_id int
     * @param room_id int
     * @param comment string
     * @return void
     */
    public function storeComment($sender_id, $room_id, $comment_id ,$comment)
    {
        $docRef = $this->db->collection('rooms')->document($room_id)->collection('comment');

        $docRef->document($comment_id)->set([
            'comment' => $comment,
            'sender_id' => $sender_id,
            'created_at' => FieldValue::serverTimestamp(),
            'updated_at' => FieldValue::serverTimestamp(),
        ]);
    }

    /**
     * firestoreのデータをupdate
     * @param sender_id int
     * @param room_id int
     * @param comment_id int
     * @param comment string
     * @return void
     */
    public function updateComment($sender_id, $room_id, $comment_id, $comment)
    {
        $docRef = $this->db->collection('rooms')->document($room_id)->collection('comment');

        $docRef->document($comment_id)->update([
            [ 'path' => 'comment', 'value' => $comment],
            ['path' => 'updated_at', 'value' => FieldValue::serverTimestamp()]
        ]);
    }

    /**
     * firestoreのデータをdelete
     * @param room_id int
     * @param comment_id int
     * @return void
     */
    public function deleteComment($room_id, $comment_id)
    {
        $docRef = $this->db->collection('rooms')->document($room_id)->collection('comment');

        $docRef->document($comment_id)->delete();
    }

}

これでuseなどを使わなくても、どこでも

\FirestoreApi::storeComment($sender_id, $room_id, $comment);

で呼び出して、Laravelからfirestoreにsetしたりできます。

10
9
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
10
9