NTTドコモ様_dカーシェア
NTTドコモ様_dカーシェア
2017.06.02
#23
バックエンドへの道

それはそれは素晴らしい『Laravel』のファイルシステムについて語りたい

エリカ

こんにちは、エリカです。

今回は『Laravel』でのファイルの保存処理についてです。それはもう唐突なのですが、『Laravel』のファイルシステムがそれはもう素晴らしいものだったので書かずにはいられませんでした。

ちなみに『Laravel』とは PHP フレームワークの一種です。

それでは、順を追って見ていきましょう。

 

ファイルシステムの設定ファイル

まずは、ファイルシステムの設定ファイル(config/filesystems.php)を見てみましょう。

'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

        's3' => [
            'driver' => 's3',
            'key' => env('AWS_KEY'),
            'secret' => env('AWS_SECRET'),
            'region' => env('AWS_REGION'),
            'bucket' => env('AWS_BUCKET'),
        ],

    ],

 
ご覧のように、disksに、localpublics3 の設定がそれぞれ記述されています。『Laravel』のファイルシステムは単一の API を通して処理を行うことができるので、ファイルのストレージを自由に設定できます。Local Storage でも Amazon S3 でも、驚くほどカンタンに切り替えられます。

これにより、開発環境や本番環境などでも、設定ファイルに従ってファイルストレージを柔軟に切り替えることができます。

『Laravel』では、はじめから PHPUnit を利用することができるので、少しテストコードを書きながら見ていきます。

 

artisan make:test StorageTest を実行して、tests/Feature/StorageTest.php を作成します。

そうすると、下記のような形になってるかと思います。

<?php

namespace TestsFeature;

use TestsTestCase;
use IlluminateFoundationTestingWithoutMiddleware;
use IlluminateFoundationTestingDatabaseMigrations;
use IlluminateFoundationTestingDatabaseTransactions;

class StorageTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

 

それではファイルシステム local への保存をテストしてみましょう。

 

localへの保存

まず、namespace の下に

use IlluminateHttpUploadedFile;

 

を追加して、testExample() の中身を変更します。

$dummy = UploadedFile::fake()->create('dummy.pdf'); // ①

        $dummy->storeAs('', 'dummy.pdf', ['disk' => 'local']); // ②

        $this->markTestIncomplete(
            'このテストは、まだ実装されていません。'
        );

 

[1]
ここではダミーのファイルオブジェクトを生成しています。実装時には、アップロードされたファイルになどになるかと思います。

[2]
1つめの引数が、設定ファイルで指定されているストレージのルートディレクトリからのパスになります。上記の例では、ストレージのルートディレクトリ直下です。2つめの引数が、保存する際のファイル名になります。3つめの引数で、どのストレージを利用するかを指定しています。上の例では、local を指定しています。

 

全体としては、こうなります。

<?php

namespace TestsFeature;

use IlluminateHttpUploadedFile;
use TestsTestCase;
use IlluminateFoundationTestingWithoutMiddleware;
use IlluminateFoundationTestingDatabaseMigrations;
use IlluminateFoundationTestingDatabaseTransactions;

class StorageTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        $dummy = UploadedFile::fake()->create('dummy.pdf');

        $dummy->storeAs('', 'dummy.pdf', ['disk' => 'local']);

        $this->markTestIncomplete(
            'このテストは、まだ実装されていません。'
        );
    }
}

 

変更したら、phpunit を実行します。 storage/app/ 以下に dummy.pdf が保存されているかと思います。

'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

 

storage_path('app') というヘルパー関数でストレージのルートディレクトリが定義されおり、実際にそのとおりの場所にファイルが保存されました。

 

publicへの保存

次に、ファイルシステム public への保存をテストしてみます。

先ほどのテストから下記のみ変更します。

$dummy->storeAs('', 'dummy.pdf', ['disk' => 'public']);

変更したら、phpunit を実行します。 今度は storage/app/public/ 以下に保存されたかと思います。

'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

 

こちらも storage_path('app/public') で指定されているルートディレクトリのとおりになりました。そして、この public ストレージへはブラウザからアクセスできるようになっているので、下記 URL へ対象のファイルを読み込めます。

http://公開URL/storage/指定したファイル名

 
事前に aritizan storage:link を実行して、public/storage から storage/app/public へのリンボリックリンクを貼っておく必要があります。

 

S3への保存

最後に、ファイルシステム s3 への保存です。こちらは、ほんの少し準備が必要です。

まず、S3 用のドライバを利用するためのパッケージをインストールします。

$ composer require league/flysystem-aws-s3-v3 ~1.0

に、AWS S3 でストレージとして利用するバケットを用意します。用意ができたら、そのバケットに対しての権限を持つ IAM を用意します。プロジェクトの直下にある .env ファイルに下記を追加して、先ほど用意した情報を設定してください。

AWS_KEY=
AWS_SECRET=
AWS_REGION=
AWS_BUCKET=

 

それでは、テストコードを一部変更します。

$dummy->storeAs('', 'dummy.pdf', ['disk' => 's3']);

 

AWS S3 のコンソールから、対象のバケットに dummy.pdf が PUT されましたか?

 

テスト用のストレージ

そして、もっと便利なのがテストのときです。S3 へ保存するコードのテストですが、AWS の設定を都度しなければなりません。

そのような場合に、ストレージの場所を一時的に変更することができます。

ストレージの操作をする前に Storage::fake('s3'); を実行するだけです。

<?php

namespace TestsFeature;

use IlluminateHttpUploadedFile;
use IlluminateSupportFacadesStorage; // ①
use TestsTestCase;
use IlluminateFoundationTestingWithoutMiddleware;
use IlluminateFoundationTestingDatabaseMigrations;
use IlluminateFoundationTestingDatabaseTransactions;

class StorageTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        Storage::fake('s3'); // ②

        $dummy = UploadedFile::fake()->create('dummy.pdf');

        $dummy->storeAs('', 'dummy.pdf', ['disk' => 's3']);

                Storage::disk('s3')->assertExists('dummy.pdf'); // ③
    }
}

 

[1]
Storage::fake()を実行できるようにします。

[2]
s3 のストレージには仮のものを割り当ててます。これは『Laravel』の特徴のひとつでもあるのですが、Storage の中身をすり替えているのです。

[3]
ストレージに対象のファイルが存在するかをテストします。

 

このようにして、phpunit を実行すると、実際に S3 へは接続せずに、storage/framework/testing/disks/s3 以下へ保存されるようになります。そして、テストの判定も その変更されたディレクトリを確認しています。

実際に、どこに保存されたかが重要でない場面のテストを行うときなどに活用できる便利な機能ですよね。

 

まとめ

唐突に『Laravel』についてご紹介しましたが、少しは興味をお持ちいただけましでしょうか? 私は、とても洗練されたフレームワークだと思いました。もちろん素晴らしい面だけでもないのかもしれませんが、気になった部分はどんどんお伝えしていければと思います。