# Shopware Platform コードリーディングガイドライン

## はじめに

このガイドラインは、Shopware Platformのコードベースを効率的に理解するための手引きです。
PHPやSymfonyに精通していないエンジニアでも、段階的に学習できるよう構成されています。

**対象読者:**
- プロジェクトに新規参画するエンジニア
- 他言語からの経験者
- コードレビューを行う担当者

---

## 1. 言語基礎

> このセクションでは、PHP 8.xの基本構文と概念を解説します。

### 1.1 プログラム構造

Shopwareは**PHP 8.2以上**で動作するEコマースプラットフォームです。すべてのPHPファイルはstrict_typesを宣言しています。

**実例** (`src/Core/Content/Product/ProductEntity.php:1-4`)
```php
<?php declare(strict_types=1);

namespace Shopware\Core\Content\Product;
```

- `declare(strict_types=1)`: 厳格な型チェックを有効化
- `namespace`: クラスの名前空間（ディレクトリ構造と対応）

### 1.2 データ型と変数

PHPは動的型付け言語ですが、Shopwareでは型宣言を積極的に使用しています。

**実例** (`src/Core/Content/Product/ProductEntity.php:47-79`)
```php
protected ?string $parentId = null;
protected int $childCount = 0;
protected ?bool $active = null;
protected ?PriceCollection $price = null;
protected string $productNumber;
protected int $stock;
```

**主要な型:**
| 型 | 説明 | 例 |
|---|---|---|
| `string` | 文字列 | `$name = 'Product'` |
| `int` | 整数 | `$stock = 100` |
| `float` | 浮動小数点 | `$weight = 1.5` |
| `bool` | 真偽値 | `$active = true` |
| `array` | 配列 | `$ids = ['id1', 'id2']` |
| `?type` | Nullable型 | `?string` (nullまたは文字列) |

### 1.3 制御構造

**条件分岐の例** (`src/Storefront/Controller/ProductController.php:87-91`)
```php
try {
    $options = json_decode($request->query->get('options', '[]'), true, 512, \JSON_THROW_ON_ERROR);
} catch (\JsonException) {
    $options = [];
}
```

**ループの例** (`src/Core/Framework/Api/Controller/ApiController.php:837-860`)
```php
foreach ($parts as $part) {
    $field = $root->getFields()->get($part['entity']);

    if (!$field) {
        throw ApiException::notExistingRelation($path);
    }
    // ...処理継続
}
```

### 1.4 関数/メソッド定義

Shopwareでは**コンストラクタプロモーション**（PHP 8.0+）を活用しています。

**実例** (`src/Storefront/Controller/ProductController.php:43-51`)
```php
public function __construct(
    private readonly ProductPageLoader $productPageLoader,
    private readonly AbstractFindProductVariantRoute $findVariantRoute,
    private readonly MinimalQuickViewPageLoader $minimalQuickViewPageLoader,
    private readonly AbstractProductReviewSaveRoute $productReviewSaveRoute,
    private readonly SeoUrlPlaceholderHandlerInterface $seoUrlPlaceholderHandler,
    private readonly AbstractProductReviewLoader $productReviewLoader,
) {
}
```

- `private readonly`: プロパティの宣言とコンストラクタ引数を同時に定義
- 依存性注入（DI）パターンを採用

### 1.5 モジュール/インポート

PHPでは`use`文でクラスをインポートします。

**実例** (`src/Core/Content/Product/ProductEntity.php:5-39`)
```php
use Shopware\Core\Checkout\Cart\Delivery\Struct\DeliveryDate;
use Shopware\Core\Content\Category\CategoryCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
use Shopware\Core\Framework\DataAbstractionLayer\EntityCustomFieldsTrait;
use Shopware\Core\Framework\DataAbstractionLayer\EntityIdTrait;
```

- フルパスの名前空間でクラスを指定
- `trait`を使用してコードの再利用が可能

---

## 2. プロジェクト固有の概念

> このセクションでは、Shopware Platform特有の概念を解説します。

### 2.1 フレームワーク固有の概念

#### Symfony Framework基盤

Shopwareは**Symfony 7.4**をベースに構築されています。

**主要なSymfonyコンポーネント:**
- **Dependency Injection**: サービスコンテナによる依存性管理
- **Routing**: URLと処理の対応付け
- **Event Dispatcher**: イベント駆動アーキテクチャ
- **Console**: CLIコマンド基盤

**ルーティング例** (`src/Storefront/Controller/ProductController.php:53-58`)
```php
#[Route(
    path: '/detail/{productId}',
    name: 'frontend.detail.page',
    defaults: [PlatformRequest::ATTRIBUTE_HTTP_CACHE => true],
    methods: [Request::METHOD_GET]
)]
```

#### Data Abstraction Layer (DAL)

ShopwareのDALは、データベース操作を抽象化する独自のORMです。

**主要コンポーネント:**
1. **EntityDefinition**: エンティティのスキーマ定義
2. **Entity**: データモデル
3. **Collection**: エンティティの集合
4. **Repository**: CRUD操作

**EntityDefinition例** (`src/Core/Content/Product/ProductDefinition.php:81-94`)
```php
#[Package('inventory')]
class ProductDefinition extends EntityDefinition
{
    final public const ENTITY_NAME = 'product';

    public function getEntityName(): string
    {
        return self::ENTITY_NAME;
    }

    public function getEntityClass(): string
    {
        return ProductEntity::class;
    }
}
```

### 2.2 プロジェクト独自のパターン

#### Attribute（PHP 8アトリビュート）

ShopwareはPHP 8のアトリビュートを活用しています。

**実例** (`src/Core/Content/Product/ProductDefinition.php:80`)
```php
#[Package('inventory')]
class ProductDefinition extends EntityDefinition
```

- `#[Package('inventory')]`: パッケージ情報のメタデータ
- `#[Route(...)]`: ルーティング定義

#### Field定義パターン

DALのフィールドはフラグで動作を制御します。

**実例** (`src/Core/Content/Product/ProductDefinition.php:141-149`)
```php
(new IdField('id', 'id'))
    ->addFlags(new ApiAware(), new PrimaryKey(), new Required())
    ->setDescription('Unique identity of the product.');

(new FkField('product_manufacturer_id', 'manufacturerId', ProductManufacturerDefinition::class))
    ->addFlags(new ApiAware(), new Inherited());
```

**主要なフラグ:**
| フラグ | 説明 |
|---|---|
| `ApiAware` | API経由でアクセス可能 |
| `PrimaryKey` | 主キー |
| `Required` | 必須フィールド |
| `Inherited` | 継承可能（バリアント商品等） |
| `CascadeDelete` | 関連削除 |

---

## 3. 命名規則

> このセクションでは、プロジェクト全体で使用される命名規則を解説します。

### 3.1 ファイル・ディレクトリ命名

| パターン | 意味 | 例 |
|---------|------|-----|
| `*Definition.php` | DALエンティティ定義 | `ProductDefinition.php` |
| `*Entity.php` | エンティティクラス | `ProductEntity.php` |
| `*Collection.php` | エンティティコレクション | `ProductCollection.php` |
| `*Controller.php` | HTTPコントローラ | `ProductController.php` |
| `*Subscriber.php` | イベントサブスクライバ | `ProductSubscriber.php` |
| `*Route.php` | Store API ルート | `FindProductVariantRoute.php` |
| `*Loader.php` | データローダー | `ProductPageLoader.php` |
| `Aggregate/*` | 関連エンティティ | `Aggregate/ProductMedia/` |

### 3.2 クラス・関数・変数命名

| プレフィックス/サフィックス | 意味 | 例 |
|---------------------------|------|-----|
| `Abstract*` | 抽象クラス | `AbstractController` |
| `*Interface` | インターフェース | `SeoUrlPlaceholderHandlerInterface` |
| `*Trait` | トレイト | `EntityIdTrait` |
| `*Exception` | 例外クラス | `ProductNotFoundException` |
| `*Event` | イベントクラス | `ProductPageLoadedEvent` |
| `*Hook` | App Script フック | `ProductPageLoadedHook` |
| `get*` | ゲッター | `getProductNumber()` |
| `set*` | セッター | `setProductNumber()` |
| `is*` / `has*` | 真偽値取得 | `isCloseout()`, `hasStock()` |

### 3.3 プログラム分類一覧

| 分類 | ディレクトリ | 説明 |
|-----|-------------|------|
| Core Bundle | `src/Core/` | コアビジネスロジック |
| Administration Bundle | `src/Administration/` | 管理画面 |
| Storefront Bundle | `src/Storefront/` | フロントエンド |
| Elasticsearch Bundle | `src/Elasticsearch/` | 検索機能 |

---

## 4. ディレクトリ構造

> このセクションでは、プロジェクトのディレクトリ構造を解説します。

```
shopware-trunk/
├── bin/                    # CLIスクリプト
├── config/                 # 設定ファイル
│   ├── bundles.php        # バンドル登録
│   └── packages/          # パッケージ設定
├── custom/                 # カスタムプラグイン
│   └── plugins/           # プラグイン配置場所
├── public/                 # Webルート
├── src/                    # ソースコード
│   ├── Administration/    # 管理画面バンドル
│   ├── Core/              # コアバンドル
│   │   ├── Checkout/     # チェックアウト機能
│   │   ├── Content/      # コンテンツ管理
│   │   ├── Framework/    # フレームワーク基盤
│   │   ├── System/       # システム設定
│   │   └── ...
│   ├── Elasticsearch/     # 検索バンドル
│   └── Storefront/        # フロントエンドバンドル
├── docs/                   # ドキュメント
└── tests/                  # テストコード
```

### 各ディレクトリの役割

| ディレクトリ | 役割 | 主要ファイル |
|-------------|------|-------------|
| `src/Core/Framework/` | フレームワーク基盤 | `Api/`, `DataAbstractionLayer/`, `Plugin/` |
| `src/Core/Content/` | コンテンツ管理 | `Product/`, `Category/`, `Media/` |
| `src/Core/Checkout/` | チェックアウト | `Cart/`, `Order/`, `Customer/` |
| `src/Core/System/` | システム設定 | `SalesChannel/`, `Tax/`, `Currency/` |
| `src/Storefront/Controller/` | フロントエンドコントローラ | `ProductController.php`, `CheckoutController.php` |
| `src/Storefront/Page/` | ページ構築 | `Product/`, `Checkout/`, `Account/` |
| `src/Administration/Controller/` | 管理画面API | `AdminSearchController.php` |

---

## 5. アーキテクチャ

> このセクションでは、プロジェクトのアーキテクチャパターンを解説します。

### 5.1 全体アーキテクチャ

Shopwareは**モジュラーモノリス**アーキテクチャを採用しています。

```mermaid
graph TB
    subgraph "Presentation Layer"
        SF[Storefront]
        AD[Administration]
        API[API]
    end

    subgraph "Application Layer"
        SA[Store API Routes]
        AA[Admin API Routes]
        CMD[Console Commands]
    end

    subgraph "Domain Layer"
        CO[Core/Content]
        CH[Core/Checkout]
        SY[Core/System]
        FW[Core/Framework]
    end

    subgraph "Infrastructure Layer"
        DAL[Data Abstraction Layer]
        MSG[Message Queue]
        CACHE[Cache]
        ES[Elasticsearch]
    end

    subgraph "Data Layer"
        DB[(MySQL/MariaDB)]
    end

    SF --> SA
    AD --> AA
    API --> SA
    API --> AA

    SA --> CO
    SA --> CH
    AA --> CO
    AA --> CH
    AA --> SY
    CMD --> FW

    CO --> DAL
    CH --> DAL
    SY --> DAL

    DAL --> DB
    DAL --> CACHE
    DAL --> ES
```

### 5.2 レイヤー構成

| レイヤー | 責務 | 代表的なファイル |
|---------|------|-----------------|
| Presentation | UI表示・テンプレート | `StorefrontController.php`, `*.html.twig` |
| Application | ユースケース実装 | `*Route.php`, `*Loader.php` |
| Domain | ビジネスロジック | `*Definition.php`, `*Entity.php` |
| Infrastructure | 技術的関心事 | `*Repository.php`, `*Subscriber.php` |

### 5.3 データフロー

```
HTTP Request
    ↓
Storefront/Administration Controller
    ↓
Store API Route / Page Loader
    ↓
Entity Repository (DAL)
    ↓
MySQL/MariaDB
    ↓
Entity/Collection
    ↓
Response (JSON/Twig Template)
```

---

## 6. 主要コンポーネント

> このセクションでは、主要なコンポーネントとその連携を解説します。

### 6.1 エントリーポイント

アプリケーションのエントリーポイントは`public/index.php`ですが、実際の処理はバンドルで構成されます。

**バンドル登録** (`config/bundles.php:5-21`)
```php
$bundles = [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    Shopware\Core\Framework\Framework::class => ['all' => true],
    Shopware\Core\System\System::class => ['all' => true],
    Shopware\Core\Content\Content::class => ['all' => true],
    Shopware\Core\Checkout\Checkout::class => ['all' => true],
    Shopware\Administration\Administration::class => ['all' => true],
    Shopware\Storefront\Storefront::class => ['all' => true],
    Shopware\Elasticsearch\Elasticsearch::class => ['all' => true],
];
```

### 6.2 ビジネスロジック

ビジネスロジックは主に**Store API Routes**と**Subscribers**で実装されます。

**Store API Route例** (`src/Core/Content/Product/SalesChannel/FindVariant/AbstractFindProductVariantRoute.php`)
- 商品バリアント検索ロジック
- Storefrontから呼び出される

**Subscriber例** (`src/Core/Content/Product/Subscriber/ProductSubscriber.php`)
- エンティティのライフサイクルイベントを処理
- 自動計算フィールドの更新など

### 6.3 データアクセス

**EntityRepository**パターンでデータアクセスを行います。

**Repository使用例** (`src/Core/Framework/Api/Controller/ApiController.php:92-96`)
```php
$eventContainer = $context->scope(Context::CRUD_API_SCOPE, function (Context $context) use ($definition, $id, $behavior): EntityWrittenContainerEvent {
    $entityRepo = $this->definitionRegistry->getRepository($definition->getEntityName());

    return $entityRepo->clone($id, $context, null, $behavior);
});
```

**主要なRepository操作:**
- `search(Criteria $criteria, Context $context)`: 検索
- `create(array $data, Context $context)`: 作成
- `update(array $data, Context $context)`: 更新
- `delete(array $ids, Context $context)`: 削除
- `clone($id, Context $context)`: 複製

### 6.4 ユーティリティ/共通機能

**Context**: 実行コンテキスト（認証情報、言語、通貨等）

```php
$context->getVersionId();           // バージョンID
$context->getLanguageIdChain();     // 言語フォールバックチェーン
$context->getCurrencyId();          // 通貨ID
$context->isAllowed($privilege);    // 権限チェック
```

**Criteria**: 検索条件ビルダー

```php
$criteria = new Criteria();
$criteria->setIds(['id1', 'id2']);
$criteria->addFilter(new EqualsFilter('active', true));
$criteria->addAssociation('manufacturer');
```

---

## 7. よく使われるパターン

> このセクションでは、コード内で頻出するパターンを解説します。

### パターン一覧

| パターン | 説明 | 出現頻度 | 代表的なファイル |
|---------|------|---------|-----------------|
| Entity/Definition/Collection | DALエンティティパターン | 高 | `ProductDefinition.php` |
| Store API Route | API実装パターン | 高 | `*Route.php` |
| Event Subscriber | イベント処理パターン | 高 | `*Subscriber.php` |
| Page Loader | ページ構築パターン | 中 | `ProductPageLoader.php` |
| Criteria Builder | 検索条件構築パターン | 高 | 各所 |

### 各パターンの詳細

#### パターン1: Entity/Definition/Collection

**目的:** データモデルの定義と操作

**実装例:**
```php
// ファイル: src/Core/Content/Product/ProductDefinition.php:138-141
protected function defineFields(): FieldCollection
{
    $fields = new FieldCollection([
        (new IdField('id', 'id'))->addFlags(new ApiAware(), new PrimaryKey(), new Required()),
        // ...他のフィールド定義
    ]);
}
```

**解説:**
- `EntityDefinition`: フィールド構造を定義
- `Entity`: データを保持するPOPO
- `EntityCollection`: 複数エンティティの集合

#### パターン2: Store API Route

**目的:** フロントエンド向けAPI提供

**実装例:**
```php
// ファイル: src/Storefront/Controller/ProductController.php:59-72
#[Route(path: '/detail/{productId}', name: 'frontend.detail.page', methods: ['GET'])]
public function index(SalesChannelContext $context, Request $request): Response
{
    $page = $this->productPageLoader->load($request, $context);
    $this->hook(new ProductPageLoadedHook($page, $context));

    return $this->renderStorefront('@Storefront/storefront/page/content/product-detail.html.twig', [
        'page' => $page,
    ]);
}
```

**解説:**
- `SalesChannelContext`: 販売チャネル固有のコンテキスト
- PageLoaderでデータ取得、Hookで拡張ポイント提供

#### パターン3: Event Subscriber

**目的:** イベント駆動でのロジック実装

**実装例:**
```php
// パターン例
class ProductSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            ProductEvents::PRODUCT_WRITTEN_EVENT => 'onProductWritten',
        ];
    }

    public function onProductWritten(EntityWrittenEvent $event): void
    {
        // 商品更新時の処理
    }
}
```

---

## 8. 業務フロー追跡の実践例

> このセクションでは、実際の業務フローをコードで追跡する方法を解説します。

### 8.1 フロー追跡の基本手順

1. エントリーポイントを特定
2. 処理の流れを追跡（呼び出し関係を追う）
3. データの変換を確認
4. 最終的な出力を確認

### 8.2 フロー追跡の実例

#### 例1: 商品詳細ページ表示

**概要:** ユーザーが商品詳細ページにアクセスした際の処理フロー

**処理フロー:**
```
HTTP GET /detail/{productId}
    → ProductController::index()
    → ProductPageLoader::load()
    → ProductRepository::search()
    → Twig Template Rendering
    → HTTP Response
```

**詳細な追跡:**

1. **ルーティング** (`src/Storefront/Controller/ProductController.php:53-58`)
   ```php
   #[Route(
       path: '/detail/{productId}',
       name: 'frontend.detail.page',
       defaults: [PlatformRequest::ATTRIBUTE_HTTP_CACHE => true],
       methods: [Request::METHOD_GET]
   )]
   ```

2. **コントローラ処理** (`src/Storefront/Controller/ProductController.php:59-72`)
   ```php
   public function index(SalesChannelContext $context, Request $request): Response
   {
       $page = $this->productPageLoader->load($request, $context);
       $this->hook(new ProductPageLoadedHook($page, $context));

       return $this->renderStorefront(
           '@Storefront/storefront/page/content/product-detail.html.twig',
           ['page' => $page, 'redirectTo' => 'frontend.detail.page']
       );
   }
   ```

3. **テンプレート出力** (`src/Storefront/Controller/StorefrontController.php:67-110`)
   ```php
   protected function renderStorefront(string $view, array $parameters = []): Response
   {
       // ...イベント発火、SEO URL置換処理
       $response = Profiler::trace('twig-rendering', fn () => $this->render($view, $event->getParameters(), new Response()));
       // ...
       return $response;
   }
   ```

### 8.3 フロー追跡チェックリスト

- [ ] エントリーポイント（Controller/Route）を特定したか
- [ ] 呼び出し関係（PageLoader, Route, Repository）を把握したか
- [ ] データの変換ポイント（Entity → ViewModel）を確認したか
- [ ] エラーハンドリングを確認したか
- [ ] 最終的な出力（JSON/HTML）を確認したか

---

## 9. 設計書の参照順序

> このセクションでは、プロジェクト理解のための設計書参照順序を案内します。

### 9.1 目的別ロードマップ

#### 全体像を把握したい場合
1. `docs/code-to-docs/README.md` - プロジェクト概要
2. `docs/code-to-docs/アーキテクチャ設計書/` - 全体構造
3. `docs/code-to-docs/機能一覧/` - 機能カタログ

#### 特定機能を理解したい場合
1. `docs/code-to-docs/機能一覧/` - 機能の概要確認
2. `docs/code-to-docs/機能設計書/` - 詳細設計
3. 関連ソースコード（Controller → Route → Repository）

#### 改修作業を行う場合
1. `docs/code-to-docs/画面設計書/` - 対象画面の仕様
2. `docs/code-to-docs/API設計書/` - API仕様
3. `docs/code-to-docs/単体テストケース一覧/` - テストケース確認

### 9.2 ドキュメント一覧

| ドキュメント | 概要 | 参照タイミング |
|-------------|------|---------------|
| README.md | プロジェクト概要 | 初回参照 |
| アーキテクチャ設計書 | 全体構造 | 全体把握時 |
| 機能一覧 | 機能カタログ | 機能検索時 |
| 機能設計書 | 詳細設計 | 実装時 |
| 画面設計書 | UI仕様 | フロント改修時 |
| API設計書 | API仕様 | API連携時 |
| データベース設計書 | DB構造 | データ操作時 |
| テストケース一覧 | テスト項目 | テスト実施時 |

---

## 10. トラブルシューティング

> このセクションでは、コードリーディング時によくある問題と解決法を解説します。

### よくある疑問と回答

#### Q: Entityのフィールドがどこで定義されているかわからない
A: `*Definition.php`の`defineFields()`メソッドを参照してください。例: `ProductDefinition::defineFields()`

#### Q: 特定のAPIエンドポイントの処理を見つけたい
A: `#[Route(path: '...')]`アトリビュートでgrepするか、`bin/console debug:router`コマンドでルート一覧を確認してください。

#### Q: イベントがどこで発火されているか知りたい
A: `EventDispatcher`の`dispatch()`呼び出しを検索、または`bin/console debug:event-dispatcher`でリスナー一覧を確認してください。

#### Q: DALのクエリがどのようなSQLになるか確認したい
A: Symfony Profilerを有効化し、Doctrine Panel でSQLクエリを確認してください。

### デバッグのヒント

1. **Symfony Profiler**: 開発モードで`/_profiler`にアクセス
2. **ログファイル**: `var/log/`配下のログを確認
3. **bin/console**: 各種デバッグコマンドを活用
   - `debug:router` - ルート一覧
   - `debug:container` - サービス一覧
   - `debug:event-dispatcher` - イベントリスナー一覧

---

## 付録

### A. 用語集

| 用語 | 説明 |
|-----|------|
| DAL | Data Abstraction Layer - Shopware独自のORM |
| SalesChannel | 販売チャネル（Webショップ、API等） |
| Context | 実行コンテキスト（認証、言語、通貨等） |
| Criteria | 検索条件ビルダー |
| Entity | データモデルオブジェクト |
| Definition | エンティティのスキーマ定義 |
| Collection | エンティティの集合 |
| Repository | データアクセスオブジェクト |
| Subscriber | イベントリスナー実装クラス |
| Route | API/Webルート定義 |
| PageLoader | ページデータ構築クラス |
| Hook | App Script拡張ポイント |

### B. ファイル一覧

| ファイル/ディレクトリ | 説明 | 主な内容 |
|---------------------|------|---------|
| `src/Core/Framework/DataAbstractionLayer/` | DAL基盤 | Entity, Definition, Repository |
| `src/Core/Content/Product/` | 商品機能 | ProductEntity, ProductDefinition |
| `src/Core/Checkout/Cart/` | カート機能 | Cart, LineItem |
| `src/Core/Checkout/Order/` | 注文機能 | Order, OrderState |
| `src/Storefront/Controller/` | フロントコントローラ | 各種ページコントローラ |
| `src/Storefront/Page/` | ページ構築 | PageLoader, Page |
| `src/Administration/Controller/` | 管理画面API | Admin API コントローラ |

### C. 参考資料

- [Shopware Developer Documentation](https://developer.shopware.com)
- [Symfony Documentation](https://symfony.com/doc/current/index.html)
- [PHP Documentation](https://www.php.net/docs.php)
- [Twig Template Engine](https://twig.symfony.com/doc/)
