Laravel11の公式パッケージPromptsにファイル選択機能はありませんが、既存のsuggestを使ってそれっぽいものを実装できます。
![](https://laravel.com/img/og-image.jpg)
前提条件
- Laravel Promptsインストール済
Laravel Promptsのインストールについては次の記事をご覧ください。
ファイル選択機能を実装する
Laravel Promptsのsuggestと、
PHPのRecursiveDirectoryIteratorを使います。
▼ディレクトリ内のエントリーを返すクラス
「src/Dir.php」
<?php
namespace MyLib;
class Dir
{
/**
* ディレクトリ内の全エントリーをRecursiveDirectoryIteratorで返す
*
* @param string $value
* @return \RecursiveDirectoryIterator|\RegexIterator|array{}
*/
public static function glob(string $value)
{
if (strlen($value) === 0) {
return new \RecursiveDirectoryIterator('.');
}
if (str_ends_with($value, '/')) {
if (is_dir($value) && is_readable($value)) {
return new \RecursiveDirectoryIterator($value);
}
return [];
}
$dir = './';
$file = $value;
if (str_contains($value, '/')) {
$dir = dirname($value);
$file = pathinfo($value)['basename'];
}
$pattern = sprintf("/%s/", preg_quote($file));
return new \RegexIterator(
new \RecursiveDirectoryIterator($dir),
$pattern
);
}
/**
* ディレクトリ内の全エントリーを配列で返す
*
* @param string $value
* @return string[]
*/
public static function entries(string $value)
{
$entries = array_map(
fn (string $e) => is_dir($e)
? str_replace('//', '/', $e . '/')
: str_replace('//', '/', $e),
iterator_to_array(self::glob($value))
);
sort($entries);
return $entries;
}
}
▼ファイル選択機能を実装したコード
「src/selectFile.php」
<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/Dir.php';
use function Laravel\Prompts\suggest;
$selected = suggest(
label: 'ファイルを選んでください。',
placeholder: './vendor/autoload.php',
default: '',
options: fn (string $value) => MyLib\Dir::entries($value),
required: 'ファイル選択は必須です。',
validate: fn (string $value) => match (true) {
is_dir($value) => 'ディレクトリは選択できません。',
!is_readable($value) => '読み取りできません。',
default => null,
},
);
var_dump($selected);
動作確認
上記のコードを実行してみます。
php -f src/selectFile.php
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_01.png)
[↓]または[↑]を押すとカレントディレクトリ内のエントリーが表示されます。
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_02.png)
「./vendor/」を選択して確定してみます。
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_04.png)
入力欄に「./vendor/」が入力補間されます。
「ディレクトリは選択できません。」は無視してください。
[→]を押してから[End]でカーソルを入力欄最後尾に配置し、
続けて「.」を入力すると、候補の選択肢が「./vendor/.」内のエントリーに切り替わります。
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_05.png)
「./vendor/autoload.php」を選択してみます。
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_07.png)
選択したファイルパスが返されました。
「/root/」のような読取権限の無いディレクトリの場合は
エントリーが表示されません。
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_09.png)
「/etc/sudoers」のような読取権限のないファイルは選択できません。
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_10.png)
まとめ
一応、それっぽい動きになっていると思いますが、
課題を挙げるとすれば次のものでしょうか。
- ディレクトリ選択後に文字列更新しないとエントリーが更新されない
- ディレクトリ選択時にバリデーションエラーが表示される
- エントリーの検索があいまい検索になっている
- 拡張子のフィルタリングは施していない
後半の課題は「Dir.php」をリファクタリングすれば解決できそうですが、前半の課題をクリアするなら、やはり機能開発して公式リポジトリにPRするべきでしょうか。
※2024/05/29 ソッコー却下されるかもしれませんが、Laravel Prompts公式リポジトリにPRしておきました。
※ 上記課題の「あいまい検索」以外は解決済です。
※ あえて「あいまい検索」は残しておきました。
※2024/05/30追記:ソッコー却下されましたが、否定的な理由では無く、慎重な表現を用いて提案が示されています。
![](https://macocci7.net/blog/wp-content/uploads/2024/05/laravel11_prompts_select_file_12.png)
▼自動翻訳
Laravel へのプルリクエストをありがとうございます。
残念ながら、今のところこのコードのマージは延期する予定です。フレームワークを適切に維持する能力を維持するには、含めるコードの量について細心の注意を払う必要があります。
可能であれば、コミュニティがあなたの貢献を引き続き活用できるように、コードをパッケージとしてリリースすることを検討してください。
このコードがフレームワークのバグを修正していると確信できる場合は、追加の説明とともにフォローアップ コメントで私に「@」を付けてください。そうすれば、GitHub からあなたの応答の通知が私に送信されます。
※ 特にバグ修正はしていないので、提案通りにパッケージとしてリリースすることの「検討を加速させる所存であります」。
※ 記念にDEMO動画を貼り付けておきます。
※ 2024/06/02 「file-selector-prompt」パッケージとしてリリースしました。
コメント