ファイルのアップロードに関連したコードの開発で、LaravelのStorageのクラスを使用する機会がありました。そのクラスを使用しての出力処理で学んだことを今回は共有します。

まず、Laravelではアップロードしたファイルや生成したファイルの保管場所としてstorage/appのディレクトリが設けられています。

例えば、現在開発しているプロジェクトでは以下のようです。

$ tree storage/app
storage/app
├── public
├── shop
│   ├── 2
│   │   ├── order.csv
│   │   ├── products20181227-024348.csv
│   │   ├── products20181227-034433.csv

storage/app/shop/2のディレクトリのファイルのリストが欲しいなら、tinkerでは、

>>> Storage::files('shop/2')
=> [
     "shop/2/order.csv",
     "shop/2/products20181227-024348.csv",
     "shop/2/products20181227-034433.csv",
   ]

さて、ここで以下のようなファイル名だけの配列のデータが欲しいです。

[
     "order.csv",
     "products20181227-024348.csv",
     "products20181227-034433.csv",
]

foreachも使えますが、array_mapを使ってみましょう。

>>> $files = Storage::files('shop/2');
=> [
     "shop/2/order.csv",
     "shop/2/products20181227-024348.csv",
     "shop/2/products20181227-034433.csv",
   ]
>>> array_map(function($file) { return basename($file); }, $files);
=> [
     "order.csv",
     "products20181227-024348.csv",
     "products20181227-034433.csv",
   ]

さらに、productsで始まるファイル名だけが欲しいとすると、

>>> $products = array_map(function($file) { \
... if (substr(basename($file), 0, 8) == 'products') return basename($file); \
... }, $files)
=> [
     null,
     "products20181227-024348.csv",
     "products20181227-034433.csv",
   ]

あれれ、これでは余計なnullのファイル名が出てきます。
それを抜くために、今度はarray_filterです。

>>> array_filter($products, function($file) { return ($file !== null); });
=> [
     1 => "products20181227-024348.csv",
     2 => "products20181227-034433.csv",
   ]

ややこしいですね。残念ながら一発で両方を行う関数はphpにはありません。

Laravelならどうでしょうか。Storage::diskは配列を返すので、まずCollectionに変えます。

>>> $files = collect(Storage::files('shop/2'));
=> Illuminate\Support\Collection {#3522
     all: [
       "shop/2/order.csv",
       "shop/2/products20181227-024348.csv",
       "shop/2/products20181227-034433.csv",
     ],
   }
>>> $files->map(function($file) { \
... if (substr(basename($file), 0, 8) == 'products') return basename($file); } \
... )->filter(function($file) { return ($file !== null); });
=> Illuminate\Support\Collection {#3534
     all: [
       1 => "products20181227-024348.csv",
       2 => "products20181227-034433.csv",
     ],
   }

phpの関数とは違ってチェーンできるので少しはすっきりします。しかし、foreachの方が簡単かな、とも思うときでもあります。

最後に、保管場所をstorage/app以外にしたいなら、config/filesystemes.phpの設定で変更できます。

...
    'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'), //ここを編集する
        ],
...

By khino