🎻

kreait/firebase-bundleで初期化したCloud Storageをleague/flysystem-bundleで使う

2022/05/26に公開

kreait/firebase-bundleで初期化したCloud Storage for Firebaseのクライアントをleague/flysystem-bundleから使う方法を解説します。

kreait/firebase-bundleとは

kreait/firebase-phpFirebase Admin SDK のPHP実装で、非公式ではありますがPHPの実装としてはデファクトスタンダードとなっています。

kreait/firebase-phpをSymfonyに簡単に統合するためのバンドルとして kreait/firebase-bundle があります。

league/flysystem-bundleとは

league/flysystem は、様々なファイルシステムを透過的に利用できるようにするためのPHPライブラリです。Amazon S3やGoogle Cloud Storageなど主要なマネージドサービスにも対応しています。

league/flysystemをSymfonyに簡単に統合するためのバンドルとして league/flysystem-bundle があります。

kreait/firebase-bundleの初期化手順

公式のREADME のとおりですが、以下のような手順になります。

1. サービスアカウントの秘密鍵をダウンロード

https://console.firebase.google.com/project/{プロジェクト名}/settings/serviceaccounts/adminsdk?hl=ja

にてサービスアカウントを作成し、秘密鍵のJSONファイルをダウンロードします。今回はそれをプロジェクトルートに firebase-credentials.json として保存することにします。

# .gitignore
/firebase-credentials.json

秘匿情報なので忘れずにgitignoreしておきましょう。

2. バンドルを設定

# config/packages/firebase.yaml

kreait_firebase:
  projects:
    {プロジェクト識別子}:
      credentials: '%kernel.project_dir%/firebase-credentials.json'

これで、kreait_firebase.{プロジェクト識別子}.storage というサービスIDで Kreait\Firebase\Contract\Storage の実装クラスのインスタンスを利用できるようになります。

league/flysystem-bundleの初期化手順

こちらも 公式のREADME および Cloud Storage Providersの利用方法についての公式ドキュメント に詳細が載っていますが、以下のような手順になります。

1. Google Cloud Storage用のアダプタをインストール

$ composer require league/flysystem-google-cloud-storage

2. バンドルを設定

# config/packages/flysystem.yaml

flysystem:
  storages:
    default.storage:
      adapter: gcloud
      options:
        client: Google\Cloud\Storage\StorageClient # service id
        bucket: '%env(FIREBASE_STORAGE_BUCKET_NAME)%'
        # prefix: optional/path/prefix # 必要なら設定
# .env(.local)

FIREBASE_STORAGE_BUCKET_NAME={プロジェクト名}.appspot.com

バケット名は {プロジェクト名}.appspot.com になります(参考)。ローカルと本番など環境ごとに異なるプロジェクトを使い分けることになるかと思いますので、具体的な値は .env に書きましょう。

さて、

client: Google\Cloud\Storage\StorageClient # service id

いきなりこのように書いてみましたが、現状 Google\Cloud\Storage\StorageClient というIDのサービスは定義されていません。

なので、前提として自前で Google\Cloud\Storage\StorageClient クラスのインスタンスを(Google\Cloud\Storage\StorageClient というサービスIDで)サービスとして定義しておく必要があります。

3. Google\Cloud\Storage\StorageClient サービスを定義

kreait/firebase-bundleによってすでに kreait_firebase.{プロジェクト識別子}.storage というサービスIDで Kreait\Firebase\Contract\Storage の実装クラスのインスタンスを利用できるようになっています。

Kreait\Firebase\Contract\Storage のコードを見てみると、getStorageClient() というpublicメソッドで Google\Cloud\Storage\StorageClient のインスタンスを取得できる ことが分かります。

というわけで、これで取得したインスタンスをサービスとして定義してあげればよさそうです。

このような場合には、Symfonyのサービスコンテナの factory 機能 が活用できます。

# config/services.yaml

services:
  Google\Cloud\Storage\StorageClient:
    factory: ['@kreait_firebase.{プロジェクト識別子}.storage', getStorageClient]

このようにすることで、kreait_firebase.{プロジェクト識別子}.storage サービス(つまり Kreait\Firebase\Contract\Storage の実装クラスのインスタンス)の getStorageClient() メソッドの戻り値を Google\Cloud\Storage\StorageClient というIDでサービスとして定義することができます。

これで無事に設定が完了しました👍

使ってみる

実際に使ってみましょう。

適当なコントローラに以下のようなコードを書いてみます。

class SomeController extends AbstractController
{
    public function __construct(private FilesystemOperator $defaultStorage)
    {
    }

    public function someAction(): Response
    {
        $this->defaultStorage->write('test.txt', 'test');

        return new Response();
    }
}

League\Flysystem\FilesystemOperator 型の $defaultStorage をインジェクトして、ここでは write() メソッドを使ってテキストファイルを作成しています。

league/flysystem-bundleのREADMEに記載があるとおり、この $defaultStorage という引数名にはルールがあり、任意の引数名で受け取ることはできません。

今回は

# config/packages/flysystem.yaml

flysystem:
  storages:
    default.storage:
      # 略

このように default.storage というストレージ名で定義したので、これをlowerCamelCaseで表現した $defaultStorage という引数名にバインドされています。

このコントローラを実際に実行したあと、Firebaseのコンソールを見ると以下のようにファイルが作成されていることを確認できます👍

おまけ:kreait/firebase-bundleでFirebase Authenticationを使うときのTips

Cloud Storage for Firebaseと違ってFirebase Authenticationを使うときは特にラッパーを被せたりせず直接使うのが普通だと思います。

Cloud Storage for Firebaseの場合と同様、バンドルにFirebaseの秘密鍵を設定した時点で、kreait_firebase.{プロジェクト識別子}.auth というサービスIDで Kreait\Firebase\Contract\Auth の実装クラスを利用できるようになっています。

が、このサービスを複数箇所で使う必要が出てきたときに、Kreait\Firebase\Contract\Auth 型でautowireしてもらえないのは非常に不便です。

そこで、services.yamlに以下の2行を追記しておきましょう。

# config/services.yaml

services:
  Kreait\Firebase\Contract\Auth:
    alias: kreait_firebase.{プロジェクト識別子}.auth

これで、Kreait\Firebase\Contract\Auth 型のコンストラクタ引数(等)に自動で kreait_firebase.{プロジェクト識別子}.auth サービスがインジェクトされてとても幸せになれます。

GitHubで編集を提案

Discussion