# 機能設計書 32-ネイティブファイルシステム

## 概要

本ドキュメントは、Laravel Frameworkにおけるネイティブファイルシステム（Native Filesystem）機能の設計書である。PHPのファイル操作関数をラップし、ファイルやディレクトリの操作を一貫したAPIで提供する基盤コンポーネントである。

### 本機能の処理概要

**業務上の目的・背景**：
アプリケーション開発において、設定ファイルの読み込み、ログファイルの出力、キャッシュファイルの管理など、ローカルファイルシステムへのアクセスは必須である。PHPの標準ファイル関数は低レベルで使いにくい場合があるため、本機能ではそれらをラップし、例外ベースのエラーハンドリング、流暢なインターフェース、追加のユーティリティメソッドを提供する。これにより、ファイル操作コードの可読性と保守性が向上する。

**機能の利用シーン**：
- 設定ファイル（PHP、JSON）の読み込み
- Bladeテンプレートのコンパイル結果の保存
- セッションファイルの管理
- キャッシュファイルの読み書き
- ログファイルへの追記
- 一時ファイルの作成と削除
- ディレクトリの作成・削除・コピー

**主要な処理内容**：
1. ファイル存在確認（`exists`, `missing`メソッド）
2. ファイル読み込み（`get`, `json`, `lines`, `sharedGet`, `getRequire`メソッド）
3. ファイル書き込み（`put`, `replace`, `prepend`, `append`メソッド）
4. ファイル情報取得（`size`, `lastModified`, `mimeType`, `hash`メソッド）
5. ファイル操作（`copy`, `move`, `delete`, `link`メソッド）
6. ディレクトリ操作（`makeDirectory`, `copyDirectory`, `deleteDirectory`, `cleanDirectory`メソッド）
7. ファイル/ディレクトリ一覧取得（`files`, `allFiles`, `directories`, `allDirectories`メソッド）

**関連システム・外部連携**：
- Symfony Filesystem: 相対リンク作成時に使用
- Symfony Finder: ファイル/ディレクトリ検索に使用
- Symfony Mime: MIMEタイプ推測に使用

**権限による制御**：
ファイルシステムのパーミッションはOSレベルで制御される。本機能は`chmod`メソッドでパーミッション変更をサポートする。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はバックエンド処理のため、直接関連する画面はない |

## 機能種別

ファイル操作 / ユーティリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | string | Yes | ファイルまたはディレクトリのパス | - |
| contents | string | Yes（書き込み時） | ファイル内容 | - |
| lock | bool | No | ファイルロックを使用するか | デフォルト: false |
| mode | int | No | パーミッション（8進数） | デフォルト: 0755（ディレクトリ）、0644（ファイル） |
| recursive | bool | No | 再帰的に処理するか | デフォルト: false |

### 入力データソース

- ローカルファイルシステム
- アプリケーションコードからの直接呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| contents | string | ファイル内容 |
| exists | bool | 存在確認結果 |
| size | int | ファイルサイズ（バイト） |
| lastModified | int | 最終更新日時（UNIXタイムスタンプ） |
| files | array | ファイル一覧 |
| directories | array | ディレクトリ一覧 |

### 出力先

- ローカルファイルシステム
- 戻り値として呼び出し元に返却

## 処理フロー

### 処理シーケンス

```
1. メソッド呼び出し
   └─ 対象パスとオプションを受け取る

2. パス検証（読み込み系）
   └─ ファイル/ディレクトリの存在確認
   └─ 存在しない場合はFileNotFoundException

3. ファイル操作実行
   └─ PHP標準関数またはSymfonyコンポーネント呼び出し
   └─ ロックが必要な場合はflock使用

4. 結果返却
   └─ 成功: 内容または操作結果
   └─ 失敗: false または例外
```

### フローチャート

```mermaid
flowchart TD
    A[メソッド呼び出し] --> B{操作種別}
    B -->|読み込み| C{ファイル存在?}
    C -->|Yes| D[ファイル読み込み]
    C -->|No| E[FileNotFoundException]
    D --> F{ロック必要?}
    F -->|Yes| G[共有ロック取得]
    F -->|No| H[直接読み込み]
    G --> I[内容取得]
    H --> I
    I --> J[ロック解放]
    J --> K[内容返却]

    B -->|書き込み| L{ディレクトリ存在?}
    L -->|No| M[ディレクトリ作成]
    L -->|Yes| N[ファイル書き込み]
    M --> N
    N --> O{ロック必要?}
    O -->|Yes| P[排他ロック取得]
    O -->|No| Q[直接書き込み]
    P --> R[書き込み実行]
    Q --> R
    R --> S[結果返却]

    B -->|削除| T[ファイル/ディレクトリ削除]
    T --> U[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-32-01 | 存在確認 | 読み込み前にファイル存在を確認し、なければ例外 | get, getRequire等 |
| BR-32-02 | アトミック置換 | replaceメソッドは一時ファイル経由で原子的に置換 | replace使用時 |
| BR-32-03 | 共有ロック | sharedGetは読み取り中に他プロセスの書き込みを防止 | sharedGet使用時 |
| BR-32-04 | 再帰作成 | makeDirectoryはrecursive=trueで親ディレクトリも作成 | recursive=true |
| BR-32-05 | シンボリックリンク | link()はWindowsではハードリンク/ジャンクション使用 | Windows環境 |

### 計算ロジック

**ハッシュ計算**:
```
hash($path, $algorithm = 'md5') = hash_file($algorithm, $path)
```

**同一ファイル判定**:
```
hasSameHash($file1, $file2) = hash_file('xxh128', $file1) === hash_file('xxh128', $file2)
```

## データベース操作仕様

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | FileNotFoundException | 指定ファイルが存在しない | パスを確認、ファイル作成 |
| - | RuntimeException | シンボリックリンク作成失敗 | パーミッション確認 |
| - | ErrorException | 削除失敗 | パーミッション確認 |

### リトライ仕様

本機能にリトライ機能は含まれない。必要に応じて呼び出し元で実装する。

## トランザクション仕様

ファイルシステム操作はデータベーストランザクションに含まれない。`replace`メソッドは一時ファイルを使用した擬似的なアトミック操作を提供する。

## パフォーマンス要件

- `lines`メソッドはLazyCollectionを返し、大きなファイルをメモリ効率よく処理可能
- `allFiles`、`allDirectories`は再帰的に全ファイルを取得するため、大量ファイル時は注意
- ファイルロックは他プロセスをブロックする可能性があるため、長時間のロックは避ける

## セキュリティ考慮事項

- パストラバーサル攻撃を防ぐため、ユーザー入力をパスに直接使用しない
- `getRequire`はPHPファイルを実行するため、信頼できないファイルには使用しない
- シンボリックリンクによるディレクトリ外アクセスに注意（`DISALLOW_LINKS`オプション）

## 備考

- Macroableトレイトにより、カスタムメソッドを動的に追加可能
- Conditionableトレイトにより、条件付きメソッドチェーンが可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: インターフェースを理解する

まず、Filesystemの契約を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FileNotFoundException.php | `src/Illuminate/Contracts/Filesystem/FileNotFoundException.php` | 例外クラスの定義 |

#### Step 2: メインクラスを理解する

Filesystemクラスの全体構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Filesystem.php | `src/Illuminate/Filesystem/Filesystem.php` | 全メソッドの実装 |

**主要処理フロー**:
- **27-30行目**: `exists()` - file_exists()のラッパー
- **52-59行目**: `get()` - ファイル内容取得、ロック対応
- **82-103行目**: `sharedGet()` - 共有ロック付き読み込み
- **114-128行目**: `getRequire()` - PHPファイルのrequireと変数展開
- **163-180行目**: `lines()` - LazyCollectionでの行単位読み込み
- **202-205行目**: `put()` - ファイル書き込み
- **215-234行目**: `replace()` - アトミック置換
- **300-319行目**: `delete()` - ファイル削除（複数対応）
- **328-331行目**: `move()` - ファイル移動
- **340-343行目**: `copy()` - ファイルコピー
- **352-365行目**: `link()` - シンボリックリンク作成
- **640-663行目**: `makeDirectory()` - ディレクトリ作成
- **690-728行目**: `copyDirectory()` - ディレクトリコピー
- **739-770行目**: `deleteDirectory()` - ディレクトリ削除

**読解のコツ**: このクラスはPHPの標準ファイル関数をラップしているため、各メソッドは対応するPHP関数を呼び出している。例外処理とオプション追加がLaravel固有の付加価値。

#### Step 3: サービスプロバイダーを理解する

コンテナ登録を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FilesystemServiceProvider.php | `src/Illuminate/Filesystem/FilesystemServiceProvider.php` | ネイティブファイルシステムの登録 |

**主要処理フロー**:
- **38-43行目**: `registerNativeFilesystem()` - `files`としてシングルトン登録

### プログラム呼び出し階層図

```
File::get($path)
    │
    └─ Filesystem::get($path, $lock)
           │
           ├─ isFile($path) ... ファイル存在確認
           │      └─ is_file()
           │
           ├─ $lock = true の場合
           │      └─ sharedGet($path)
           │             ├─ fopen($path, 'rb')
           │             ├─ flock($handle, LOCK_SH)
           │             ├─ stream_get_contents($handle)
           │             ├─ flock($handle, LOCK_UN)
           │             └─ fclose($handle)
           │
           └─ $lock = false の場合
                  └─ file_get_contents($path)

File::put($path, $contents)
    │
    └─ Filesystem::put($path, $contents, $lock)
           │
           └─ file_put_contents($path, $contents, $lock ? LOCK_EX : 0)

File::delete($paths)
    │
    └─ Filesystem::delete($paths)
           │
           └─ foreach $paths
                  └─ unlink($path)
                         └─ clearstatcache(false, $path)
```

### データフロー図

```
[入力]                    [処理]                           [出力]

パス文字列 ──────────────▶ Filesystem::get()
                               │
                         ファイル存在確認
                               │
                         ┌─────┴─────┐
                         │           │
                      存在する    存在しない
                         │           │
                    ファイル読み込み  FileNotFoundException
                         │
                    内容（string）◀──┘

パス + 内容 ──────────────▶ Filesystem::put()
                               │
                         file_put_contents()
                               │
                    書き込みバイト数 / false ◀──┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Filesystem.php | `src/Illuminate/Filesystem/Filesystem.php` | ソース | ネイティブファイルシステム操作の主実装 |
| FilesystemServiceProvider.php | `src/Illuminate/Filesystem/FilesystemServiceProvider.php` | ソース | サービスプロバイダー |
| FileNotFoundException.php | `src/Illuminate/Contracts/Filesystem/FileNotFoundException.php` | インターフェース | ファイル未検出例外 |
| Filesystem.php | `src/Illuminate/Contracts/Filesystem/Filesystem.php` | インターフェース | Filesystem契約（クラウド用） |
| LazyCollection.php | `src/Illuminate/Support/LazyCollection.php` | ソース | linesメソッドで使用 |
