Laravelのキャッシュファイルのパーミッション設定

以前以下の記事でキャッシュファイルのパーミッション設定を結局「umask」を利用しましたが、もっと良い方法がないか調べてみました。
[Laravelのファイルパーミッションの問題](https://qiita.com/FattyRabbit/items/cf05e5ce79150daf2113)

## 他は？
ファイル・ディレクトリの作成がumaskの影響を受けることなら、ログの設定ファイルでパーミッションはどうやるの？調べてみました。たどり着いたのが以下のメソッドです。

```php:Monolog\Handler\StreamHandler.php

   /**
     * {@inheritdoc}
     */
    protected function write(array $record): void
    {
        if (!is_resource($this->stream)) {
            if (null === $this->url || '' === $this->url) {
                throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
            }
            $this->createDir();
            $this->errorMessage = null;
            set_error_handler([$this, 'customErrorHandler']);
            $this->stream = fopen($this->url, 'a');
            if ($this->filePermission !== null) {
                @chmod($this->url, $this->filePermission);
            }
            restore_error_handler();
            if (!is_resource($this->stream)) {
                $this->stream = null;

                throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
            }
        }

        if ($this->useLocking) {
            // ignoring errors here, there's not much we can do about them
            flock($this->stream, LOCK_EX);
        }

        $this->streamWrite($this->stream, $record);

        if ($this->useLocking) {
            flock($this->stream, LOCK_UN);
        }
    }
```
:frowning2:結局chmodか〜〜〜。そうなら俺も作るよ。

## カスタムキャッシュドライバを作成
### 設定ファイル
先ず、設定ファイルを追記して置きましょう！permissionsを追加しました。

```php:config/cache.php
        'file' => [
            'driver' => 'local',
            'path' => storage_path('framework/cache/data'),
            'permissions' => [
                'dir' => 0775,
                'file' => 0664,
            ],
        ],
```
ここのdriverも「file」→「local」に変えます。

### ストア作成
そのあと、ドライバー用のストアを作成します。

```php:pp\Extensions\CacheLocalFileStore.php
<?php
namespace App\Extensions;

use Illuminate\Cache\FileStore;
use Illuminate\Filesystem\Filesystem;
use League\Flysystem\Cached\CachedAdapter;

class CacheLocalFileStore extends FileStore
{

    /**
     * The file cache permissions.
     *
     * @var array
     */
    protected $permissions;

    /**
     * Create a new file cache store instance.
     *
     * @param Filesystem $files
     * @param $config
     */
    public function __construct(Filesystem $files, $config)
    {
        $this->files = $files;
        $this->directory = $config['path'];
        $this->permissions = $config['permissions'];
    }

    /**
     * Store an item in the cache for a given number of seconds.
     *
     * @param  string  $key
     * @param  mixed   $value
     * @param  int  $seconds
     * @return bool
     */
    public function put($key, $value, $seconds)
    {
        $this->ensureCacheDirectoryExists($path = $this->path($key));

        $result = $this->files->put(
            $path, $this->expiration($seconds).serialize($value), true
        );
        @chmod($path, $this->permissions['file']);

        return $result !== false && $result > 0;
    }

    /**
     * Create the file cache directory if necessary.
     *
     * @param  string  $path
     * @return void
     */
    protected function ensureCacheDirectoryExists($path)
    {
        $concatPath = $this->directory;
        $dir = trim(str_replace($concatPath, '', dirname($path)), '/');
        $dirNames = explode('/', $dir);
        foreach ($dirNames as $direName) {
            $concatPath .= '/'. $direName;
            if (! $this->files->exists($concatPath)) {
                $this->files->makeDirectory($concatPath, 0777, true, true);
                @chmod($concatPath, $this->permissions['dir']);
            }
        }
    }
}
```
既存のFileStoreを継承して使いました。ensureCacheDirectoryExists中でforeach分を使った理由は作成するpathが「/8/50」ようなディレクトリ構造なのでchmodが親の断層も出来る用法が思い浮かばなかったからです。

### プロバイダー作成
登録するためにプロバイダーを作成します。

```php
<?php

namespace App\Providers;

use App\Extensions\CacheLocalFileStore;
use App\Extensions\MongoStore;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;

class CacheServiceProvider extends ServiceProvider
{
    /**
     * コンテナ結合の登録
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * 全アプリケーションサービスの初期起動
     *
     * @return void
     */
    public function boot()
    {
        Cache::extend('local', function ($app) {
            return Cache::repository(new CacheLocalFileStore($app['files'], config('cache.stores.file')));
        });
    }
}
```
設定ファイルのドライバー「local」で登録します。上記のプロバイダーをconfig/app.phpに登録します。