LaravelをAPIサーバーとして使い、Laravelからwebsocketなどではなく、firestoreでチャットやプッシュ通知などリアルタイム通信させたいときがあります。
公式( https://firebase.google.com/docs/firestore/quickstart?hl=ja )によれば、
PHPの場合、gRPCのインストールが必要です。
dockerでのインストールの情報が皆無なので書いておきます。
gRPCのインストール
dockerfileの修正(docker-compose で制御する場合の参考)
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のインストールに関係する部分は、
autoconf zlib1g-dev
でpeclをインストールし、
pecl install grpc && \
pecl install protobuf && \
でgrpc本体をインストールという流れです。
protobufはgrpcのパフォーマンスを向上させるライブラリのようです。
php.iniの修正
dockerfile書くときにphp.iniも書いていると思いますので、
そこに以下を追記
extension=grpc.so
extension=protobuf.so
そして、composer.jsonファイルの
"require"に
"grpc/grpc": "^1.27.0",
を追記してください。
バージョンは公式(https://cloud.google.com/php/grpc?hl=ja)で最新版を確認してください。
そのうえで、再ビルドすればgRPCの導入完了です。
(ただし、gRPCのインストールはめちゃくちゃ時間がかかります。。。)
laravelからfirestoreへのsetができるようにする
ライブラリの導入
コマンドでライブラリのインストール
composer require google/cloud-firestore
composer require kreait/laravel-firebase
config/app.phpに追記
return [
// ...
'providers' => [
// ... これを追記
Kreait\Laravel\Firebase\ServiceProvider::class
]
// ...
];
次に、firebaseのコンソールで、歯車 > サービスアカウント > FIrebase Admin SDK > 新しい秘密鍵の生成
をクリックしてください。
ダウンロードされたファイル名を
firebase_credentials.json
に変えて、プロジェクト直下に設置し、
秘匿情報なので、
gitignoreに
firebase_credentials.json
を追記しておきましょう。
もし本番環境がECS fargateの場合、本番環境ではsshログインできませんので、codebuildのときにs3からコピーするように処理を追記しておきましょう
FIREBASE_CREDENTIALS=firebase_credentials.json
そして、コマンドでconfigファイルを作っておきましょう。
php artisan vendor:publish --provider="Kreait\Laravel\Firebase\ServiceProvider" --tag=config
firestoreへのデータのセット等はいろんな箇所で使うことが多いと思うので、サービス化しておきましょう。
以下、サービス化(知っている方、必要ない方は読み飛ばしてください。)
<?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()
{
//
}
}
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class FirestoreApiFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'FirestoreApi';
}
}
// providersに追記
App\Providers\FirestoreApiServiceProvider::class,
// aliasesに追記
'FirestoreApi' => App\Facades\FirestoreApiFacade::class,
これでサービス化は完了です。
そしていよいよfirestoreへのデータset,update,deleteです。
<?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したりできます。