# 画面設計書 43-メディア管理

## 概要

本ドキュメントは、Shopware 6 Administration（管理画面）における「メディア管理」画面の設計書です。この画面は画像・ファイルのアップロード・管理を行うメディアライブラリ機能を提供します。

### 本画面の処理概要

**業務上の目的・背景**：ECサイト運営において、商品画像、バナー、ドキュメントなど多様なメディアファイルを効率的に管理することは重要な業務です。本画面は、フォルダ構造によるファイル整理、一括アップロード、メタ情報の編集、他エンティティでの利用状況確認など、包括的なメディア管理機能を提供します。ドラッグ&ドロップによる直感的な操作と、強力な検索・フィルター機能により、大量のメディアファイルを効率的に管理できます。

**画面へのアクセス方法**：管理画面にログイン後、左側メニューの「コンテンツ」→「メディア」をクリックすることでアクセスできます。URLパスは `/admin#/sw/media/index` または `/admin#/sw/media/index/{folderId}` となります。`media.viewer` 権限を持つユーザーのみがアクセス可能です。

**主要な操作・処理内容**：
1. メディア一覧の表示 - グリッド形式でメディアファイルとフォルダを一覧表示
2. メディアのアップロード - ファイル選択またはドラッグ&ドロップによるアップロード
3. フォルダの作成・編集・削除 - 階層構造によるファイル整理
4. メディアの検索 - キーワード検索による絞り込み
5. メディアの詳細表示・編集 - サイドバーでのメタ情報表示・編集
6. メディアの削除 - 単一または複数ファイルの削除
7. フォルダ間移動 - ドラッグ&ドロップによるファイル移動
8. 使用状況の確認 - メディアがどのエンティティで使用されているか表示

**画面遷移**：
- 遷移元: ダッシュボード、メニュー、各種エンティティ編集画面（商品、カテゴリ等）
- 遷移先: なし（モーダル形式での詳細編集）

**権限による表示制御**：
- `media.viewer`: 閲覧権限 - メディア一覧の表示が可能
- `media.creator`: 作成権限 - アップロード、フォルダ作成が可能
- `media.editor`: 編集権限 - メタ情報の編集、移動が可能
- `media.deleter`: 削除権限 - 削除ボタンが表示

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 62 | CMSページ表示 | 補助機能 | 画像・ファイルのアップロード・管理 |

## 画面種別

一覧（グリッドビュー、フォルダ階層ナビゲーション付き）

## URL/ルーティング

- **パス**: `/admin#/sw/media/index` または `/admin#/sw/media/index/:folderId?`
- **コンポーネント**: `sw-media-index`
- **ルート名**: `sw.media.index`
- **必要権限**: `media.viewer`
- **パラメータ**: `folderId` - 表示するフォルダのID（オプション、省略時はルートフォルダ）

## 入出力項目

| 項目名 | 種別 | 型 | 必須 | 説明 |
|--------|------|-----|------|------|
| routeFolderId | 入力 | string | - | 表示するフォルダのID |
| term | 入力 | string | - | 検索キーワード |
| fileAccept | 入力 | string | - | アップロード可能なファイルタイプ（デフォルト: */*） |

## 表示項目

| 項目名 | 説明 | 編集可否 |
|--------|------|----------|
| サムネイル | メディアファイルのプレビュー画像 | - |
| ファイル名 | メディアのファイル名 | string |
| ファイルサイズ | ファイルの容量 | - |
| 拡張子 | ファイルの種類（jpg, png, pdf等） | - |
| アップロード日時 | ファイルがアップロードされた日時 | - |
| 代替テキスト | 画像のalt属性 | string |
| タイトル | メディアのタイトル | string |
| 使用状況 | 商品、カテゴリ等での使用箇所 | - |
| タグ | メディアに付けられたタグ | array |

## イベント仕様

### 1-ページ読み込み（createdComponent）

画面初期表示時の処理。

**処理フロー**:
1. `updateFolder()` を呼び出しフォルダ情報を取得
2. routeFolderIdがない場合、ルートフォルダを表示
3. routeFolderIdがある場合、該当フォルダと親フォルダ情報を取得

### 2-フォルダ移動（updateRoute）

パンくずリストまたはフォルダクリックで別フォルダへ移動。

**処理フロー**:
1. 検索キーワードをリセット
2. `$router.push()` で新しいフォルダへ遷移
3. `updateFolder()` で新しいフォルダ情報を取得

### 3-アップロード開始（onUploadsAdded）

ファイルをドラッグ&ドロップまたは選択。

**処理フロー**:
1. アップロード予定数を `pendingUploadsCount` に加算
2. `mediaService.runUploads()` でアップロード処理を開始

### 4-アップロード完了（onUploadFinished）

ファイルのアップロードが完了。

**処理フロー**:
1. アップロード完了したファイルを `uploads` から削除
2. `pendingUploadsCount` をデクリメント
3. 全アップロード完了時、リストを再取得（`reloadList()`）

### 5-アップロード失敗（onUploadFailed）

アップロードエラー発生。

**処理フロー**:
1. 失敗したファイルを `uploads` から削除
2. `pendingUploadsCount` をデクリメント
3. 全アップロード完了時、リストを再取得

### 6-検索実行（onSearch）

検索ボックスにキーワードを入力。

**処理フロー**:
1. 検索キーワードを `term` にセット
2. 選択状態をクリア（`clearSelection()`）
3. sw-media-library コンポーネントが検索を実行

### 7-メディア選択解除（onMediaUnselect）

選択済みメディアの選択を解除。

**処理フロー**:
1. `selectedItems` から該当アイテムを削除
2. サイドバーの表示を更新

### 8-アイテム削除（onItemsDeleted）

メディアまたはフォルダを削除。

**処理フロー**:
1. フォルダ削除の場合、`onMediaFoldersDissolved()` を呼び出し
2. 現在表示中のフォルダが削除された場合、親フォルダへ遷移
3. 選択状態をクリアしてリスト再取得

### 9-言語切替（onChangeLanguage）

管理画面の言語を変更。

**処理フロー**:
1. 選択状態をクリア（`clearSelection()`）
2. リストは自動的に再取得される

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| メディア一覧取得 | media, media_folder | SELECT | メディアとフォルダデータの取得 |
| メディアアップロード | media | INSERT | 新規メディアレコードの作成 |
| メディア情報更新 | media | UPDATE | タイトル、alt等の更新 |
| メディア削除 | media | DELETE | メディアレコードの削除 |
| フォルダ作成 | media_folder | INSERT | 新規フォルダの作成 |
| フォルダ更新 | media_folder | UPDATE | フォルダ名等の更新 |
| フォルダ削除 | media_folder | DELETE | フォルダの削除 |

### テーブル別更新項目詳細

#### media

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | media_folder_id に基づくフィルター | フォルダ配下のメディアを取得 |
| INSERT | file_name, file_extension, file_size, mime_type, media_folder_id | アップロードファイルの情報 | アップロード時 |
| UPDATE | title, alt, custom_fields | 入力値 | メタ情報編集時 |
| DELETE | - | id指定 | メディア削除時 |

#### media_folder

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | parent_id に基づく階層取得 | フォルダ構造の取得 |
| INSERT | name, parent_id, configuration_id | 入力値 | フォルダ作成時 |
| UPDATE | name | 入力値 | 名前変更時 |
| DELETE | - | id指定 | フォルダ削除時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|----------|
| sw-media.index.rootFolderName | 情報 | メディア | ルートフォルダの表示名 |
| - | 成功 | アップロード完了 | アップロード成功時 |
| - | エラー | アップロード失敗 | アップロードエラー時 |

## 例外処理

| 例外ケース | 処理内容 |
|-----------|---------|
| アップロードファイルサイズ超過 | エラー通知を表示、該当ファイルをスキップ |
| 不正なファイル形式 | エラー通知を表示、該当ファイルをスキップ |
| 削除対象が使用中 | 確認ダイアログを表示、強制削除または中止を選択 |
| 表示中フォルダが削除 | 親フォルダへ自動遷移 |
| 権限不足 | 該当機能のボタンを非表示/無効化 |

## 備考

- アップロードはバックグラウンドで処理され、進捗がUIに表示される
- メディアライブラリはモーダルとしても使用可能（sw-media-modal-v2）
- ファイルのサムネイルは自動生成され、画像以外のファイルタイプ用のデフォルトアイコンも用意
- 動画ファイルのサムネイル生成には `video-cover.mixin` を使用
- フォルダ設定により、サムネイル品質やファイル制限を個別に設定可能

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

メディアエンティティとフォルダの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MediaDefinition | `src/Core/Content/Media/MediaDefinition.php` | メディアエンティティの定義 |
| 1-2 | MediaFolderDefinition | `src/Core/Content/Media/Aggregate/MediaFolder/MediaFolderDefinition.php` | フォルダ構造 |

**読解のコツ**: メディアはmedia_folderに属し、media_folder_configurationで設定を継承する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.js | `src/Administration/Resources/app/administration/src/module/sw-media/index.js` | モジュール登録、ルート定義 |

**主要処理フロー**:
1. **35-80行**: `Module.register('sw-media', ...)` でモジュールを登録
2. **47-63行**: ルート定義（index、folderIdパラメータ対応）
3. **66-77行**: ナビゲーション定義

#### Step 3: 画面コンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sw-media-index/index.js | `src/Administration/Resources/app/administration/src/module/sw-media/page/sw-media-index/index.js` | メイン画面コンポーネント |

**主要処理フロー**:
- **33-43行**: `data()` - コンポーネントの状態定義
- **91-104行**: `updateFolder()` - フォルダ情報の更新
- **108-114行**: `onUploadsAdded()` - アップロード開始処理
- **150-153行**: `onSearch()` - 検索処理

#### Step 4: ライブラリコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | sw-media-library/index.js | `src/Administration/Resources/app/administration/src/module/sw-media/component/sw-media-library/index.js` | メディア一覧表示 |

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

```
sw-media-index (Vue Component)
    │
    ├─ createdComponent()
    │      └─ updateFolder()
    │             ├─ mediaFolderRepository.get() [フォルダIDがある場合]
    │             └─ rootFolder作成 [フォルダIDがない場合]
    │
    ├─ onUploadsAdded()
    │      └─ mediaService.runUploads()
    │             └─ Shopware API (POST /api/_action/media/upload)
    │
    ├─ onUploadFinished() / onUploadFailed()
    │      └─ reloadList()
    │             └─ $refs.mediaLibrary.refreshList()
    │
    └─ sw-media-library (子コンポーネント)
           ├─ 検索・フィルター処理
           └─ メディア/フォルダ一覧取得
```

### データフロー図

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

フォルダID ─────────────────▶ sw-media-index Component
                                   │
                                   ├──▶ updateFolder()
                                   │         │
                                   │         ▼
                                   │    mediaFolderRepository.get()
                                   │         │
                                   │         ▼
                                   └──▶ currentFolder/parentFolder

ファイル選択 ───────────────▶ sw-media-index Component
                                   │
                                   ├──▶ onUploadsAdded()
                                   │         │
                                   │         ▼
                                   │    mediaService.runUploads()
                                   │         │
                                   │         ▼
                                   │    Shopware API
                                   │         │
                                   │         ▼
                                   └──▶ メディア一覧更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `src/Administration/Resources/app/administration/src/module/sw-media/index.js` | ソース | モジュール定義 |
| sw-media-index/index.js | `src/Administration/Resources/app/administration/src/module/sw-media/page/sw-media-index/index.js` | ソース | 画面コンポーネント |
| sw-media-index.html.twig | `src/Administration/Resources/app/administration/src/module/sw-media/page/sw-media-index/sw-media-index.html.twig` | テンプレート | 画面テンプレート |
| sw-media-library/index.js | `src/Administration/Resources/app/administration/src/module/sw-media/component/sw-media-library/index.js` | ソース | ライブラリコンポーネント |
| sw-media-sidebar/index.js | `src/Administration/Resources/app/administration/src/module/sw-media/component/sidebar/sw-media-sidebar/index.js` | ソース | サイドバーコンポーネント |
| media-grid-listener.mixin.js | `src/Administration/Resources/app/administration/src/module/sw-media/mixin/media-grid-listener.mixin.js` | ソース | グリッドイベント処理 |
| acl/index.js | `src/Administration/Resources/app/administration/src/module/sw-media/acl/index.js` | ソース | 権限定義 |
