Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
a92a191
feat: EC-CUBE 4.4への対応
ttokoro20240902 Jun 24, 2026
e647b16
test: Docker Compose によるテスト環境を追加
ttokoro20240902 Jun 24, 2026
516760c
fix: Docker 環境を dev で起動し管理画面にログインできるようにする
ttokoro20240902 Jun 24, 2026
151ddd5
chore: テスト/Docker 一時成果物を .gitignore に追加
ttokoro20240902 Jun 24, 2026
d094ccb
chore: 静的解析・整形ツール設定と CLAUDE.md を追加
ttokoro20240902 Jun 24, 2026
b0a5970
refactor: rector/php-cs-fixer を適用し phpstan baseline を追加
ttokoro20240902 Jun 24, 2026
e84eb32
ci: composer install で ext-redis の platform 要件を無視する
ttokoro20240902 Jun 24, 2026
52f6e97
ci: phpunit 前に cache:warmup してプラグインのルート未登録を防ぐ
ttokoro20240902 Jun 24, 2026
13c6a1e
refactor: phpstan level 6 を baseline なしでクリアする
ttokoro20240902 Jun 25, 2026
49f1c1a
ci: 配布パッケージから開発・テスト用ファイルを除外する
ttokoro20240902 Jun 25, 2026
18fdcf6
ci: 静的解析(phpstan/rector/php-cs-fixer)の専用ジョブを追加
ttokoro20240902 Jun 25, 2026
e10f559
ci: 静的解析ジョブで fixtures:load を実行し、PHP 8.5 を対象に追加
ttokoro20240902 Jun 25, 2026
cd21c6d
refactor: PluginManager::\$originBlock を readonly にする
ttokoro20240902 Jun 25, 2026
db885ec
fix(docker): dev環境でおすすめ管理ページが初回ロードで404になる問題に対応
ttokoro20240902 Jun 25, 2026
78dde65
fix(admin): おすすめ商品の並び替えに POST 制限と CSRF トークン検証を追加
ttokoro20240902 Aug 4, 2026
92b0834
chore: レビュー指摘に対応(デッドコード削除・ツール設定・CI 整合)
ttokoro20240902 Aug 4, 2026
5817ef4
ci: 静的解析ジョブの SQLite セットアップで doctrine:database:create を実行しない
ttokoro20240902 Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 97 additions & 36 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI for Recommend42
name: CI for Recommend44
on:
push:
branches:
Expand All @@ -17,55 +17,34 @@ on:
jobs:
run-on-linux:
name: Run on Linux
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
eccube_version: [ '4.2', '4.3' ]
php: [ '7.4', '8.0', '8.1', '8.2', '8.3']
db: [ 'mysql', 'mysql8', 'pgsql' ]
plugin_code: [ 'Recommend42' ]
eccube_version: [ '4.4' ]
php: [ '8.2', '8.3', '8.4', '8.5' ]
db: [ 'mysql8', 'pgsql' ]
plugin_code: [ 'Recommend44' ]
include:
- db: mysql
database_url: mysql://root:password@127.0.0.1:3306/eccube_db
database_server_version: 5.7
database_charset: utf8mb4
- db: mysql8
database_url: mysql://root:password@127.0.0.1:3308/eccube_db
database_server_version: 8
database_charset: utf8mb4
- db: pgsql
database_url: postgres://postgres:password@127.0.0.1:5432/eccube_db
database_server_version: 14
database_server_version: 18
database_charset: utf8
exclude:
- eccube_version: 4.2
php: 8.2
- eccube_version: 4.2
php: 8.3
- eccube_version: 4.3
php: 7.4
- eccube_version: 4.3
php: 8.0
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: ${{ matrix.dbname }}
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
mysql8:
image: mysql:8
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: ${{ matrix.dbname }}
ports:
- 3308:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
postgres:
image: postgres:14
image: postgres:18
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
Expand All @@ -81,7 +60,7 @@ jobs:
- 1025:1025
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Setup PHP
uses: nanasess/setup-php@master
Expand All @@ -94,7 +73,7 @@ jobs:
run: |
tar cvzf ${GITHUB_WORKSPACE}/${PLUGIN_CODE}.tar.gz ./*
- name: Checkout EC-CUBE
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
repository: 'EC-CUBE/ec-cube'
ref: ${{ matrix.eccube_version }}
Expand All @@ -103,16 +82,18 @@ jobs:
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v1
echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install to composer
working-directory: 'ec-cube'
run: composer install --no-interaction -o --apcu-autoloader
# Symfony 7.4 の symfony/cache が ext-redis <6.1 と衝突するが、ランナーには
# 古い php-redis(5.3.7) が入っている。本プラグイン/本体テストは redis 未使用のため無視する。
run: composer install --no-interaction -o --apcu-autoloader --ignore-platform-req=ext-redis

- name: Setup EC-CUBE
env:
Expand All @@ -137,8 +118,8 @@ jobs:
working-directory: 'ec-cube'
run: |
bin/console eccube:plugin:install --code=${PLUGIN_CODE} --path=${GITHUB_WORKSPACE}/${PLUGIN_CODE}.tar.gz
bin/console cache:clear --no-warmup
bin/console eccube:plugin:enable --code=${PLUGIN_CODE}
bin/console cache:clear --no-warmup
- name: Run PHPUnit
env:
APP_ENV: 'test'
Expand All @@ -149,7 +130,11 @@ jobs:
PLUGIN_CODE: ${{ matrix.plugin_code }}
working-directory: 'ec-cube'
run: |
# 有効化したプラグインのルーティングはコンテナのコンパイル時に確定する。
# phpunit プロセスでの遅延コンパイルに任せると DB/タイミングで有効プラグイン一覧を
# 取りこぼし RouteNotFound になることがあるため、クリーンなプロセスで warmup して確定させる。
bin/console cache:clear --no-warmup
bin/console cache:warmup
./vendor/bin/phpunit -c app/Plugin/${PLUGIN_CODE}/phpunit.xml.dist app/Plugin/${PLUGIN_CODE}/Tests

- name: Disable Plugin
Expand All @@ -173,3 +158,79 @@ jobs:
PLUGIN_CODE: ${{ matrix.plugin_code }}
working-directory: 'ec-cube'
run: bin/console eccube:plugin:uninstall --code=${PLUGIN_CODE}

static-analysis:
name: Static Analysis
runs-on: ubuntu-24.04
# 静的解析は DB 種別に依存しないため、SQLite 1 構成で一度だけ実行する。
# (php-cs-fixer / rector は DB 不要だが、phpstan は objectManagerLoader が
# カーネルを起動し EccubeExtension が dtb_plugin を読むため本体+DBが必要)
env:
PLUGIN_CODE: Recommend44
APP_ENV: 'test'
APP_DEBUG: 0
DATABASE_URL: 'sqlite:///var/eccube.db'
DATABASE_SERVER_VERSION: 3
DATABASE_CHARSET: 'utf8'
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: nanasess/setup-php@master
with:
php-version: '8.5'

- name: Archive Plugin
run: |
tar cvzf ${GITHUB_WORKSPACE}/${PLUGIN_CODE}.tar.gz ./*
- name: Checkout EC-CUBE
uses: actions/checkout@v4
with:
repository: 'EC-CUBE/ec-cube'
ref: '4.4'
path: 'ec-cube'

- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install to composer
working-directory: 'ec-cube'
run: composer install --no-interaction -o --apcu-autoloader --ignore-platform-req=ext-redis

- name: Setup EC-CUBE
working-directory: 'ec-cube'
run: |
# SQLite では doctrine:database:create が
# 「SQLitePlatform::getCreateDatabaseSQL is not supported by platform」で失敗する。
# DB ファイルは schema:create が生成するため実行しない(本体 4.4 の unit-test.yml と同じ扱い)
bin/console doctrine:schema:create
# プラグイン有効化時に DeviceType 等のマスタデータを参照するため fixtures を投入する
bin/console eccube:fixtures:load
- name: Setup Plugin
working-directory: 'ec-cube'
run: |
bin/console eccube:plugin:install --code=${PLUGIN_CODE} --path=${GITHUB_WORKSPACE}/${PLUGIN_CODE}.tar.gz
bin/console eccube:plugin:enable --code=${PLUGIN_CODE}
bin/console cache:clear --no-warmup

- name: Run php-cs-fixer
working-directory: 'ec-cube'
run: ./vendor/bin/php-cs-fixer fix --config=app/Plugin/${PLUGIN_CODE}/Resource/.php-cs-fixer.dist.php --dry-run --diff

- name: Run Rector
working-directory: 'ec-cube'
run: ./vendor/bin/rector process --config=app/Plugin/${PLUGIN_CODE}/Resource/rector.php --dry-run

- name: Run PHPStan
working-directory: 'ec-cube'
run: |
bin/console cache:clear --no-warmup
./vendor/bin/phpstan analyse -c app/Plugin/${PLUGIN_CODE}/phpstan.neon.dist --no-progress
6 changes: 5 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ on:
jobs:
deploy:
name: Build
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Packaging
working-directory: ../
run: |
rm -rf $GITHUB_WORKSPACE/.github

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] このファイルだけ runs-on: ubuntu-22.04 のまま残っています(8 行目)

main.yml は 2 ジョブとも ubuntu-24.04 に更新されていますが、release.yml は 22.04 のままです。配布パッケージ生成は tar と rm しか使わないため今すぐ壊れはしませんが、ランナーイメージの世代を揃えておかないと将来 22.04 の提供終了時にリリースだけ落ちます。

(8 行目は差分範囲外のため、本 PR で触っているこの行にコメントしています。別 PR での対応でも構いません。)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

別 PR でも構わないとのことでしたが、main.yml を 24.04 にしたのが本 PR なので、こちらで ubuntu-24.04 に揃えました(92b0834)。

# 開発・テスト用ファイルは配布パッケージに含めない
rm -rf $GITHUB_WORKSPACE/docker-compose*.yml $GITHUB_WORKSPACE/dockerbuild
rm -f $GITHUB_WORKSPACE/CLAUDE.md $GITHUB_WORKSPACE/phpstan.neon.dist
rm -f $GITHUB_WORKSPACE/Resource/rector.php "$GITHUB_WORKSPACE/Resource/.php-cs-fixer.dist.php"
find $GITHUB_WORKSPACE -name "dummy" -delete
find $GITHUB_WORKSPACE -name ".git*" -and ! -name ".gitkeep" -print0 | xargs -0 rm -rf
chmod -R o+w $GITHUB_WORKSPACE
Expand Down
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
composer.phar
/vendor/

# 本プラグインはライブラリ (type: eccube-plugin) のため composer.lock はコミットしない
# https://getcomposer.org/doc/02-libraries.md#lock-file
composer.lock

# 静的解析・整形ツールのキャッシュ
.php-cs-fixer.cache

# Playwright MCP の一時生成物
/.playwright-mcp/
106 changes: 106 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## このリポジトリについて

EC-CUBE 4 系の**おすすめ商品管理プラグイン**。フロントにおすすめ商品の一覧ブロックを追加し、管理画面からおすすめ商品の登録・編集・削除・並び替えを行える。

- 管理画面: 「コンテンツ管理 → おすすめ管理」(`Controller/RecommendController.php`、`Controller/RecommendSearchModelController.php`)
- フロント: おすすめ商品ブロック(`Resource/template/Block/recommend_product_block.twig`)

プラグインコードは `Recommend44`、Composer パッケージ名は `ec-cube/recommend44`。コード中の Twig 名前空間(`@Recommend44`)・クラス名前空間(`Plugin\Recommend44\...`)はすべて `Recommend44` 接頭辞を使う。

### ブランチ運用

ブランチ名が対応する EC-CUBE 本体バージョンを表す(`4.0` / `4.2` / `4.4` など)。`4.2` がデフォルトブランチ。`4.2` ブランチは EC-CUBE 4.2/4.3(`Recommend42`)に対応し、`4.4` ブランチは EC-CUBE 4.4(Symfony 7.4 / Doctrine ORM 3.0 / PHP 8.2+、`Recommend44`)に対応する。**4.3 と 4.4 はアノテーション必須/属性必須・ORM 2/3 の違いで非互換**のため、別ブランチで保守する。

## 開発・テストコマンド

このプラグイン単体では動作せず、**EC-CUBE 本体に組み込んだ状態**で開発・テストする。本体の取得・インストール・プラグイン有効化は `docker-compose.dev.yml` の entrypoint が自動実行する。

```bash
# 開発環境 (SQLite) の起動 — 本体インストール・プラグイン有効化まで自動
export COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml
docker compose up -d --wait

# MySQL / PostgreSQL で起動する場合
export COMPOSE_FILE=docker-compose.yml:docker-compose.mysql.yml:docker-compose.dev.yml
export COMPOSE_FILE=docker-compose.yml:docker-compose.pgsql.yml:docker-compose.dev.yml

# PHP バージョン切り替え(8.2-apache-4.4 / 8.3-apache-4.4 / 8.4-apache-4.4 / 8.5-apache-4.4)
TAG=8.3-apache-4.4 docker compose up -d --wait
```

起動後は管理画面 `http://localhost:8080/admin`(`admin` / `password`)、メールは MailCatcher `http://localhost:1080`。

### PHPUnit

テストは `Tests/` 配下の PHPUnit(`Tests/Repository/`・`Tests/Web/`)。`phpunit.xml.dist` により `APP_ENV=test` で実行される。

```bash
docker compose exec ec-cube bash -lc \
"APP_ENV=test bin/console cache:clear --no-warmup && ./vendor/bin/phpunit -c app/Plugin/Recommend44/phpunit.xml.dist app/Plugin/Recommend44/Tests"
```

**注意(コンパイル済みキャッシュ)**: 有効化したプラグインのルーティングは、コンテナのコンパイル時に `dtb_plugin` を読む `EccubeExtension` で確定する。有効化直後の test キャッシュには反映されていないことがあるため、**PHPUnit 実行前に `APP_ENV=test` でキャッシュをクリアする**。これを怠るとコントローラのルートが `RouteNotFoundException` になる。

### 静的解析・整形(任意)

EC-CUBE 本体(コンテナ内)の vendor を使って実行する。

```bash
# php-cs-fixer
docker compose exec ec-cube bash -lc \
"cd app/Plugin/Recommend44 && /var/www/html/vendor/bin/php-cs-fixer fix --config=Resource/.php-cs-fixer.dist.php --dry-run --diff"

# rector(再移行・検証用)
docker compose exec ec-cube bash -lc \
"cd app/Plugin/Recommend44 && /var/www/html/vendor/bin/rector process --config=Resource/rector.php --dry-run"

# phpstan
docker compose exec ec-cube bash -lc \
"cd app/Plugin/Recommend44 && /var/www/html/vendor/bin/phpstan analyse"
```

phpstan は level 6 で **baseline なし・エラーゼロ**。Repository は `@extends AbstractRepository<RecommendProduct>` を付与して `find()` 等の戻り値型を確定させている。新規コードもこの水準を維持すること。

## アーキテクチャ

- **Entity** (`Entity/RecommendProduct.php`): `plg_recommend_product` テーブル。`#[ORM\*]` 属性 + 型付きプロパティ。`Product` との OneToOne、`visible` で論理削除、`sort_no` で並び順。
- **Controller** (`Controller/`): `#[Route]`/`#[Template]` 属性。一覧・新規/編集・削除・並び替え(Ajax)・商品検索モーダル。
- **Form** (`Form/Type/RecommendProductType.php`): おすすめ商品の入力フォーム。`EntityToIdTransformer` で `Product` を ID 連携。
- **Repository** (`Repository/RecommendProductRepository.php`): 一覧取得・最大 sort_no・並び替えトランザクション等。
- **Service** (`Service/RecommendService.php`): 登録/更新のドメインロジック。
- **PluginManager** (`PluginManager.php`): 有効化時におすすめ商品ブロックを配置、無効化/アンインストールで除去。全メソッド `: void`。
- **Nav** (`Nav.php`): 管理画面メニューにおすすめ管理を追加。

## 規約・移行メモ

### 開発ツール設定ファイルは `Resource/` 配下に置く(rector.php / .php-cs-fixer.dist.php)

`rector.php` や `.php-cs-fixer.dist.php` を**プラグインのルート直下に置いてはならない**。`Resource/` 配下に置く。

**理由**: EC-CUBE 本体の `config/eccube/services.yaml` がプラグインを丸ごと PSR-4 サービス検出対象として読み込む:

```yaml
Plugin\:
resource: '../../../app/Plugin/*'
exclude: '../../../app/Plugin/*/{Entity,Resource,ServiceProvider,Tests,Codeception,DoctrineMigrations}'
```

ルート直下の `*.php` は「サービスクラス」として読み込まれるため、`rector.php` を置くと Symfony が `Plugin\Recommend44\rector` クラスを期待し、見つからず **EC-CUBE 全体が 500 エラー**になる。`exclude` に `Resource` が含まれるため `Resource/` 配下なら衝突しない。`phpstan.neon.dist` は `.php` ではないためルートに置ける。

**将来「本体に合わせてルートへ戻す」とリグレッションするため、この配置を変更しないこと。**

### docker 環境は `APP_ENV=dev` で起動する

ブラウザログインには実セッション(`session.storage.factory.native`)が必要。`APP_ENV=test` ではモックストレージ(`mock_file`)になりログインできない。また EC-CUBE 4.4(Symfony 7)は既定 `cookie_samesite: none` のため、HTTP 環境では `dockerbuild/dev-framework.yaml`(`cookie_secure:false` / `cookie_samesite:lax`)を `app/config/eccube/packages/dev/framework.yaml` に重ねて回避している。

### 有効化後は `cache:clear` を 2 回流す(ルート/Nav の確定)

`eccube:plugin:enable` 直後の 1 回の `cache:clear` だけでは、プラグインのルーティング(おすすめ管理ページ `plugin_recommend_list`)と Nav メニューが確定せず、**初回ロードで `/admin/plugin/recommend` が 404** になることを確認した。enable とは別パスで `cache:clear` をもう一度実行すると確定する(`enable` が内部で行うキャッシュ再生成と競合するためと見られる)。そのため `docker-compose.dev.yml` の entrypoint は有効化後に `bin/console cache:clear` を **2 回** 実行する。手動でプラグインを再有効化した場合も同様に行うこと。

### プラグインの導入方法(tar + plugin:install)

`docker-compose.dev.yml` はマウントしたプラグインを `./*` で tar 化し `eccube:plugin:install --path` で導入する。`eccube:composer:require` はパッケージ API(`extra.id`)を要求するため path プラグインでは使えない。また **`PharData` は先頭の `./` エントリで展開に失敗する**ため、プラグインディレクトリ内で `./*` を対象に tar 化する(`-C dir .` は不可)。
Loading
Loading