4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravel で vendor 配下のファイル操作ライブラリ Filesystem(Flysystem) を拡張する方法

Last updated at Posted at 2020-08-20

こんにちは、しょいみんです。
Laravel フレームワーク内の処理で詰まったところがあったので知見を共有していきますm(_ _)m

概要

Laravel フレームワークはフレームワーク自体に様々なオープンソースのライブラリが含まれているため、それほどプラスα でライブラリをインストールすることなく簡単に開発できるようになっています。

しかし、開発を進めていくと**「既存のライブラリだと少し物足りないなぁ」「既存のライブラリを少しだけ拡張したいなぁ」**といった要望が出てくると思います。

今回は、Laravel で標準インストールされている Flysystem のライブラリを拡張する方法を紹介いたします。この方法を利用すれば Flysystem に限らず Laravel 内の他のライブラリも同様に拡張することができます。

結論

サービスプロバイダー既存のクラスから自分で定義したクラス切り替えることでどんなライブラリでも自分で定義したクラスに差し替えて呼び出すことができます!!!!!

拡張したい関数だけ修正して他の処理は元のライブラリの処理のままコピペすることで既存の処理を壊さずに拡張したい関数だけ修正することができます。

環境

Laravel 5.8
php7.4.5
※検証してませんが Laravel 6, 7 でもサービスプロバイダーの考え方は一緒なので同様の方法で実現できると思います。

目標(拡張したい処理の内容)

画像一覧を取得する関数がデフォルトでファイル名ソートしかできないので任意のメタ情報で昇順・降順ソートできるように関数を拡張します

拡張前の元ファイルと関数

下記ライブラリの関数を修正します。
見ての通りオプションもなくファイルパスでしかソートできないですね (´・ω・`)
vendor/league/flysystem/src/Util/ContentListingFormatter.php

ContentListingFormatter.php
class ContentListingFormatter
{
・・・・・省略・・・・・・

    /**
     * @param array $listing
     *
     * @return array
     */
    private function sortListing(array $listing)
    {
        usort($listing, function ($a, $b) {
            return strcasecmp($a['path'], $b['path']);
        });

        return $listing;
    }
}

拡張後のファイルと関数

拡張後のファイルと関数の内容です。
ファイルパスでしかソートできなかった sortListing() 関数を任意のメタ情報昇順・降順フラグを引数にとって並び替えできるように拡張します。

app/Extensions/Flysystem/Util/ContentListingFormatter.php

ContentListingFormatter.php
class ContentListingFormatter
{
・・・・・省略・・・・・・

    /**
     * @param array $listing
     * @param string $sortType
     * @param bool $isAsc
     *
     * @return array
     */
    private function sortListing(array $listing, string $key = 'path', $isAsc = true)
    {
        usort($listing, function ($a, $b) use ($key, $isAsc) {
            $result = $isAsc ? strcasecmp($a[$key], $b[$key]) : strcasecmp($b[$key], $a[$key]);
            return $result;
        });

        return $listing;
    }
}

修正手順

修正手順です。この3つの手順に沿って修正手順を解説していきます。

  1. 拡張したい関数が記述されてるクラスとそのクラスを呼び出しているクラスをコピペして新しく作成
  2. 関数の修正やネームスペース、呼び出しクラスの参照パスを修正
  3. サービスプロバイダー(FilesystemServiceProvider::class)の切り替え

新しく作成するファイル一覧

下記ファイルパスの vendor 配下のライブラリのコードをコピー元として新規作成します。
修正箇所は後述します。

元ファイルと新規作成ファイル
# league/flysystem ライブラリ
コピー元:  vendor/league/flysystem/src/Filesystem.php
新規作成: app/Extensions/Flysystem/Filesystem.php

コピー元:  vendor/league/flysystem/src/Util/ContentListingFormatter.php
新規作成: app/Extensions/Flysystem/Util/ContentListingFormatter.php

# Laravel 標準フレームワーク内の ファイルシステム 
コピー元:  vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemManager.php
新規作成: app/Extensions/Flysystem/FilesystemManager.php

# Laravel 標準フレームワーク内の サービスプロバイダー
コピー元:  vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemServiceProvider.php
新規作成: app/Providers/FilesystemServiceProvider.php

※ 新規作成するファイルの保存ディレクトリはどこでもいいですが Extensions に格納することとします。
※ サービスプロバイダーは Providers フォルダに格納することとします。

1. 拡張したい関数が記述されてるクラスとそのクラスを呼び出しているクラスをコピペして新しく作成

ContentListingFormatter.php を自身で定義したクラスに差し替えるために必要なファイルをすべてコピペします。
新規作成するファイルは上記の 「元ファイルと新規作成ファイル」 で記載されている 4 ファイルです。
Laravel のファイルシステム実行処理の関係で修正が必要なクラスファイルが増えています。
下記に画像一覧を表示させるための処理の流れを記述しておきます。


  1. config/app.php に記載されている FilesystemServiceProvider.php が呼び出される
  2. FilesystemServiceProvider.phpregisterManager() がエイリアス 'filesystem'FilesystemManagerインスタンスを作成する。
  3. FilesystemManager.phpcreateFlysystem() 関数で Flysystem のインスタンスを返す。
  4. Flysystem.phplistContents() 関数で ContentListingFormatterのインスタンスのformatListing() 関数を実行する。
  5. ContentListingFormatter.phpformatListing() 関数内でソートの関数である $this->sortListing() が実行される。 ← 今回はここの関数の処理を改造します。

流れを確認したことで、5番で利用されている ContentListingFormatter.php自身で定義したクラスに差し替えるために 1 ~ 4 で呼び出されているクラスファイルの参照パスを修正する必要があることがわかります。

2. 関数の修正とネームスペース、呼び出しクラスの参照パスを修正

次にコピペして新規作成したファイルを一つずつ修正していきます。

ContentListingFormatter.php

app/Extensions/Flysystem/Util/ContentListingFormatter.php

<?php

namespace app\Extensions\Flysystem\Util;
# namespace League\Flysystem\Util;

use League\Flysystem\Util;

/**
 * @internal
 */
class ContentListingFormatter
{

--------- 途中 vendor と同じなので省略 ---------

    /**
     * @param array $listing
     * @param string $sortType
     * @param bool $isAsc
     *
     * @return array
     */
#    private function sortListing(array $listing)
    private function sortListing(array $listing, string $key = 'path', $isAsc = true)
    {
        usort($listing, function ($a, $b) use ($key, $isAsc) {
            $result = $isAsc ? strcasecmp($a[$key], $b[$key]) : strcasecmp($b[$key], $a[$key]);
            return $result;
        });

#        usort($listing, function ($a, $b) {
#            return strcasecmp($a['path'], $b['path']);
#        });
        return $listing;
    }
}

ContentListingFormatter.php では拡張したい関数を修正し namespace を app フォルダ配下のパスに修正します。

それ以外のコードは元ファイルのコピペをそのまま利用します。

Filesystem.php

app/Extensions/Flysystem/Filesystem.php
<?php

# namespace League\Flysystem;
namespace app\Extensions\Flysystem;

use InvalidArgumentException;
use League\Flysystem\Adapter\CanOverwriteFiles;
use League\Flysystem\Plugin\PluggableTrait;
# use League\Flysystem\Util\ContentListingFormatter;
use League\Flysystem\FilesystemInterface; # 追記
use League\Flysystem\ConfigAwareTrait; # 追記
use League\Flysystem\AdapterInterface; # 追記
use League\Flysystem\File; # 追記
use League\Flysystem\Directory; # 追記
use League\Flysystem\Handler; # 追記
use League\Flysystem\Util; # 追記
use League\Flysystem\Config; # 追記
use League\Flysystem\FileNotFoundException; # 追記
use League\Flysystem\FileExistsException; # 追記
use League\Flysystem\RootViolationException; # 追記
use App\Extensions\Flysystem\Util\ContentListingFormatter; # 追記
--------- 以下 vendor と同じなので省略 ---------

Filesystem.php では namespaceFilesystem.php 内で利用してるクラスを use 文で参照させます。

もともと vendor 配下の Filesystem.php では同ディレクトリに他のクラスファイルの php が配置されていたので直で参照されていました。今回は app フォルダ配下に Filesystem.php を新規作成したので vendor 配下のクラスファイルをしっかりと use 文で参照させています。

また、
use League\Flysystem\Util\ContentListingFormatter; は vendor 配下のクラスファイルを参照してるのでコメントアウトし、今回自分で作成したファイル
use App\Extensions\Flysystem\Util\ContentListingFormatter;
に参照させ直します。

FilesystemManager.php

app/Extensions/Flysystem/FilesystemManager.php
<?php

# namespace Illuminate\Filesystem;
namespace app\Extensions\Flysystem;

use Closure;
use Aws\S3\S3Client;
use OpenCloud\Rackspace;
use Illuminate\Support\Arr;
use InvalidArgumentException;
use League\Flysystem\AdapterInterface;
use League\Flysystem\Sftp\SftpAdapter;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\Cached\CachedAdapter;
# use League\Flysystem\Filesystem as Flysystem;
use App\Extensions\Flysystem\Filesystem as Flysystem; # 追記
use League\Flysystem\Adapter\Ftp as FtpAdapter;
use League\Flysystem\Rackspace\RackspaceAdapter;
use League\Flysystem\Adapter\Local as LocalAdapter;
use League\Flysystem\AwsS3v3\AwsS3Adapter as S3Adapter;
use League\Flysystem\Cached\Storage\Memory as MemoryStore;
use Illuminate\Contracts\Filesystem\Factory as FactoryContract;
use Illuminate\Filesystem\FilesystemAdapter; # 追記
--------- 以下 vendor と同じなので省略 ---------

こちらも同様 namespace と参照している vendor 配下の Filesystem.php の参照先を自分で作成した app 配下の Filesystem.php に参照させ直しています。

FilesystemServiceProvider.php

app/Providers/FilesystemServiceProvider.php

<?php

# namespace Illuminate\Filesystem;
namespace App\Providers; # 追記

use Illuminate\Support\ServiceProvider;
use Illuminate\Filesystem\Filesystem; # 追記
use App\Extensions\Flysystem\FilesystemManager; # 追記
--------- 以下 vendor と同じなので省略 ---------

Filesystem のサービスプロバイダーです。 config/app.php から呼び出されるやつですね。
こちらも同様、namespace と FilesystemManager.php の参照パスを修正し、参照が切れてしまっているクラスファイルを参照させ直しましょう。

以上で、新規作成したファイルの修正が完了となります。
最後にサービスプロバイダーの切り替えを行いましょう。

3. サービスプロバイダー(FilesystemServiceProvider::class)の切り替え

既存のファイルシステムサービスプロバイダーを自身で作成したサービスプロバイダーに切り替えて変更を反映させます。

app.php

config/app.php
<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Autoloaded Service Providers
    |--------------------------------------------------------------------------
    |
    | The service providers listed here will be automatically loaded on the
    | request to your application. Feel free to add your own services to
    | this array to grant expanded functionality to your applications.
    |
    */

    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        // 既存の Filesystem ではなくソートのコードを拡張した Filesystem を利用するため
        // Illuminate\Filesystem\FilesystemServiceProvider::class,
        App\Providers\FilesystemServiceProvider::class, # 追記

----------- 以下略 -------------
    ],
];

config/app.php ファイルを開けて、'providers' 配列を見てみましょう。
既存のファイルシステムサービスプロバイダーであるIlluminate\Filesystem\FilesystemServiceProvider::class
クラスが記述されています。

ここを自身で作成した、
App\Providers\FilesystemServiceProvider::class
に変更します。

以上ですべての修正が完了です。あとはオートローダのリロードを行うと反映されます。

composer dump-autoload

まとめ

Laravel ではサービスプロバイダーの切り替えで vendor 配下のライブラリですら自身で定義したクラスファイルに切り替えできることがわかりました。

切り替えの手順は 3 ステップ

  1. 拡張したい関数が記述されてるクラスとそのクラスを呼び出しているクラスをコピペして新しく作成
  2. 関数の修正やネームスペース、呼び出しクラスの参照パスを修正
  3. サービスプロバイダー(FilesystemServiceProvider::class)の切り替え

これで vendor 配下を汚さずに拡張できるのでもし要件があったら参考にしてみてくださいm(_ _)m。

ただし、自身で拡張したクラスファイル(ここの場合は Filesystem.phpContentListingFormatter.phpFilesystemManager.phpFilesystemServiceProvider.php の4ファイル) は composer でのライブラリアップデートには追随しないことに注意してください。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?