From 12dbe2ec17f6077c868e5f278dd010b69c3915b8 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 20 Sep 2026 11:06:23 +0900 Subject: [PATCH 01/10] Advertise product-corpus on Stock so an admin edit reaches it (#127) Every writer of stock (product_update.sql, product_create.sql, product_copy.sql) announces product-corpus through ProductCacheInvalidator::invalidateCorpus(), but Stock only carried its own URI tag. An admin stock edit left app://self/product/stock?productCode=... serving the stale value for up to 30s, and App\Product's rebuild after its own purge still re-embedded that stale Stock read because the child's cache was never invalidated. Stock now sets Header::SURROGATE_KEY to Products::SURROGATE_KEY, the same tag every other writer of the corpus already announces. Added a gated oracle flow (product-stock-corpus) that purges product-corpus and asserts Stock's own entry falls with it - it reproduces violations 4/5 before this fix and passes after. Registered in verify-all.sh's flow loop so the gate runs it going forward. --- src/Resource/App/Product/Stock.php | 8 +++++++- var/loop/verify-all.sh | 2 +- var/loop/verify-cache.php | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Resource/App/Product/Stock.php b/src/Resource/App/Product/Stock.php index 955e77cfd..fc7ac088d 100644 --- a/src/Resource/App/Product/Stock.php +++ b/src/Resource/App/Product/Stock.php @@ -4,11 +4,13 @@ namespace MyVendor\BeMart\Resource\App\Product; +use BEAR\QueryRepository\Header; use BEAR\RepositoryModule\Annotation\Cacheable; use BEAR\Resource\Code; use BEAR\Resource\ResourceObject; use MyVendor\BeMart\Be\Reason\Entity\ProductEntity; use MyVendor\BeMart\Be\Reason\Query\ProductQueryInterface; +use MyVendor\BeMart\Resource\App\Products; /** * The part of a product that moves: how many are left @@ -17,7 +19,10 @@ * them in one cache entry means the slow-moving part is thrown away at the speed of the fast one. * This resource carries the fast part alone, so `app://self/product` can embed it and be * invalidated through it - purging this URI drops the product entry with it, because the parent is - * stored under this resource's tag. + * stored under this resource's tag. It also carries the corpus tag directly: every writer of stock + * announces `product-corpus`, not this URI, so an admin edit has to reach this entry the same way + * it reaches the rest of the corpus, or a re-embed after the parent's own purge still hands back + * the stale number. */ #[Cacheable(expirySecond: 30)] class Stock extends ResourceObject @@ -38,6 +43,7 @@ public function onGet(string $productCode): static } $this->code = Code::OK; + $this->headers[Header::SURROGATE_KEY] = Products::SURROGATE_KEY; $this->body = [ 'productCode' => $product->productCode, 'stock' => $product->stock, diff --git a/var/loop/verify-all.sh b/var/loop/verify-all.sh index 3a6ff39b1..d50397420 100755 --- a/var/loop/verify-all.sh +++ b/var/loop/verify-all.sh @@ -31,7 +31,7 @@ else fi status=0 -for flow in help help-revalidate help-cdn help-cache-down agent-catalog agent-product products-app products-page product-stock products-corpus-tag shopping-complete customer-profile; do +for flow in help help-revalidate help-cdn help-cache-down agent-catalog agent-product products-app products-page product-stock product-stock-corpus products-corpus-tag shopping-complete customer-profile; do if "$PHP" var/loop/verify-cache.php "$flow" > "var/loop/last-$flow.txt" 2>&1; then printf 'oracle %-14s ok\n' "$flow" else diff --git a/var/loop/verify-cache.php b/var/loop/verify-cache.php index bb9798b9d..b8c2ed1f3 100644 --- a/var/loop/verify-cache.php +++ b/var/loop/verify-cache.php @@ -112,6 +112,14 @@ 'purge' => 'app://self/product/stock?productCode=sample-001', 'embeds' => true, ], + // The same number, reached the way an admin edit reaches it: every writer of stock announces + // `product-corpus`, so the resource holding stock has to be stored under that key too. + 'product-stock-corpus' => [ + 'read' => 'app://self/product/stock?productCode=sample-001', + 'write' => null, + 'purgeTags' => ['product-corpus'], + 'embeds' => false, + ], // A page that carries a CSRF token must NOT be cached; what it must do is hit the child it // embeds. Caching it would hand one shopper's token to the next. 'products-page' => [ From 1adba65f38bb0662e8e1f9e1f14fb000667b67bc Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 20 Sep 2026 11:28:39 +0900 Subject: [PATCH 02/10] Take the html-link-audit scan out of the production render path (#132) LinkHeaderRenderer.render() called HtmlLinkAuditor::audit() unconditionally, so every HTML response - production included, where a SilentHtmlLinkAuditLogger only discarded the result - paid for the regex scan of the rendered body. HtmlLinkAuditor is final with no interface, so the renderer required it as a hard constructor dependency. Split the renderer and its module in two: - LinkHeaderRenderer (production): only the Link: header contract. No HtmlLinkAuditor dependency at all - the audit type does not appear in the production dependency graph. links() is now public so a decorator can reuse the same computation. - AuditedLinkHeaderRenderer / AuditedLinkHeaderModule (test-only, new): wraps the production renderer and adds the audit call. install()ed explicitly by the two tests that judge the audit result (HtmlLinkAuditLedgerTest, LinkHeaderRendererTest); never referenced by HtmlModule or any production context. HtmlLinkAuditSuppressionTest pinned the old shape (default context resolves HtmlLinkAuditLoggerInterface to a Silent instance); updated to assert the stronger post-#132 fact - the default context has no binding for it at all, so nothing in that graph can warn anywhere. Verified: full suite green (2805 tests), psalm clean, HtmlLinkAuditLedgerTest still reconciles its full ledger, LinkHeaderRendererTest's Link: header contract passes on the audit-free production renderer, and `composer page -- get '/'` still emits the Link: header in a real SQL-backed render. --- src/Module/HtmlModule.php | 2 - src/Support/Html/AuditedLinkHeaderModule.php | 35 +++++++++++ .../Html/AuditedLinkHeaderRenderer.php | 40 ++++++++++++ src/Support/Html/LinkHeaderModule.php | 2 - src/Support/Html/LinkHeaderRenderer.php | 14 +++-- tests/Html/HtmlLinkAuditLedgerTest.php | 2 + tests/Html/LinkHeaderRendererTest.php | 63 ++++++++++++++++++- tests/Module/HtmlLinkAuditSuppressionTest.php | 15 +++-- 8 files changed, 158 insertions(+), 15 deletions(-) create mode 100644 src/Support/Html/AuditedLinkHeaderModule.php create mode 100644 src/Support/Html/AuditedLinkHeaderRenderer.php diff --git a/src/Module/HtmlModule.php b/src/Module/HtmlModule.php index 98f46b438..fdfb8a688 100644 --- a/src/Module/HtmlModule.php +++ b/src/Module/HtmlModule.php @@ -20,9 +20,7 @@ use MyVendor\BeMart\Provide\Render\AdminAuthRedirectRenderer; use MyVendor\BeMart\Provide\Transfer\DownloadContentTypePolicyInterface; use MyVendor\BeMart\Provide\Transfer\HtmlDownloadContentTypePolicy; -use MyVendor\BeMart\Support\Html\HtmlLinkAuditLoggerInterface; use MyVendor\BeMart\Support\Html\LinkHeaderModule; -use MyVendor\BeMart\Support\Html\SilentHtmlLinkAuditLogger; use MyVendor\BeMart\Support\Resource\AdminLoginFormSubmissionInterface; use MyVendor\BeMart\Support\Resource\HtmlAdminLoginFormSubmission; use MyVendor\BeMart\Support\Resource\HtmlMutationResponse; diff --git a/src/Support/Html/AuditedLinkHeaderModule.php b/src/Support/Html/AuditedLinkHeaderModule.php new file mode 100644 index 000000000..d40189fcf --- /dev/null +++ b/src/Support/Html/AuditedLinkHeaderModule.php @@ -0,0 +1,35 @@ +bind(RenderInterface::class)->to(AuditedLinkHeaderRenderer::class)->in(Scope::SINGLETON); + $this->bind(LinkHeaderRenderer::class); + $this->bind(HtmlLinkAuditor::class); + $this->bind(HtmlLinkAuditLoggerInterface::class)->to(SilentHtmlLinkAuditLogger::class); + } +} diff --git a/src/Support/Html/AuditedLinkHeaderRenderer.php b/src/Support/Html/AuditedLinkHeaderRenderer.php new file mode 100644 index 000000000..00cdc7e98 --- /dev/null +++ b/src/Support/Html/AuditedLinkHeaderRenderer.php @@ -0,0 +1,40 @@ +renderer->links($ro); + $view = $this->renderer->render($ro); + $this->auditor->audit($links, $view); + + return $view; + } +} diff --git a/src/Support/Html/LinkHeaderModule.php b/src/Support/Html/LinkHeaderModule.php index 9fc60d589..73a228e45 100644 --- a/src/Support/Html/LinkHeaderModule.php +++ b/src/Support/Html/LinkHeaderModule.php @@ -21,7 +21,5 @@ protected function configure(): void { $this->rename(RenderInterface::class, 'html'); $this->bind(RenderInterface::class)->to(LinkHeaderRenderer::class)->in(Scope::SINGLETON); - $this->bind(HtmlLinkAuditor::class); - $this->bind(HtmlLinkAuditLoggerInterface::class)->to(SilentHtmlLinkAuditLogger::class); } } diff --git a/src/Support/Html/LinkHeaderRenderer.php b/src/Support/Html/LinkHeaderRenderer.php index e435686d7..b79c9381c 100644 --- a/src/Support/Html/LinkHeaderRenderer.php +++ b/src/Support/Html/LinkHeaderRenderer.php @@ -31,7 +31,6 @@ public function __construct( #[Named('html')] private readonly RenderInterface $renderer, private readonly ReverseLinkerInterface $reverseLinker, - private readonly HtmlLinkAuditor $auditor, ) { } @@ -44,7 +43,6 @@ public function render(ResourceObject $ro) $links = $this->links($ro); $this->appendLinkHeader($ro, $links); $ro->view = $this->renderer->render($ro); - $this->auditor->audit($links, $ro->view); return $ro->view; } @@ -72,8 +70,16 @@ private function appendLinkHeader(ResourceObject $ro, array $links): void $ro->headers[self::HEADER] = $header; } - /** @return list */ - private function links(ResourceObject $ro): array + /** + * The #[Link] annotations a resource's handler method declares. + * + * Public because {@see AuditedLinkHeaderRenderer} - a test-only decorator, never wired into a + * production context - needs the same list this render() pass computes to audit it against the + * rendered HTML. A pure read of method annotations; safe to compute twice. + * + * @return list + */ + public function links(ResourceObject $ro): array { $method = 'on' . ucfirst($ro->uri->method); if (! method_exists($ro, $method)) { diff --git a/tests/Html/HtmlLinkAuditLedgerTest.php b/tests/Html/HtmlLinkAuditLedgerTest.php index 5e1cfa051..f4e1eb09d 100644 --- a/tests/Html/HtmlLinkAuditLedgerTest.php +++ b/tests/Html/HtmlLinkAuditLedgerTest.php @@ -14,6 +14,7 @@ use MyVendor\BeMart\Be\Reason\Service\AdminSession; use MyVendor\BeMart\Be\Reason\Service\CustomerSession; use Ray\Csrf\CsrfTokenInterface; +use MyVendor\BeMart\Support\Html\AuditedLinkHeaderModule; use MyVendor\BeMart\Support\Html\HtmlLinkAuditLoggerInterface; use MyVendor\BeMart\Tests\Support\RecordingHtmlLinkAuditLogger; use Madapaja\TwigModule\Exception\TemplateNotFound; @@ -134,6 +135,7 @@ public function __construct( #[Override] protected function configure(): void { + $this->install(new AuditedLinkHeaderModule()); $this->bind(HtmlLinkAuditLoggerInterface::class)->toInstance($this->logger); $this->bind(CsrfTokenInterface::class)->toInstance(new NullCsrfToken()); $this->bind(AdminSession::class)->toInstance(new FakeAdminSession($this->admin ? HtmlLinkAuditLedgerTest::ADMIN_ID : null)); diff --git a/tests/Html/LinkHeaderRendererTest.php b/tests/Html/LinkHeaderRendererTest.php index 360cee7cd..081a742c8 100644 --- a/tests/Html/LinkHeaderRendererTest.php +++ b/tests/Html/LinkHeaderRendererTest.php @@ -8,6 +8,8 @@ use BEAR\Resource\RenderInterface; use BEAR\Resource\ReverseLinkerInterface; use BEAR\Resource\Uri; +use MyVendor\BeMart\Support\Html\AuditedLinkHeaderModule; +use MyVendor\BeMart\Support\Html\AuditedLinkHeaderRenderer; use MyVendor\BeMart\Support\Html\HtmlLinkAuditLoggerInterface; use MyVendor\BeMart\Support\Html\HtmlLinkAuditor; use MyVendor\BeMart\Support\Html\LinkHeaderModule; @@ -22,12 +24,31 @@ final class LinkHeaderRendererTest extends TestCase { - public function testRenderAddsLinkHeaderAndAuditsRenderedHtml(): void + public function testRenderAddsLinkHeader(): void { - $logger = new RecordingHtmlLinkAuditLogger(); $renderer = new LinkHeaderRenderer( new SemanticAnchorRenderer(), new NullReverseLinker(), + ); + $ro = new LinkedResourceObject(); + $ro->uri = new Uri('page://self/current'); + $ro->uri->method = 'get'; + $ro->body = []; + + $view = $renderer->render($ro); + + $this->assertSame('Next', $view); + $this->assertSame('; rel="goNext"; method="get"', $ro->headers['Link']); + } + + public function testAuditedRendererAddsLinkHeaderAndAuditsRenderedHtml(): void + { + $logger = new RecordingHtmlLinkAuditLogger(); + $renderer = new AuditedLinkHeaderRenderer( + new LinkHeaderRenderer( + new SemanticAnchorRenderer(), + new NullReverseLinker(), + ), new HtmlLinkAuditor($logger), ); $ro = new LinkedResourceObject(); @@ -50,11 +71,47 @@ protected function configure(): void { $this->bind(RenderInterface::class)->to(SemanticAnchorRenderer::class); $this->bind(ReverseLinkerInterface::class)->to(NullReverseLinker::class); - $this->bind(HtmlLinkAuditLoggerInterface::class)->toInstance(new RecordingHtmlLinkAuditLogger()); } })); $renderer = $injector->getInstance(RenderInterface::class); $this->assertInstanceOf(LinkHeaderRenderer::class, $renderer); } + + public function testAuditedModuleWrapsLinkHeaderModuleAndAudits(): void + { + $logger = new RecordingHtmlLinkAuditLogger(); + $base = new AuditedLinkHeaderModule(new LinkHeaderModule(new class extends AbstractModule { + #[Override] + protected function configure(): void + { + $this->bind(RenderInterface::class)->to(SemanticAnchorRenderer::class); + $this->bind(ReverseLinkerInterface::class)->to(NullReverseLinker::class); + } + })); + $base->override(new class ($logger) extends AbstractModule { + public function __construct(private readonly RecordingHtmlLinkAuditLogger $logger) + { + parent::__construct(); + } + + #[Override] + protected function configure(): void + { + $this->bind(HtmlLinkAuditLoggerInterface::class)->toInstance($this->logger); + } + }); + $injector = new Injector($base); + $renderer = $injector->getInstance(RenderInterface::class); + $this->assertInstanceOf(AuditedLinkHeaderRenderer::class, $renderer); + + $ro = new LinkedResourceObject(); + $ro->uri = new Uri('page://self/current'); + $ro->uri->method = 'get'; + $ro->body = []; + + $renderer->render($ro); + + $this->assertSame([], $logger->drain(), 'the fake anchor already carries the rel; nothing should be flagged'); + } } diff --git a/tests/Module/HtmlLinkAuditSuppressionTest.php b/tests/Module/HtmlLinkAuditSuppressionTest.php index 897a6bef5..cd59c95d3 100644 --- a/tests/Module/HtmlLinkAuditSuppressionTest.php +++ b/tests/Module/HtmlLinkAuditSuppressionTest.php @@ -5,16 +5,23 @@ namespace MyVendor\BeMart\Tests\Module; use MyVendor\BeMart\Support\Html\HtmlLinkAuditLoggerInterface; -use MyVendor\BeMart\Support\Html\SilentHtmlLinkAuditLogger; use MyVendor\BeMart\Tests\Support\HtmlTestInjector; use PHPUnit\Framework\TestCase; +use Ray\Di\Exception\Unbound; +/** + * The default HTML context does not bind an audit logger at all - #132 moved the html-link-audit + * scan (and everything it needs) out of {@see \MyVendor\BeMart\Support\Html\LinkHeaderModule}, + * into the test-only {@see \MyVendor\BeMart\Support\Html\AuditedLinkHeaderModule}. A page render + * through the standard context cannot warn anywhere, because nothing in that graph can even ask + * for a logger to warn through - not because a bound logger happens to be silent. + */ final class HtmlLinkAuditSuppressionTest extends TestCase { - public function testHtmlContextSuppressesDevHtmlLinkAuditWarnings(): void + public function testHtmlContextHasNoAuditLoggerBinding(): void { - $logger = HtmlTestInjector::getInstance()->getInstance(HtmlLinkAuditLoggerInterface::class); + $this->expectException(Unbound::class); - $this->assertInstanceOf(SilentHtmlLinkAuditLogger::class, $logger); + HtmlTestInjector::getInstance()->getInstance(HtmlLinkAuditLoggerInterface::class); } } From 616ebda63d9bd94d85634ce481d9dada9a7b8c10 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 20 Sep 2026 11:47:13 +0900 Subject: [PATCH 03/10] Move HTML session start to a DI boundary (#93) Three Auth adapters (EccubeSharedSessionAdapter, HtmlAdminSessionAdapter, EccubeSharedCsrfTokenAdapter) each carried an identical private ensureSessionStarted() - same CLI/active/headers-sent guards, same session_name() + session_start() options - and EccubeSharedCsrfTokenAdapter's copy hardcoded a cross-reference to EccubeSharedSessionAdapter::COOKIE_NAME regardless of which session adapter a context actually bound. Which cookie a request's session lived under was a fact only recoverable by reading Auth/ adapter internals, not the context module that wires them. Introduced SessionStarterInterface (ensureStarted(): void) with two implementations: - CookieSessionStarter: the production policy, extracted verbatim from the three duplicates, parametrized by cookie name. - NullSessionStarter: test-null, for a context that must never touch session machinery. Each adapter now takes a SessionStarterInterface with a default value (new CookieSessionStarter(EccubeSharedSessionAdapter::COOKIE_NAME)) so every call across the existing PHPUnit fixtures keeps working unchanged. HtmlModule and EccubeModule each bind SessionStarterInterface explicitly to the same cookie, so the choice is now a context/DI fact rather than adapter-internal. Also added AdminLoginChallengeInterface, extracted from the concrete, final HtmlAdminLoginChallengeAdapter per the issue's follow-up comment: Login, TwoFactorAuth, and TwoFactorAuthSet now depend on the interface. AppModule binds both the interface and the concrete class (the class has no constructor state - is a shared superglobal - so both bindings resolving to separate instances is safe), so existing tests that fetch the concrete class via the injector are unaffected; a future test whose subject is not the challenge machinery itself can now bind a fake. Verified: full suite green (2805 tests), psalm clean, all 35 Auth adapter tests and the admin login/2FA resource/ExcludedResponseBodyStore tests pass, and `composer page -- get '/admin/login'` still renders against a real SQL-backed context. --- src/Auth/AdminLoginChallengeInterface.php | 40 ++++++++++++ src/Auth/CookieSessionStarter.php | 65 ++++++++++++++++++++ src/Auth/EccubeSharedCsrfTokenAdapter.php | 43 ++----------- src/Auth/EccubeSharedSessionAdapter.php | 53 +++------------- src/Auth/HtmlAdminLoginChallengeAdapter.php | 12 +++- src/Auth/HtmlAdminSessionAdapter.php | 45 +++----------- src/Auth/NullSessionStarter.php | 22 +++++++ src/Auth/SessionStarterInterface.php | 18 ++++++ src/Module/AppModule.php | 2 + src/Module/EccubeModule.php | 7 ++- src/Module/HtmlModule.php | 7 +++ src/Resource/Page/Admin/Login.php | 4 +- src/Resource/Page/Admin/TwoFactorAuth.php | 4 +- src/Resource/Page/Admin/TwoFactorAuthSet.php | 4 +- 14 files changed, 201 insertions(+), 125 deletions(-) create mode 100644 src/Auth/AdminLoginChallengeInterface.php create mode 100644 src/Auth/CookieSessionStarter.php create mode 100644 src/Auth/NullSessionStarter.php create mode 100644 src/Auth/SessionStarterInterface.php diff --git a/src/Auth/AdminLoginChallengeInterface.php b/src/Auth/AdminLoginChallengeInterface.php new file mode 100644 index 000000000..fd85ccad1 --- /dev/null +++ b/src/Auth/AdminLoginChallengeInterface.php @@ -0,0 +1,40 @@ +cookieName); + // No error suppression: if session_start emits a warning, surface + // it. The headers_sent() guard above covers the common case; + // other failures (session.save_path unwritable, etc.) are + // operator-config issues that must be visible in the error log, + // not silently swallowed into "request is anonymous". + session_start([ + 'use_strict_mode' => true, + 'cookie_httponly' => true, + 'cookie_samesite' => 'Lax', + ]); + } +} diff --git a/src/Auth/EccubeSharedCsrfTokenAdapter.php b/src/Auth/EccubeSharedCsrfTokenAdapter.php index 197416e92..5a933f600 100644 --- a/src/Auth/EccubeSharedCsrfTokenAdapter.php +++ b/src/Auth/EccubeSharedCsrfTokenAdapter.php @@ -9,15 +9,8 @@ use function bin2hex; use function hash_equals; -use function headers_sent; use function is_string; use function random_bytes; -use function session_name; -use function session_start; -use function session_status; - -use const PHP_SAPI; -use const PHP_SESSION_ACTIVE; /** * Production Ray\Csrf\CsrfTokenInterface adapter — validates submitted tokens @@ -42,11 +35,8 @@ * JSON / form body, and asks this adapter to compare it against * `$_SESSION[SESSION_KEY]` using `hash_equals`. * - * CLI safety: in `bin/app.php` there is no HTTP origin to defend. CLI - * requests use the token in $_SESSION when a test or context module supplies - * one; otherwise POSTs fail the CSRF check the same way an anonymous browser - * request would. Application code must not inspect process environment to - * decide the trusted token. + * Which cookie starts the session backing $_SESSION, and whether one starts + * at all, is a context/DI decision - see {@see SessionStarterInterface} and #93. * * Comparison is always timing-safe (`hash_equals`). Empty strings and * non-string types are rejected before comparison. @@ -71,6 +61,7 @@ public const SESSION_KEY = '_csrf_token'; public function __construct( + private SessionStarterInterface $sessionStarter = new CookieSessionStarter(EccubeSharedSessionAdapter::COOKIE_NAME), private string $sessionKey = self::SESSION_KEY, ) { } @@ -78,7 +69,7 @@ public function __construct( #[Override] public function issue(): string { - $this->ensureSessionStarted(); + $this->sessionStarter->ensureStarted(); $existing = $this->storedToken(); if ($existing !== null) { @@ -100,7 +91,7 @@ public function verify(string $candidate): bool return false; } - $this->ensureSessionStarted(); + $this->sessionStarter->ensureStarted(); $stored = $this->storedToken(); return $stored !== null && hash_equals($stored, $candidate); @@ -109,7 +100,7 @@ public function verify(string $candidate): bool #[Override] public function clear(): void { - $this->ensureSessionStarted(); + $this->sessionStarter->ensureStarted(); unset($_SESSION[$this->sessionKey]); } @@ -122,26 +113,4 @@ private function storedToken(): string|null return is_string($stored) && $stored !== '' ? $stored : null; } - - private function ensureSessionStarted(): void - { - if (PHP_SAPI === 'cli') { - return; - } - - if (session_status() === PHP_SESSION_ACTIVE) { - return; - } - - if (headers_sent()) { - return; - } - - session_name(EccubeSharedSessionAdapter::COOKIE_NAME); - session_start([ - 'use_strict_mode' => true, - 'cookie_httponly' => true, - 'cookie_samesite' => 'Lax', - ]); - } } diff --git a/src/Auth/EccubeSharedSessionAdapter.php b/src/Auth/EccubeSharedSessionAdapter.php index 1e58f7e16..8acf59ec7 100644 --- a/src/Auth/EccubeSharedSessionAdapter.php +++ b/src/Auth/EccubeSharedSessionAdapter.php @@ -6,13 +6,7 @@ use MyVendor\BeMart\Be\Reason\Service\CustomerSession; -use function headers_sent; use function is_string; -use function session_name; -use function session_start; -use function session_status; - -use const PHP_SESSION_ACTIVE; /** * Production CustomerSession adapter — reads PHP's `$_SESSION` using @@ -45,13 +39,13 @@ * starts the session under the same cookie name and reads the flat * key. No Symfony deps required on the BEAR side. * - * CLI safety: in `bin/app.php` we have no HTTP context. CLI requests are - * anonymous unless a context module binds a different CustomerSession. - * Application code must not inspect process environment to decide auth. + * CLI safety: in `bin/app.php` we have no HTTP context. CLI requests are + * anonymous unless a context module binds a different CustomerSession. + * Application code must not inspect process environment to decide auth. * - * Headers-sent safety: if `session_start()` cannot run (output already - * flushed), we treat the request as anonymous. Domain code already - * handles `customerId === null` correctly. + * Which cookie name starts the session, and whether one starts at all, is a + * context/DI decision - see {@see SessionStarterInterface} and #93. Headers-sent + * safety and the "not started" → anonymous fallback live there now. */ final readonly class EccubeSharedSessionAdapter extends CustomerSession { @@ -70,10 +64,10 @@ public const CUSTOMER_ID_KEY = 'customer_id'; public function __construct( - private string $cookieName = self::COOKIE_NAME, + private SessionStarterInterface $sessionStarter = new CookieSessionStarter(self::COOKIE_NAME), private string $sessionKey = self::CUSTOMER_ID_KEY, ) { - $this->ensureSessionStarted(); + $this->sessionStarter->ensureStarted(); parent::__construct($this->readCustomerId()); } @@ -92,35 +86,4 @@ private function readCustomerId(): string|null return null; } - - private function ensureSessionStarted(): void - { - // CLI has no real session. Tests can still poke $_SESSION directly; - // this adapter just won't try to start a session machinery that - // would emit a warning or fail. - if (PHP_SAPI === 'cli') { - return; - } - - if (session_status() === PHP_SESSION_ACTIVE) { - return; - } - - if (headers_sent()) { - // Cannot start a session now; treat request as anonymous. - return; - } - - session_name($this->cookieName); - // No error suppression: if session_start emits a warning, surface - // it. The headers_sent() guard above covers the common case; - // other failures (session.save_path unwritable, etc.) are - // operator-config issues that must be visible in the error log, - // not silently swallowed into "request is anonymous". - session_start([ - 'use_strict_mode' => true, - 'cookie_httponly' => true, - 'cookie_samesite' => 'Lax', - ]); - } } diff --git a/src/Auth/HtmlAdminLoginChallengeAdapter.php b/src/Auth/HtmlAdminLoginChallengeAdapter.php index f14f9c9fe..7e056592c 100644 --- a/src/Auth/HtmlAdminLoginChallengeAdapter.php +++ b/src/Auth/HtmlAdminLoginChallengeAdapter.php @@ -4,6 +4,8 @@ namespace MyVendor\BeMart\Auth; +use Override; + use function is_string; use function session_regenerate_id; use function session_status; @@ -23,11 +25,12 @@ * logout ({@see HtmlAdminSessionWriter}); elevation happens inside an * already-authenticated session, so it does not rotate it again. */ -final class HtmlAdminLoginChallengeAdapter +final class HtmlAdminLoginChallengeAdapter implements AdminLoginChallengeInterface { public const VERIFY_CHALLENGE_KEY = 'admin_2fa_verify_challenge'; public const SETUP_CHALLENGE_KEY = 'admin_2fa_setup_challenge'; + #[Override] public function startVerification(string $adminId, string $loginId): void { $session = &$this->session(); @@ -38,6 +41,7 @@ public function startVerification(string $adminId, string $loginId): void ]; } + #[Override] public function startSetup(string $adminId, string $loginId, string $authKey): void { $session = &$this->session(); @@ -49,6 +53,7 @@ public function startSetup(string $adminId, string $loginId, string $authKey): v ]; } + #[Override] public function verificationChallenge(): AdminTwoFactorChallenge|null { $session = &$this->session(); @@ -56,6 +61,7 @@ public function verificationChallenge(): AdminTwoFactorChallenge|null return $this->challengeFrom($session[self::VERIFY_CHALLENGE_KEY] ?? null, requiresAuthKey: false); } + #[Override] public function setupChallenge(): AdminTwoFactorChallenge|null { $session = &$this->session(); @@ -70,12 +76,14 @@ public function setupChallenge(): AdminTwoFactorChallenge|null * codes tried): the pre-auth identity must not survive, or the next * request would resume the same challenge. */ + #[Override] public function abandonVerification(): void { $session = &$this->session(); unset($session[self::VERIFY_CHALLENGE_KEY]); } + #[Override] public function completeVerification(AdminTwoFactorChallenge $challenge): void { $this->regenerateActiveSessionId(); @@ -84,6 +92,7 @@ public function completeVerification(AdminTwoFactorChallenge $challenge): void $session[HtmlAdminSessionAdapter::ADMIN_ID_KEY] = $challenge->adminId; } + #[Override] public function completeSetup(AdminTwoFactorChallenge $challenge): void { $this->regenerateActiveSessionId(); @@ -92,6 +101,7 @@ public function completeSetup(AdminTwoFactorChallenge $challenge): void $session[HtmlAdminSessionAdapter::ADMIN_ID_KEY] = $challenge->adminId; } + #[Override] public function regenerateActiveSessionId(): void { if (session_status() !== PHP_SESSION_ACTIVE) { diff --git a/src/Auth/HtmlAdminSessionAdapter.php b/src/Auth/HtmlAdminSessionAdapter.php index 694b164f5..fae2216ed 100644 --- a/src/Auth/HtmlAdminSessionAdapter.php +++ b/src/Auth/HtmlAdminSessionAdapter.php @@ -6,14 +6,7 @@ use MyVendor\BeMart\Be\Reason\Service\AdminSession; -use function headers_sent; use function is_string; -use function session_name; -use function session_start; -use function session_status; - -use const PHP_SAPI; -use const PHP_SESSION_ACTIVE; /** * HTML-context admin session adapter. @@ -21,25 +14,29 @@ * `public/index.php` starts the cookie-backed PHP session for the HTML context * before dispatch. This adapter snapshots the flat admin id written by the html * admin login/logout resources. + * + * Which cookie starts that session is a context/DI decision - see + * {@see SessionStarterInterface} and #93. */ final class HtmlAdminSessionAdapter extends AdminSession { public const ADMIN_ID_KEY = 'admin_id'; - public function __construct() - { - parent::__construct(self::readAdminId()); + public function __construct( + private readonly SessionStarterInterface $sessionStarter = new CookieSessionStarter(EccubeSharedSessionAdapter::COOKIE_NAME), + ) { + parent::__construct($this->readAdminId()); } public function refresh(): void { - $this->adminId = self::readAdminId(); + $this->adminId = $this->readAdminId(); } /** @return non-empty-string|null */ - private static function readAdminId(): string|null + private function readAdminId(): string|null { - self::ensureSessionStarted(); + $this->sessionStarter->ensureStarted(); $session = isset($_SESSION) ? $_SESSION : []; /** @var mixed $raw */ $raw = $session[self::ADMIN_ID_KEY] ?? null; @@ -49,26 +46,4 @@ private static function readAdminId(): string|null return null; } - - private static function ensureSessionStarted(): void - { - if (PHP_SAPI === 'cli') { - return; - } - - if (session_status() === PHP_SESSION_ACTIVE) { - return; - } - - if (headers_sent()) { - return; - } - - session_name(EccubeSharedSessionAdapter::COOKIE_NAME); - session_start([ - 'use_strict_mode' => true, - 'cookie_httponly' => true, - 'cookie_samesite' => 'Lax', - ]); - } } diff --git a/src/Auth/NullSessionStarter.php b/src/Auth/NullSessionStarter.php new file mode 100644 index 000000000..9a52d445b --- /dev/null +++ b/src/Auth/NullSessionStarter.php @@ -0,0 +1,22 @@ +bind(ProductCacheInvalidatorInterface::class)->to(ProductCacheInvalidator::class); $this->bind(HtmlAdminLoginChallengeAdapter::class); + $this->bind(AdminLoginChallengeInterface::class)->to(HtmlAdminLoginChallengeAdapter::class); $this->bind(CustomerSessionWriterInterface::class)->to(NoopCustomerSessionWriter::class)->in(Scope::SINGLETON); $this->bind(AdminSessionWriterInterface::class)->to(NoopAdminSessionWriter::class)->in(Scope::SINGLETON); $this->bind(CartSessionPrefixInterface::class)->to(NoopCartSessionPrefix::class)->in(Scope::SINGLETON); diff --git a/src/Module/EccubeModule.php b/src/Module/EccubeModule.php index 5ad8557ec..00bdaf8a3 100644 --- a/src/Module/EccubeModule.php +++ b/src/Module/EccubeModule.php @@ -4,13 +4,15 @@ namespace MyVendor\BeMart\Module; +use MyVendor\BeMart\Auth\CookieSessionStarter; use MyVendor\BeMart\Auth\EccubeSharedCsrfTokenAdapter; use MyVendor\BeMart\Auth\EccubeSharedSessionAdapter; use MyVendor\BeMart\Auth\HtmlAdminSessionAdapter; +use MyVendor\BeMart\Auth\SessionStarterInterface; use MyVendor\BeMart\Be\Reason\Service\AdminSession; -use Ray\Csrf\CsrfTokenInterface; use MyVendor\BeMart\Be\Reason\Service\CustomerSession; use Override; +use Ray\Csrf\CsrfTokenInterface; use Ray\Di\AbstractModule; /** @@ -24,6 +26,9 @@ final class EccubeModule extends AbstractModule #[Override] protected function configure(): void { + // Explicit here so the cookie every EC-CUBE-bridge session/CSRF adapter shares is a + // context/DI fact, not something read out of Auth/ adapter internals. See #93. + $this->bind(SessionStarterInterface::class)->toInstance(new CookieSessionStarter(EccubeSharedSessionAdapter::COOKIE_NAME)); $this->bind(CustomerSession::class)->to(EccubeSharedSessionAdapter::class); $this->bind(AdminSession::class)->to(HtmlAdminSessionAdapter::class); $this->bind(CsrfTokenInterface::class)->to(EccubeSharedCsrfTokenAdapter::class); diff --git a/src/Module/HtmlModule.php b/src/Module/HtmlModule.php index fdfb8a688..87dcabfa8 100644 --- a/src/Module/HtmlModule.php +++ b/src/Module/HtmlModule.php @@ -10,11 +10,14 @@ use Madapaja\TwigModule\TwigModule; use MyVendor\BeMart\Auth\AdminSessionWriterInterface; use MyVendor\BeMart\Auth\CartSessionPrefixInterface; +use MyVendor\BeMart\Auth\CookieSessionStarter; +use MyVendor\BeMart\Auth\EccubeSharedSessionAdapter; use MyVendor\BeMart\Auth\HtmlAdminSessionAdapter; use MyVendor\BeMart\Auth\HtmlAdminSessionWriter; use MyVendor\BeMart\Auth\HtmlCartSessionPrefix; use MyVendor\BeMart\Auth\HtmlCustomerSessionWriter; use MyVendor\BeMart\Auth\CustomerSessionWriterInterface; +use MyVendor\BeMart\Auth\SessionStarterInterface; use MyVendor\BeMart\Be\Reason\Service\AdminSession; use MyVendor\BeMart\Provide\Error\HtmlThrowableHandler; use MyVendor\BeMart\Provide\Render\AdminAuthRedirectRenderer; @@ -49,6 +52,10 @@ protected function configure(): void // See AdminAuthRedirectRenderer. Resource-level 403s are unchanged. $this->override(new LinkHeaderModule(new AdminAuthRedirectModule(new TwigModule(options: $this->twigOptions)))); $this->bind(ReverseLinkerInterface::class)->to(RouterReverseLinker::class); + // Same cookie EccubeModule uses for the eccube-bridge context - see #93. Explicit here + // so a plain HTML context (no EC-CUBE bridge) still gets a session without HtmlAdminSessionAdapter + // hardcoding a cross-reference to it. + $this->bind(SessionStarterInterface::class)->toInstance(new CookieSessionStarter(EccubeSharedSessionAdapter::COOKIE_NAME)); $this->bind(AdminSession::class)->to(HtmlAdminSessionAdapter::class); $this->bind(CustomerSessionWriterInterface::class)->to(HtmlCustomerSessionWriter::class); $this->bind(AdminSessionWriterInterface::class)->to(HtmlAdminSessionWriter::class); diff --git a/src/Resource/Page/Admin/Login.php b/src/Resource/Page/Admin/Login.php index f15d9cab9..fa818347e 100644 --- a/src/Resource/Page/Admin/Login.php +++ b/src/Resource/Page/Admin/Login.php @@ -12,7 +12,7 @@ use Be\Framework\BecomingInterface; use Be\Framework\Exception\SemanticVariableException; use Be\Framework\SemanticVariable\ValidationMessageHandler; -use MyVendor\BeMart\Auth\HtmlAdminLoginChallengeAdapter; +use MyVendor\BeMart\Auth\AdminLoginChallengeInterface; use MyVendor\BeMart\Auth\HtmlAdminSessionAdapter; use MyVendor\BeMart\Be\Exception\AdminLoginFailedException; use MyVendor\BeMart\Be\Exception\LoginAttemptsExceededException; @@ -77,7 +77,7 @@ public function __construct( private readonly CsrfTokenInterface $csrf, private readonly FormFactory $formFactory, private readonly TwoFactorAuthInterface $twoFactorAuth, - private readonly HtmlAdminLoginChallengeAdapter $loginChallenge, + private readonly AdminLoginChallengeInterface $loginChallenge, private readonly AdminLoginFormSubmissionInterface $formSubmission, ) { } diff --git a/src/Resource/Page/Admin/TwoFactorAuth.php b/src/Resource/Page/Admin/TwoFactorAuth.php index bffeb5277..0c084feae 100644 --- a/src/Resource/Page/Admin/TwoFactorAuth.php +++ b/src/Resource/Page/Admin/TwoFactorAuth.php @@ -12,8 +12,8 @@ use Be\Framework\Exception\SemanticVariableException; use Be\Framework\SemanticVariable\ValidationMessageHandler; use Ray\Csrf\Attribute\CsrfToken; +use MyVendor\BeMart\Auth\AdminLoginChallengeInterface; use MyVendor\BeMart\Auth\AdminTwoFactorChallenge; -use MyVendor\BeMart\Auth\HtmlAdminLoginChallengeAdapter; use MyVendor\BeMart\Be\Exception\LoginAttemptsExceededException; use MyVendor\BeMart\Be\Exception\TwoFactorAuthFailedException; use MyVendor\BeMart\Be\Final\TwoFactorAuthVerified; @@ -57,7 +57,7 @@ class TwoFactorAuth extends ResourceObject public function __construct( private readonly FormFactory $formFactory, private readonly BecomingInterface $becoming, - private readonly HtmlAdminLoginChallengeAdapter $loginChallenge, + private readonly AdminLoginChallengeInterface $loginChallenge, private readonly AdminSession $adminSession, private readonly AdminQueryInterface $adminQuery, private readonly CsrfTokenInterface $csrf, diff --git a/src/Resource/Page/Admin/TwoFactorAuthSet.php b/src/Resource/Page/Admin/TwoFactorAuthSet.php index 2e31e3be0..6f3c5ad68 100644 --- a/src/Resource/Page/Admin/TwoFactorAuthSet.php +++ b/src/Resource/Page/Admin/TwoFactorAuthSet.php @@ -11,8 +11,8 @@ use Be\Framework\BecomingInterface; use Be\Framework\Exception\SemanticVariableException; use Ray\Csrf\Attribute\CsrfToken; +use MyVendor\BeMart\Auth\AdminLoginChallengeInterface; use MyVendor\BeMart\Auth\AdminTwoFactorChallenge; -use MyVendor\BeMart\Auth\HtmlAdminLoginChallengeAdapter; use MyVendor\BeMart\Be\Exception\TwoFactorAuthFailedException; use MyVendor\BeMart\Be\Final\TwoFactorAuthConfigured; use MyVendor\BeMart\Be\Input\SetTwoFactorAuthInput; @@ -59,7 +59,7 @@ class TwoFactorAuthSet extends ResourceObject public function __construct( private readonly FormFactory $formFactory, private readonly BecomingInterface $becoming, - private readonly HtmlAdminLoginChallengeAdapter $loginChallenge, + private readonly AdminLoginChallengeInterface $loginChallenge, private readonly AdminSession $adminSession, private readonly AdminQueryInterface $adminQuery, private readonly TwoFactorAuthInterface $twoFactorAuth, From 996eb5156c09379280f49d832a0ca6cefbbc2004 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 20 Sep 2026 12:32:35 +0900 Subject: [PATCH 04/10] Publish csrfToken from every page that rendered it empty (#139) 37 pages rendered a hidden csrfToken field with value="" because their GET resources never published the field: 9 nullByDesign markers left waiting on an EC-CUBE-side EventListener mirror that was never implemented, and 28 notPublished cases where the resource simply never set the key. Both resolve into a production HTTP POST to any of these forms failing CSRF validation (403) - the empty-token-ledger regression guard (#140) is what kept the set from growing further, but never shrank it. EccubeSharedCsrfTokenAdapter::issue() already self-issues and stores a fresh token when none exists (documented but unexercised until now), so closing these out is mechanical: inject Ray\Csrf\CsrfTokenInterface, publish 'csrfToken' => $this->csrf->issue() in each onGet body, and - since every affected schema is additionalProperties: false - add csrfToken to that schema's top-level properties/required (some already declared it under $defs without wiring it to properties; some declared it nullable for the old null marker; most didn't have it at all - each was checked individually, never assumed from a bare grep, since JsonSchemaInterceptor validates every annotated response and throws on an undeclared property). Also closed the blindspot the guard test's own docblock named: three pages (admin/category/category-list, admin/product/csv-category, admin/product/csv-class-name) filled the field via the csrf_token() Twig function instead, which reads $_SESSION directly and renders non-empty while the resource publishes nothing - invisible to the empty-field regex sweep. Fixed the resources to publish the field and simplified the templates to `{{ csrfToken }}`. Added a new guard (testNoTemplateFallsBackToTheSessionReadingCsrfHelper) that fails if any template reaches for csrf_token() again, since the existing sweep structurally cannot detect that regression. AbstractCsvUpload::onGet() is shared by four CSV-upload screens; fixing it once covers CsvCategory, CsvClassCategory, CsvProduct, and CsvClassName. ClassCategoryExport/ClassNameExport previously set $this->body to a raw CSV string, which TwigRenderer::buildBody() silently drops to [] for non-array bodies - that's why their upload-form template always rendered empty regardless of any csrfToken fix; converted their body to an array (content + csrfToken) and renamed the corresponding schemas' `value` property to `content` to match. DownloadResponder already special-cases a 'content' array key for the real CSV byte-stream download path, so the production download response is unchanged. Emptied tests/Html/csrf-empty-token-ledger.json now that all 37 entries are fixed, and fixed three sibling tests (ShoppingShippingResourceTest x2, WithdrawResourceTest, WithdrawResourceSqlTest) that pinned the old assertNull(csrfToken) marker behavior - updated to assert the real FakeCsrfToken::TOKEN value, the correct post-fix contract, not deleted. Delivered as three parallel subagent batches (customer-priority 13 pages, admin 12, admin 12 + the shared base class + the 3 twig-fallback pages) per a shared mechanical pattern and per-file schema-verification procedure, then reconciled centrally: ledger trim, guard test, full suite, psalm. Verified: full suite green (2806 tests, 33061 assertions), psalm clean, CsrfTokenRenderedTest fully green (empty ledger, new Twig-fallback guard passing), zero remaining `csrf_token(` calls in var/templates, zero remaining hardcoded `'csrfToken' => null` in src/Resource. (WithdrawResourceSqlTest's fix is unverifiable, and not because of this worktree: be/tests/Sql/ contains only LoginAttemptGateSqlTest.php, PreOrderClaimSqlTest.php, and bootstrap.php on origin/1.x itself - SqlFixturesTrait.php was deleted by commit 47016e64 "Remove SQL PHPUnit suite" but tests/Resource/Sql/AbstractResourceSqlTestCase.php still does `use SqlFixturesTrait;`. tests/Resource/Sql/* cannot load for anyone on this branch; it is excluded from phpunit.xml's default suite for that reason. The assertion change was made to match the proven Fake-variant pattern and is correct by inspection, but cannot be run until that repo-level gap is fixed separately.) --- src/Resource/Page/Admin/BaseInfo.php | 3 + src/Resource/Page/Admin/Category/Category.php | 3 + .../Page/Admin/Category/CategoryList.php | 3 + src/Resource/Page/Admin/Category/Csv.php | 3 + src/Resource/Page/Admin/Category/Edit.php | 4 + src/Resource/Page/Admin/ChangePassword.php | 3 + .../ClassCategory/ClassCategoryExport.php | 7 +- .../Page/Admin/ClassName/ClassNameExport.php | 7 +- src/Resource/Page/Admin/Customer.php | 3 + .../Page/Admin/CustomerDeliveryEdit.php | 3 + src/Resource/Page/Admin/Delivery/Delivery.php | 3 + .../Page/Admin/Delivery/DeliveryList.php | 3 + .../Page/Admin/Order/ExportShipping.php | 3 + .../Page/Admin/Order/ImportShipping.php | 4 +- src/Resource/Page/Admin/Order/MailConfirm.php | 3 + src/Resource/Page/Admin/Order/SendMail.php | 3 + .../Page/Admin/Order/ShippingAddress.php | 3 + .../Page/Admin/Order/ShippingNotifyMail.php | 4 +- src/Resource/Page/Admin/Payment/Payment.php | 3 + .../Page/Admin/Product/CsvClassCategory.php | 4 +- .../Page/Admin/Product/CsvClassName.php | 4 +- src/Resource/Page/Admin/Product/Edit.php | 4 + src/Resource/Page/Admin/ProductCsv.php | 3 + src/Resource/Page/Admin/Tag/TagList.php | 3 + src/Resource/Page/Admin/TwoFactorAuthEdit.php | 3 + src/Resource/Page/Contact/Confirm.php | 3 + src/Resource/Page/Entry/Confirm.php | 3 + src/Resource/Page/ForgotPassword.php | 6 +- src/Resource/Page/Mypage/Address.php | 4 +- src/Resource/Page/Mypage/Change.php | 3 + src/Resource/Page/Mypage/History.php | 3 + src/Resource/Page/Mypage/Withdraw.php | 8 +- src/Resource/Page/Mypage/WithdrawConfirm.php | 11 +- src/Resource/Page/Reset.php | 6 +- src/Resource/Page/Shopping/Login.php | 3 + src/Resource/Page/Shopping/Shipping.php | 8 +- src/Resource/Page/Shopping/ShippingEdit.php | 4 +- .../Page/Shopping/ShippingMultipleEdit.php | 4 +- src/Support/Resource/AbstractCsvUpload.php | 3 + tests/Html/CsrfTokenRenderedTest.php | 71 ++++++-- tests/Html/csrf-empty-token-ledger.json | 151 +----------------- tests/Resource/AdminClassCsvResourceTest.php | 2 +- .../Resource/ShoppingShippingResourceTest.php | 4 +- .../Resource/Sql/WithdrawResourceSqlTest.php | 2 +- tests/Resource/WithdrawResourceTest.php | 2 +- var/json_schema/get-admin-base-info.json | 10 ++ .../get-admin-category-category-list.json | 12 +- .../get-admin-category-category.json | 10 ++ var/json_schema/get-admin-category-csv.json | 10 ++ var/json_schema/get-admin-category-edit.json | 10 ++ .../get-admin-change-password.json | 10 ++ ...-class-category-class-category-export.json | 14 +- ...et-admin-class-name-class-name-export.json | 14 +- .../get-admin-customer-delivery-edit.json | 10 ++ var/json_schema/get-admin-customer.json | 10 ++ .../get-admin-delivery-delivery-list.json | 10 ++ .../get-admin-delivery-delivery.json | 10 ++ .../get-admin-order-export-shipping.json | 10 ++ .../get-admin-order-import-shipping.json | 17 +- .../get-admin-order-mail-confirm.json | 12 +- .../get-admin-order-send-mail.json | 12 +- .../get-admin-order-shipping-address.json | 12 +- .../get-admin-order-shipping-notify-mail.json | 13 +- .../get-admin-payment-payment.json | 12 +- .../get-admin-product-csv-category.json | 12 +- .../get-admin-product-csv-class-category.json | 12 +- .../get-admin-product-csv-class-name.json | 12 +- .../get-admin-product-csv-product.json | 12 +- var/json_schema/get-admin-product-csv.json | 12 +- var/json_schema/get-admin-product-edit.json | 12 +- var/json_schema/get-admin-tag-tag-list.json | 12 +- .../get-admin-two-factor-auth-edit.json | 12 +- var/json_schema/get-contact-confirm.json | 12 +- var/json_schema/get-entry-confirm.json | 12 +- var/json_schema/get-forgot-password.json | 8 +- var/json_schema/get-mypage-address.json | 8 +- var/json_schema/get-mypage-change.json | 12 +- var/json_schema/get-mypage-history.json | 12 +- .../get-mypage-withdraw-confirm.json | 8 +- var/json_schema/get-mypage-withdraw.json | 8 +- var/json_schema/get-reset.json | 8 +- var/json_schema/get-shopping-login.json | 12 +- .../get-shopping-shipping-edit.json | 8 +- .../get-shopping-shipping-multiple-edit.json | 8 +- var/json_schema/get-shopping-shipping.json | 8 +- .../Admin/Category/CategoryList.html.twig | 4 +- .../Page/Admin/Product/CsvCategory.html.twig | 2 +- .../Page/Admin/Product/CsvClassName.html.twig | 2 +- 88 files changed, 572 insertions(+), 264 deletions(-) diff --git a/src/Resource/Page/Admin/BaseInfo.php b/src/Resource/Page/Admin/BaseInfo.php index 283996485..cbc1c475f 100644 --- a/src/Resource/Page/Admin/BaseInfo.php +++ b/src/Resource/Page/Admin/BaseInfo.php @@ -17,6 +17,7 @@ use MyVendor\BeMart\Be\Input\GetBaseInfoInput; use MyVendor\BeMart\Be\Input\UpdateBaseInfoInput; use MyVendor\BeMart\Form\AdminShopMasterForm; +use Ray\Csrf\CsrfTokenInterface; use Ray\WebFormModule\FormFactory; use BEAR\Resource\Annotation\JsonSchema; @@ -49,6 +50,7 @@ class BaseInfo extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -103,6 +105,7 @@ public function onGet(): static 'businessHour' => $final->businessHour, 'shopEmail01' => $final->shopEmail01, 'shopMessage' => $final->shopMessage, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Category/Category.php b/src/Resource/Page/Admin/Category/Category.php index 963065567..41772fba3 100644 --- a/src/Resource/Page/Admin/Category/Category.php +++ b/src/Resource/Page/Admin/Category/Category.php @@ -20,6 +20,7 @@ use MyVendor\BeMart\Be\Input\DeleteCategoryInput; use MyVendor\BeMart\Be\Input\GetAdminCategoryInput; use MyVendor\BeMart\Be\Input\UpdateCategoryInput; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -42,6 +43,7 @@ class Category extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -66,6 +68,7 @@ public function onGet(string $categoryId): static 'categoryName' => $final->categoryName, 'parentId' => $final->parentId, 'sortNo' => $final->sortNo, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Category/CategoryList.php b/src/Resource/Page/Admin/Category/CategoryList.php index 9d58e790c..2ffcd3c5f 100644 --- a/src/Resource/Page/Admin/Category/CategoryList.php +++ b/src/Resource/Page/Admin/Category/CategoryList.php @@ -19,6 +19,7 @@ use MyVendor\BeMart\Be\Input\CreateCategoryInput; use MyVendor\BeMart\Be\Input\GetAdminCategoryListInput; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; use function sprintf; @@ -47,6 +48,7 @@ class CategoryList extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -69,6 +71,7 @@ public function onGet(): static $this->body = [ 'count' => $final->count, 'categories' => $final->categories, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Category/Csv.php b/src/Resource/Page/Admin/Category/Csv.php index 9e16f2487..578013a81 100644 --- a/src/Resource/Page/Admin/Category/Csv.php +++ b/src/Resource/Page/Admin/Category/Csv.php @@ -16,6 +16,7 @@ use MyVendor\BeMart\Be\Final\CategoryCsvImported; use MyVendor\BeMart\Be\Input\ExportCategoryInput; use MyVendor\BeMart\Be\Input\ImportCategoryCsvInput; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -39,6 +40,7 @@ class Csv extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -58,6 +60,7 @@ public function onGet(): static $this->body = [ 'csv' => $final->csv, 'rowCount' => $final->rowCount, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Category/Edit.php b/src/Resource/Page/Admin/Category/Edit.php index 74d988f92..9be041a84 100644 --- a/src/Resource/Page/Admin/Category/Edit.php +++ b/src/Resource/Page/Admin/Category/Edit.php @@ -18,6 +18,7 @@ use MyVendor\BeMart\Be\Input\GetAdminCategoryListInput; use MyVendor\BeMart\Form\AdminCategoryForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -48,6 +49,7 @@ class Edit extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -79,6 +81,7 @@ public function onGet(string $categoryId = ''): static 'category' => null, 'categories' => $listFinal->categories, 'count' => $listFinal->count, + 'csrfToken' => $this->csrf->issue(), ]; return $this; @@ -106,6 +109,7 @@ public function onGet(string $categoryId = ''): static ], 'categories' => $listFinal->categories, 'count' => $listFinal->count, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/ChangePassword.php b/src/Resource/Page/Admin/ChangePassword.php index eb56abc72..31689ffe9 100644 --- a/src/Resource/Page/Admin/ChangePassword.php +++ b/src/Resource/Page/Admin/ChangePassword.php @@ -21,6 +21,7 @@ use MyVendor\BeMart\Be\Reason\Service\AdminSession; use MyVendor\BeMart\Form\AdminChangePasswordForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use SensitiveParameter; @@ -51,6 +52,7 @@ public function __construct( private readonly AdminSession $adminSession, private readonly FormFactory $formFactory, private readonly BecomingInterface $becoming, + private readonly CsrfTokenInterface $csrf, ) { } @@ -82,6 +84,7 @@ public function onGet(): static // to render via `{{ form.input(...) }}`. JSON contexts ignore // it. 'form' => $this->formFactory->newInstance(AdminChangePasswordForm::class), + 'csrfToken' => $this->csrf->issue(), ]; assert($this->body['form'] instanceof AdminChangePasswordForm); diff --git a/src/Resource/Page/Admin/ClassCategory/ClassCategoryExport.php b/src/Resource/Page/Admin/ClassCategory/ClassCategoryExport.php index 4febae1a3..3b8d286ea 100644 --- a/src/Resource/Page/Admin/ClassCategory/ClassCategoryExport.php +++ b/src/Resource/Page/Admin/ClassCategory/ClassCategoryExport.php @@ -12,6 +12,7 @@ use MyVendor\BeMart\Be\Exception\UnauthorizedAdminAccessException; use MyVendor\BeMart\Be\Final\ClassCategoryCsvExported; use MyVendor\BeMart\Be\Input\ExportClassCategoryInput; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -30,6 +31,7 @@ class ClassCategoryExport extends ResourceObject { public function __construct( private readonly BecomingInterface $becoming, + private readonly CsrfTokenInterface $csrf, ) { } @@ -53,7 +55,10 @@ public function onGet(string|null $classNameId = null): static // Japanese 規格分類名 decode correctly instead of mis-declaring Shift_JIS. $this->headers['Content-Type'] = 'text/csv; charset=UTF-8'; $this->headers['Content-Disposition'] = $final->document->contentDisposition; - $this->body = $final->document->content; + $this->body = [ + 'content' => $final->document->content, + 'csrfToken' => $this->csrf->issue(), + ]; return $this; } diff --git a/src/Resource/Page/Admin/ClassName/ClassNameExport.php b/src/Resource/Page/Admin/ClassName/ClassNameExport.php index f5cd85c12..751c4dfbc 100644 --- a/src/Resource/Page/Admin/ClassName/ClassNameExport.php +++ b/src/Resource/Page/Admin/ClassName/ClassNameExport.php @@ -12,6 +12,7 @@ use MyVendor\BeMart\Be\Exception\UnauthorizedAdminAccessException; use MyVendor\BeMart\Be\Final\ClassNameCsvExported; use MyVendor\BeMart\Be\Input\ExportClassNameInput; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -29,6 +30,7 @@ class ClassNameExport extends ResourceObject { public function __construct( private readonly BecomingInterface $becoming, + private readonly CsrfTokenInterface $csrf, ) { } @@ -49,7 +51,10 @@ public function onGet(): static // Japanese 規格名 decode correctly instead of mis-declaring Shift_JIS. $this->headers['Content-Type'] = 'text/csv; charset=UTF-8'; $this->headers['Content-Disposition'] = $final->document->contentDisposition; - $this->body = $final->document->content; + $this->body = [ + 'content' => $final->document->content, + 'csrfToken' => $this->csrf->issue(), + ]; return $this; } diff --git a/src/Resource/Page/Admin/Customer.php b/src/Resource/Page/Admin/Customer.php index ac8421734..efc3ee445 100644 --- a/src/Resource/Page/Admin/Customer.php +++ b/src/Resource/Page/Admin/Customer.php @@ -16,6 +16,7 @@ use MyVendor\BeMart\Be\Input\GetAdminCustomerInput; use MyVendor\BeMart\Form\AdminCustomerForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -60,6 +61,7 @@ class Customer extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -129,6 +131,7 @@ public function onGet( 'totalSpent' => $final->totalSpent, 'favorites' => $final->favorites, 'favoriteCount' => $final->favoriteCount, + 'csrfToken' => $this->csrf->issue(), ]; // Phase 3: an AdminCustomerForm pre-filled with the persisted // profile, for the HTML edit page (Customer.html.twig) to render diff --git a/src/Resource/Page/Admin/CustomerDeliveryEdit.php b/src/Resource/Page/Admin/CustomerDeliveryEdit.php index a8f7bb4fa..91af7ff41 100644 --- a/src/Resource/Page/Admin/CustomerDeliveryEdit.php +++ b/src/Resource/Page/Admin/CustomerDeliveryEdit.php @@ -11,6 +11,7 @@ use MyVendor\BeMart\Be\Reason\Service\AdminSession; use MyVendor\BeMart\Form\AdminCustomerDeliveryForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -33,6 +34,7 @@ class CustomerDeliveryEdit extends ResourceObject public function __construct( private readonly AdminSession $adminSession, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -66,6 +68,7 @@ public function onGet(string $customerId = '', string $id = ''): static $this->body = [ 'form' => $form, 'customerId' => $customerId, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Delivery/Delivery.php b/src/Resource/Page/Admin/Delivery/Delivery.php index 144bf3620..4ba8118da 100644 --- a/src/Resource/Page/Admin/Delivery/Delivery.php +++ b/src/Resource/Page/Admin/Delivery/Delivery.php @@ -22,6 +22,7 @@ use MyVendor\BeMart\Be\Input\UpdateDeliveryInput; use MyVendor\BeMart\Form\AdminDeliveryForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -42,6 +43,7 @@ public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -94,6 +96,7 @@ public function onGet(string $deliveryId = ''): static 'form' => $form, 'deliveryId' => $deliveryId, 'delivery' => $delivery, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Delivery/DeliveryList.php b/src/Resource/Page/Admin/Delivery/DeliveryList.php index 502249a9d..480bd383c 100644 --- a/src/Resource/Page/Admin/Delivery/DeliveryList.php +++ b/src/Resource/Page/Admin/Delivery/DeliveryList.php @@ -17,6 +17,7 @@ use MyVendor\BeMart\Be\Final\DeliveryCreated; use MyVendor\BeMart\Be\Input\CreateDeliveryInput; use MyVendor\BeMart\Be\Input\GetAdminDeliveryListInput; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -37,6 +38,7 @@ class DeliveryList extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -57,6 +59,7 @@ public function onGet(): static $this->body = [ 'count' => $final->count, 'deliveries' => $final->deliveries, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Order/ExportShipping.php b/src/Resource/Page/Admin/Order/ExportShipping.php index e8dc001d6..a2e2178de 100644 --- a/src/Resource/Page/Admin/Order/ExportShipping.php +++ b/src/Resource/Page/Admin/Order/ExportShipping.php @@ -12,6 +12,7 @@ use MyVendor\BeMart\Be\Exception\UnauthorizedAdminAccessException; use MyVendor\BeMart\Be\Final\AdminShippingCsvExported; use MyVendor\BeMart\Be\Input\AdminExportShippingInput; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -33,6 +34,7 @@ class ExportShipping extends ResourceObject { public function __construct( private readonly BecomingInterface $becoming, + private readonly CsrfTokenInterface $csrf, ) { } @@ -52,6 +54,7 @@ public function onGet(): static $this->body = [ 'csv' => $final->csv, 'rowCount' => $final->rowCount, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Order/ImportShipping.php b/src/Resource/Page/Admin/Order/ImportShipping.php index 7bbcfefad..6be93ba71 100644 --- a/src/Resource/Page/Admin/Order/ImportShipping.php +++ b/src/Resource/Page/Admin/Order/ImportShipping.php @@ -14,6 +14,7 @@ use MyVendor\BeMart\Be\Final\AdminShippingCsvImported; use MyVendor\BeMart\Be\Input\AdminImportShippingCsvInput; use MyVendor\BeMart\Be\Reason\Service\AdminSession; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -35,6 +36,7 @@ class ImportShipping extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly AdminSession $adminSession, + private readonly CsrfTokenInterface $csrf, ) { } @@ -61,7 +63,7 @@ public function onGet(): static } $this->code = Code::OK; - $this->body = []; + $this->body = ['csrfToken' => $this->csrf->issue()]; return $this; } diff --git a/src/Resource/Page/Admin/Order/MailConfirm.php b/src/Resource/Page/Admin/Order/MailConfirm.php index 25efc4026..01d3d2799 100644 --- a/src/Resource/Page/Admin/Order/MailConfirm.php +++ b/src/Resource/Page/Admin/Order/MailConfirm.php @@ -9,6 +9,7 @@ use BEAR\Resource\Code; use BEAR\Resource\ResourceObject; use MyVendor\BeMart\Be\Reason\Service\AdminSession; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -33,6 +34,7 @@ class MailConfirm extends ResourceObject { public function __construct( private readonly AdminSession $adminSession, + private readonly CsrfTokenInterface $csrf, ) { } @@ -56,6 +58,7 @@ public function onGet(string $orderNo = ''): static $this->code = Code::OK; $this->body = [ 'orderNo' => $orderNo, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Order/SendMail.php b/src/Resource/Page/Admin/Order/SendMail.php index 464b8d8cd..b25a05407 100644 --- a/src/Resource/Page/Admin/Order/SendMail.php +++ b/src/Resource/Page/Admin/Order/SendMail.php @@ -19,6 +19,7 @@ use MyVendor\BeMart\Form\AdminOrderMailForm; use Ray\WebFormModule\FormFactory; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; @@ -46,6 +47,7 @@ public function __construct( private readonly BecomingInterface $becoming, private readonly AdminSession $adminSession, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -85,6 +87,7 @@ public function onGet(string $orderNo = ''): static $this->body = [ 'form' => $form, 'orderNo' => $orderNo, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Order/ShippingAddress.php b/src/Resource/Page/Admin/Order/ShippingAddress.php index dace2b283..84eb2eca1 100644 --- a/src/Resource/Page/Admin/Order/ShippingAddress.php +++ b/src/Resource/Page/Admin/Order/ShippingAddress.php @@ -22,6 +22,7 @@ use MyVendor\BeMart\Form\AdminOrderShippingForm; use Ray\WebFormModule\FormFactory; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; @@ -59,6 +60,7 @@ public function __construct( private readonly BecomingInterface $becoming, private readonly AdminSession $adminSession, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -101,6 +103,7 @@ public function onGet(string $orderNo = ''): static $this->body = [ 'form' => $form, 'orderNo' => $orderNo, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Order/ShippingNotifyMail.php b/src/Resource/Page/Admin/Order/ShippingNotifyMail.php index 4c128ce94..b7684df3f 100644 --- a/src/Resource/Page/Admin/Order/ShippingNotifyMail.php +++ b/src/Resource/Page/Admin/Order/ShippingNotifyMail.php @@ -18,6 +18,7 @@ use MyVendor\BeMart\Be\Reason\Query\OrderQueryInterface; use MyVendor\BeMart\Be\Reason\Service\AdminSession; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; @@ -44,6 +45,7 @@ public function __construct( private readonly BecomingInterface $becoming, private readonly AdminSession $adminSession, private readonly OrderQueryInterface $orders, + private readonly CsrfTokenInterface $csrf, ) { } @@ -78,7 +80,7 @@ public function onGet(string $orderNo): static 'orderNo' => $order->orderNo, 'customerId' => $order->customerId, 'message' => '出荷通知メールを送信します。よろしいですか?', - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), 'submitTo' => [ 'method' => 'POST', 'href' => 'page://self/admin/order/shipping-notify-mail', diff --git a/src/Resource/Page/Admin/Payment/Payment.php b/src/Resource/Page/Admin/Payment/Payment.php index 6e8c313f8..dfe9d3c4f 100644 --- a/src/Resource/Page/Admin/Payment/Payment.php +++ b/src/Resource/Page/Admin/Payment/Payment.php @@ -23,6 +23,7 @@ use MyVendor\BeMart\Form\AdminPaymentForm; use Ray\WebFormModule\FormFactory; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; use function sprintf; @@ -42,6 +43,7 @@ public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -97,6 +99,7 @@ public function onGet(string $paymentId = ''): static 'form' => $form, 'paymentId' => $paymentId, 'payment' => $payment, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Product/CsvClassCategory.php b/src/Resource/Page/Admin/Product/CsvClassCategory.php index a0ebbe914..6234e058a 100644 --- a/src/Resource/Page/Admin/Product/CsvClassCategory.php +++ b/src/Resource/Page/Admin/Product/CsvClassCategory.php @@ -11,6 +11,7 @@ use Be\Framework\BecomingInterface; use Be\Framework\Exception\SemanticVariableException; use Ray\Csrf\Attribute\CsrfToken; +use Ray\Csrf\CsrfTokenInterface; use MyVendor\BeMart\Be\Exception\UnauthorizedAdminAccessException; use MyVendor\BeMart\Be\Final\ClassCategoryCsvImported; use MyVendor\BeMart\Be\Input\ImportClassCategoryCsvInput; @@ -39,10 +40,11 @@ class CsvClassCategory extends AbstractCsvUpload public function __construct( AdminSession $adminSession, FormFactory $formFactory, + CsrfTokenInterface $csrf, private readonly BecomingInterface $becoming, private readonly MutationResponseInterface $mutationResponse, ) { - parent::__construct($adminSession, $formFactory); + parent::__construct($adminSession, $formFactory, $csrf); } /** ALPS `goExportClassCategory` に対応する GET 操作。 */ diff --git a/src/Resource/Page/Admin/Product/CsvClassName.php b/src/Resource/Page/Admin/Product/CsvClassName.php index 2184e623d..403ebfe0f 100644 --- a/src/Resource/Page/Admin/Product/CsvClassName.php +++ b/src/Resource/Page/Admin/Product/CsvClassName.php @@ -11,6 +11,7 @@ use Be\Framework\BecomingInterface; use Be\Framework\Exception\SemanticVariableException; use Ray\Csrf\Attribute\CsrfToken; +use Ray\Csrf\CsrfTokenInterface; use MyVendor\BeMart\Be\Exception\UnauthorizedAdminAccessException; use MyVendor\BeMart\Be\Final\ClassNameCsvImported; use MyVendor\BeMart\Be\Input\ImportClassNameCsvInput; @@ -39,10 +40,11 @@ class CsvClassName extends AbstractCsvUpload public function __construct( AdminSession $adminSession, FormFactory $formFactory, + CsrfTokenInterface $csrf, private readonly BecomingInterface $becoming, private readonly MutationResponseInterface $mutationResponse, ) { - parent::__construct($adminSession, $formFactory); + parent::__construct($adminSession, $formFactory, $csrf); } /** ALPS `goExportClassName` に対応する GET 操作。 */ diff --git a/src/Resource/Page/Admin/Product/Edit.php b/src/Resource/Page/Admin/Product/Edit.php index 7e30ae7d1..d5281075c 100644 --- a/src/Resource/Page/Admin/Product/Edit.php +++ b/src/Resource/Page/Admin/Product/Edit.php @@ -18,6 +18,7 @@ use MyVendor\BeMart\Form\AdminProductEditForm; use Ray\WebFormModule\FormFactory; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; @@ -49,6 +50,7 @@ public function __construct( private readonly BecomingInterface $becoming, private readonly AdminSession $adminSession, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -86,6 +88,7 @@ public function onGet(string $productCode = ''): static 'form' => $form, 'productCode' => '', 'product' => null, + 'csrfToken' => $this->csrf->issue(), ]; return $this; @@ -120,6 +123,7 @@ public function onGet(string $productCode = ''): static 'searchWord' => $final->searchWord, 'note' => $final->note, ], + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/ProductCsv.php b/src/Resource/Page/Admin/ProductCsv.php index a31b1e15c..55e91c77b 100644 --- a/src/Resource/Page/Admin/ProductCsv.php +++ b/src/Resource/Page/Admin/ProductCsv.php @@ -19,6 +19,7 @@ use MyVendor\BeMart\Be\Input\AdminCreateProductInput; use MyVendor\BeMart\Be\Input\AdminExportProductInput; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function array_flip; use function assert; @@ -56,6 +57,7 @@ class ProductCsv extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -77,6 +79,7 @@ public function onGet(): static $this->body = [ 'csv' => $final->csv, 'count' => $final->count, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Admin/Tag/TagList.php b/src/Resource/Page/Admin/Tag/TagList.php index 7ed43a031..2eb97a307 100644 --- a/src/Resource/Page/Admin/Tag/TagList.php +++ b/src/Resource/Page/Admin/Tag/TagList.php @@ -20,6 +20,7 @@ use MyVendor\BeMart\Form\AdminTagForm; use Ray\WebFormModule\FormFactory; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; @@ -32,6 +33,7 @@ public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -50,6 +52,7 @@ public function onGet(): static $this->body = [ 'count' => $final->count, 'tags' => $final->tags, + 'csrfToken' => $this->csrf->issue(), ]; // Phase 3: an empty AdminTagForm for the HTML list page to render // the inline-create input via `{{ form.input('name') }}`. JSON diff --git a/src/Resource/Page/Admin/TwoFactorAuthEdit.php b/src/Resource/Page/Admin/TwoFactorAuthEdit.php index 9a5fe121f..12d223e61 100644 --- a/src/Resource/Page/Admin/TwoFactorAuthEdit.php +++ b/src/Resource/Page/Admin/TwoFactorAuthEdit.php @@ -11,6 +11,7 @@ use MyVendor\BeMart\Form\AdminTwoFactorAuthForm; use Ray\WebFormModule\FormFactory; use BEAR\Resource\Annotation\JsonSchema; +use Ray\Csrf\CsrfTokenInterface; use function assert; @@ -26,6 +27,7 @@ class TwoFactorAuthEdit extends ResourceObject public function __construct( private readonly AdminSession $adminSession, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } /** ALPS `goAdminTwoFactorAuthEdit` に対応する GET 操作。 */ @@ -51,6 +53,7 @@ public function onGet(): static 'authKey' => '', 'memberName' => $adminId, 'shopName' => 'BeMart', + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Contact/Confirm.php b/src/Resource/Page/Contact/Confirm.php index 7165afaaf..4224ecc6a 100644 --- a/src/Resource/Page/Contact/Confirm.php +++ b/src/Resource/Page/Contact/Confirm.php @@ -10,6 +10,7 @@ use BEAR\Resource\ResourceObject; use MyVendor\BeMart\Form\ContactConfirmForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -47,6 +48,7 @@ class Confirm extends ResourceObject { public function __construct( private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -74,6 +76,7 @@ public function onGet(): static 'page' => 'contact-confirm', 'title' => 'お問い合わせ', ], + 'csrfToken' => $this->csrf->issue(), // Phase 3: the confirm screen carries the inquiry payload as // hidden inputs — a ContactConfirmForm (every field `hidden`). // JSON contexts ignore `body['form']`. diff --git a/src/Resource/Page/Entry/Confirm.php b/src/Resource/Page/Entry/Confirm.php index de74d260c..47e1bc8a3 100644 --- a/src/Resource/Page/Entry/Confirm.php +++ b/src/Resource/Page/Entry/Confirm.php @@ -10,6 +10,7 @@ use BEAR\Resource\ResourceObject; use MyVendor\BeMart\Form\EntryConfirmForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -51,6 +52,7 @@ class Confirm extends ResourceObject { public function __construct( private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -79,6 +81,7 @@ public function onGet(): static 'page' => 'entry-confirm', 'title' => '新規会員登録(確認)', ], + 'csrfToken' => $this->csrf->issue(), // Phase 3: the confirm screen carries the registration payload // as hidden inputs — an EntryConfirmForm (every field `hidden`). // JSON contexts ignore `body['form']`. diff --git a/src/Resource/Page/ForgotPassword.php b/src/Resource/Page/ForgotPassword.php index 91c084e95..813751c2a 100644 --- a/src/Resource/Page/ForgotPassword.php +++ b/src/Resource/Page/ForgotPassword.php @@ -15,6 +15,7 @@ use MyVendor\BeMart\Be\Input\RequestPasswordResetInput; use MyVendor\BeMart\Form\ForgotForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -43,6 +44,7 @@ class ForgotPassword extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -52,8 +54,6 @@ public function __construct( * * Pure form-info endpoint: no Be Framework, no domain logic. * Anonymous-accessible (returns 200 regardless of session state). - * `csrfToken` stays `null` — the EventListener mirrors the Symfony - * token into the session for the subsequent POST (same as Login). */ #[Alps('doRequestPasswordReset')] #[JsonSchema(schema: 'get-forgot-password.json')] @@ -69,7 +69,7 @@ public function onGet(): static 'method' => 'POST', 'href' => 'page://self/forgot-password', ], - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), // Phase 3: an empty ForgotForm for the HTML port to render // via `{{ form.input(...) }}`. JSON contexts ignore it. 'form' => $this->formFactory->newInstance(ForgotForm::class), diff --git a/src/Resource/Page/Mypage/Address.php b/src/Resource/Page/Mypage/Address.php index d372a6f28..d021645db 100644 --- a/src/Resource/Page/Mypage/Address.php +++ b/src/Resource/Page/Mypage/Address.php @@ -23,6 +23,7 @@ use MyVendor\BeMart\Be\Reason\Service\CustomerSession; use MyVendor\BeMart\Form\AddressForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function array_filter; @@ -59,6 +60,7 @@ public function __construct( private readonly AddressStorageInterface $addresses, private readonly FormFactory $formFactory, private readonly MutationResponseInterface $mutationResponse, + private readonly CsrfTokenInterface $csrf, ) { } @@ -144,7 +146,7 @@ public function onGet(string|null $addressId = null): static 'submitTo' => $addressId === null ? ['method' => 'POST', 'href' => 'page://self/mypage/address-list'] : ['method' => 'PUT', 'href' => 'page://self/mypage/address'], - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), 'form' => $form, ]; diff --git a/src/Resource/Page/Mypage/Change.php b/src/Resource/Page/Mypage/Change.php index 0c4234122..211d1659e 100644 --- a/src/Resource/Page/Mypage/Change.php +++ b/src/Resource/Page/Mypage/Change.php @@ -19,6 +19,7 @@ use MyVendor\BeMart\Be\Input\UpdateCustomerInput; use MyVendor\BeMart\Form\ChangeForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function array_filter; @@ -42,6 +43,7 @@ class Change extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -101,6 +103,7 @@ public function onGet(): static 'addr01' => $final->addr01, 'addr02' => $final->addr02, 'submitTo' => $final->submitTo, + 'csrfToken' => $this->csrf->issue(), // Phase 3: a ChangeForm pre-populated with the current // profile for the HTML port. JSON contexts ignore it. 'form' => $form, diff --git a/src/Resource/Page/Mypage/History.php b/src/Resource/Page/Mypage/History.php index aac510938..d92539083 100644 --- a/src/Resource/Page/Mypage/History.php +++ b/src/Resource/Page/Mypage/History.php @@ -15,6 +15,7 @@ use MyVendor\BeMart\Be\Exception\UnauthorizedOrderAccessException; use MyVendor\BeMart\Be\Final\MypageHistoryFetched; use MyVendor\BeMart\Be\Input\GetMypageHistoryInput; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -37,6 +38,7 @@ class History extends ResourceObject { public function __construct( private readonly BecomingInterface $becoming, + private readonly CsrfTokenInterface $csrf, ) { } @@ -73,6 +75,7 @@ public function onGet(string $orderNo): static 'paymentDate' => $final->paymentDate, 'shippings' => $final->shippings, 'mailHistories' => $final->mailHistories, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Mypage/Withdraw.php b/src/Resource/Page/Mypage/Withdraw.php index 8fe5a7eb5..b8f6dee04 100644 --- a/src/Resource/Page/Mypage/Withdraw.php +++ b/src/Resource/Page/Mypage/Withdraw.php @@ -18,6 +18,7 @@ use MyVendor\BeMart\Be\Final\CustomerWithdrawn; use MyVendor\BeMart\Be\Input\WithdrawCustomerInput; use MyVendor\BeMart\Be\Reason\Service\CustomerSession; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use function assert; @@ -47,6 +48,7 @@ public function __construct( private readonly CartSessionPrefixInterface $cartSessionPrefix, private readonly MutationResponseInterface $mutationResponse, private readonly CustomerSessionWriterInterface $sessionWriter, + private readonly CsrfTokenInterface $csrf, ) { } @@ -59,9 +61,7 @@ public function __construct( * * Surfaces the current customer's email + name01/name02 so the * confirm page can render "退会されるアカウント: name01 name02 - * (email)". `csrfToken` body field stays `null` — EventListener - * mirrors the Symfony token into the session for the subsequent - * POST. + * (email)". */ #[Alps('goMypageWithdraw')] #[JsonSchema(schema: 'get-mypage-withdraw.json')] @@ -97,7 +97,7 @@ public function onGet(): static 'method' => 'POST', 'href' => 'page://self/mypage/withdraw', ], - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), 'customerId' => (string) $profile->body['customerId'], 'email' => (string) $profile->body['email'], 'name01' => (string) $profile->body['name01'], diff --git a/src/Resource/Page/Mypage/WithdrawConfirm.php b/src/Resource/Page/Mypage/WithdrawConfirm.php index f4a516904..35967ec54 100644 --- a/src/Resource/Page/Mypage/WithdrawConfirm.php +++ b/src/Resource/Page/Mypage/WithdrawConfirm.php @@ -8,6 +8,7 @@ use BEAR\Resource\Annotation\Link; use BEAR\Resource\Code; use BEAR\Resource\ResourceObject; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -38,8 +39,7 @@ * var/templates/README.md) no AbstractForm is needed; the form-page * recipe's `Form` exists for screens that render `` fields. * The submit target is doWithdrawCustomer (`page://self/mypage/withdraw`, - * POST). `csrfToken` stays null — the EventListener mirrors the live - * Symfony token into the body for the subsequent POST. + * POST). * * The Mypage navi welcome line reads `name01`/`name02` from the page * body, which are absent here (the customer name is a MISSING BODY @@ -50,6 +50,11 @@ */ class WithdrawConfirm extends ResourceObject { + public function __construct( + private readonly CsrfTokenInterface $csrf, + ) { + } + /** ALPS `goMypageWithdrawConfirm` に対応する GET 操作。 */ #[Alps('goMypageWithdrawConfirm')] #[JsonSchema(schema: 'get-mypage-withdraw-confirm.json')] @@ -65,7 +70,7 @@ public function onGet(): static 'method' => 'POST', 'href' => 'page://self/mypage/withdraw', ], - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Reset.php b/src/Resource/Page/Reset.php index 3ab8f2767..d60341e68 100644 --- a/src/Resource/Page/Reset.php +++ b/src/Resource/Page/Reset.php @@ -16,6 +16,7 @@ use MyVendor\BeMart\Be\Input\ResetPasswordInput; use MyVendor\BeMart\Form\ResetForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; use SensitiveParameter; @@ -43,6 +44,7 @@ class Reset extends ResourceObject public function __construct( private readonly BecomingInterface $becoming, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -54,8 +56,6 @@ public function __construct( * Anonymous-accessible (the reset-key check is the POST's job). The * `resetKey` arrives as a query param on the emailed reset link and * is carried into a hidden form field for the subsequent POST. - * `csrfToken` stays `null` — the EventListener mirrors the Symfony - * token into the session for the POST (same as Login). * * @psalm-taint-source input $resetKey */ @@ -74,7 +74,7 @@ public function onGet(#[SensitiveParameter] string|null $resetKey = null): stati 'href' => 'page://self/reset', ], 'resetKey' => $resetKey, - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), // Phase 3: an empty ResetForm for the HTML port to render // via `{{ form.input(...) }}`. JSON contexts ignore it. 'form' => $this->formFactory->newInstance(ResetForm::class), diff --git a/src/Resource/Page/Shopping/Login.php b/src/Resource/Page/Shopping/Login.php index 450b5a544..5c151adb7 100644 --- a/src/Resource/Page/Shopping/Login.php +++ b/src/Resource/Page/Shopping/Login.php @@ -10,6 +10,7 @@ use BEAR\Resource\ResourceObject; use MyVendor\BeMart\Form\LoginForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -39,6 +40,7 @@ class Login extends ResourceObject { public function __construct( private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -56,6 +58,7 @@ public function onGet(): static 'fields' => [], 'submitTo' => null, 'staticContent' => null, + 'csrfToken' => $this->csrf->issue(), // Phase 3: an empty LoginForm for the HTML port to render // the checkout-login inputs. JSON contexts ignore it. 'form' => $this->formFactory->newInstance(LoginForm::class), diff --git a/src/Resource/Page/Shopping/Shipping.php b/src/Resource/Page/Shopping/Shipping.php index b7c33c504..41156083a 100644 --- a/src/Resource/Page/Shopping/Shipping.php +++ b/src/Resource/Page/Shopping/Shipping.php @@ -9,6 +9,7 @@ use BEAR\Resource\Code; use BEAR\Resource\ResourceObject; use Ray\Csrf\Attribute\CsrfToken; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -27,6 +28,11 @@ */ class Shipping extends ResourceObject { + public function __construct( + private readonly CsrfTokenInterface $csrf, + ) { + } + /** * ALPS `goShoppingShipping` に対応する GET 操作。 * @todo Wave-future: surface the authenticated customer's @@ -52,7 +58,7 @@ public function onGet(): static ], 'staticContent' => null, 'addresses' => [], - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/src/Resource/Page/Shopping/ShippingEdit.php b/src/Resource/Page/Shopping/ShippingEdit.php index fb67c4439..c09719018 100644 --- a/src/Resource/Page/Shopping/ShippingEdit.php +++ b/src/Resource/Page/Shopping/ShippingEdit.php @@ -11,6 +11,7 @@ use Ray\Csrf\Attribute\CsrfToken; use MyVendor\BeMart\Form\ShoppingShippingEditForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -35,6 +36,7 @@ class ShippingEdit extends ResourceObject { public function __construct( private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -71,7 +73,7 @@ public function onGet(): static 'href' => 'page://self/shopping/shipping-edit', ], 'staticContent' => null, - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), // Phase 3: an empty ShoppingShippingEditForm for the HTML // port to render the address inputs. JSON contexts ignore it. 'form' => $this->formFactory->newInstance(ShoppingShippingEditForm::class), diff --git a/src/Resource/Page/Shopping/ShippingMultipleEdit.php b/src/Resource/Page/Shopping/ShippingMultipleEdit.php index adb44ca48..f8f34e37f 100644 --- a/src/Resource/Page/Shopping/ShippingMultipleEdit.php +++ b/src/Resource/Page/Shopping/ShippingMultipleEdit.php @@ -11,6 +11,7 @@ use Ray\Csrf\Attribute\CsrfToken; use MyVendor\BeMart\Form\ShoppingShippingEditForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use BEAR\Resource\Annotation\JsonSchema; /** @@ -47,6 +48,7 @@ class ShippingMultipleEdit extends ResourceObject { public function __construct( private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -83,7 +85,7 @@ public function onGet(): static 'href' => 'page://self/shopping/shipping-multiple-edit', ], 'staticContent' => null, - 'csrfToken' => null, + 'csrfToken' => $this->csrf->issue(), // Phase 3: an empty ShoppingShippingEditForm (the shared // CustomerAddressType shape) for the HTML port to render the // address inputs. JSON contexts ignore it. diff --git a/src/Support/Resource/AbstractCsvUpload.php b/src/Support/Resource/AbstractCsvUpload.php index 330c2a5a0..470751c76 100644 --- a/src/Support/Resource/AbstractCsvUpload.php +++ b/src/Support/Resource/AbstractCsvUpload.php @@ -10,6 +10,7 @@ use MyVendor\BeMart\Be\Reason\Service\AdminSession; use MyVendor\BeMart\Form\AdminCsvUploadForm; use Ray\WebFormModule\FormFactory; +use Ray\Csrf\CsrfTokenInterface; use function assert; @@ -35,6 +36,7 @@ abstract class AbstractCsvUpload extends ResourceObject public function __construct( private readonly AdminSession $adminSession, private readonly FormFactory $formFactory, + private readonly CsrfTokenInterface $csrf, ) { } @@ -70,6 +72,7 @@ public function onGet(): static 'csvTitle' => $this->csvTitle(), 'skeletonRoute' => $this->skeletonRoute(), 'columns' => $this->columns(), + 'csrfToken' => $this->csrf->issue(), ]; return $this; diff --git a/tests/Html/CsrfTokenRenderedTest.php b/tests/Html/CsrfTokenRenderedTest.php index c0e95735d..d0e7b25db 100644 --- a/tests/Html/CsrfTokenRenderedTest.php +++ b/tests/Html/CsrfTokenRenderedTest.php @@ -18,6 +18,9 @@ use Override; use PHPUnit\Framework\TestCase; use Ray\Di\AbstractModule; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use SplFileInfo; use function array_diff_key; use function array_keys; @@ -26,6 +29,7 @@ use function json_decode; use function ksort; use function preg_match_all; +use function str_contains; use function str_starts_with; use const JSON_THROW_ON_ERROR; @@ -40,22 +44,23 @@ * create forms stayed dead while per-page tests asserted only the field name. * * The bound adapter returns a fixed non-empty token, so an empty value can only - * mean the resource body lacks `csrfToken`. The remaining pages are recorded in - * the ledger so the set can only shrink: + * mean the resource body lacks `csrfToken`. #139 closed the ledger: every page + * publishes the field from the `CsrfTokenInterface` port now, including the + * three pages (`admin/category/category-list`, `admin/product/csv-category`, + * `admin/product/csv-class-name`) that used to fill the field from the + * `csrf_token()` Twig function instead — a helper that reads `$_SESSION` + * directly and so rendered non-empty while the resource published nothing, + * invisible to this sweep. The ledger stays as a regression guard: a page + * whose resource stops publishing the field, or a template that reaches for + * `csrf_token()` again, fails here instead of at submit time in production. + * + * `reason` values a re-opened entry may use: * * nullByDesign the resource sets `csrfToken => null` on purpose, waiting for * the EC-CUBE EventListener that mirrors the Symfony token into * the session (see EccubeSharedCsrfTokenAdapter's docblock). * notPublished the resource simply never publishes the field. * - * An empty ledger would not mean every page reaches the `CsrfToken` port. A - * template may fill the field from the `csrf_token()` Twig function instead, - * which reads `$_SESSION` directly, so the page renders non-empty while its - * resource publishes nothing and this sweep never sees it. Three pages do that - * today — `admin/category/category-list` (2 fields), `admin/product/csv-category` - * and `admin/product/csv-class-name` — and none of them appear below. They are - * tracked with the rest in #139. - * * @psalm-type Entry = array{fields: int, reason: string} */ final class CsrfTokenRenderedTest extends TestCase @@ -86,6 +91,32 @@ public function testEveryPageWithAnEmptyCsrfFieldIsRecorded(): void ); } + /** + * The regex sweep in {@see testEveryPageWithAnEmptyCsrfFieldIsRecorded} only catches an + * *empty* rendered field; a template that fills it via the `csrf_token()` Twig function + * instead of the resource-published value renders non-empty and slips past that sweep + * entirely (that was the #139 blindspot for `admin/category/category-list`, + * `admin/product/csv-category`, `admin/product/csv-class-name`). Guard the closed ledger + * directly: no template may call the session-reading helper at all. + */ + public function testNoTemplateFallsBackToTheSessionReadingCsrfHelper(): void + { + $offenders = []; + foreach ($this->twigFiles() as $file) { + $contents = (string) file_get_contents($file->getPathname()); + if (str_contains($contents, 'csrf_token(')) { + $offenders[] = $file->getPathname(); + } + } + + $this->assertSame( + [], + $offenders, + "Template(s) fill csrfToken via the \$_SESSION-reading Twig helper instead of the resource-published value:\n" + . implode("\n", $offenders), + ); + } + public function testLedgerEntriesAreWellFormed(): void { foreach ($this->ledger() as $key => $entry) { @@ -158,4 +189,24 @@ protected function configure(): void return HtmlTestInjector::getOverrideInstance($module)->getInstance(ResourceInterface::class); } + + /** @return list */ + private function twigFiles(): array + { + $files = []; + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(__DIR__ . '/../../var/templates'), + ); + foreach ($iterator as $file) { + if (! $file instanceof SplFileInfo || ! $file->isFile()) { + continue; + } + + if ($file->getExtension() === 'twig') { + $files[] = $file; + } + } + + return $files; + } } diff --git a/tests/Html/csrf-empty-token-ledger.json b/tests/Html/csrf-empty-token-ledger.json index a6b13bba4..0967ef424 100644 --- a/tests/Html/csrf-empty-token-ledger.json +++ b/tests/Html/csrf-empty-token-ledger.json @@ -1,150 +1 @@ -{ - "GET page://self/admin/base-info": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/category/category": { - "fields": 2, - "reason": "notPublished" - }, - "GET page://self/admin/category/csv": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/category/edit": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/change-password": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/class-category/class-category-export": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/class-name/class-name-export": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/customer": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/customer-delivery-edit": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/delivery/delivery": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/delivery/delivery-list": { - "fields": 2, - "reason": "notPublished" - }, - "GET page://self/admin/order/export-shipping": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/order/import-shipping": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/order/mail-confirm": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/order/send-mail": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/order/shipping-address": { - "fields": 2, - "reason": "notPublished" - }, - "GET page://self/admin/order/shipping-notify-mail": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/admin/payment/payment": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/product-csv": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/product/csv-class-category": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/product/csv-product": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/product/edit": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/tag/tag-list": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/admin/two-factor-auth-edit": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/contact/confirm": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/entry/confirm": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/forgot-password": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/mypage/address": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/mypage/change": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/mypage/history": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/mypage/withdraw": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/mypage/withdraw-confirm": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/reset": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/shopping/login": { - "fields": 1, - "reason": "notPublished" - }, - "GET page://self/shopping/shipping": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/shopping/shipping-edit": { - "fields": 1, - "reason": "nullByDesign" - }, - "GET page://self/shopping/shipping-multiple-edit": { - "fields": 1, - "reason": "nullByDesign" - } -} +{} diff --git a/tests/Resource/AdminClassCsvResourceTest.php b/tests/Resource/AdminClassCsvResourceTest.php index f5f1272e9..7a559d60b 100644 --- a/tests/Resource/AdminClassCsvResourceTest.php +++ b/tests/Resource/AdminClassCsvResourceTest.php @@ -62,7 +62,7 @@ public function testExportClassNameDownload(): void // (regression guard for issue #30: the two exports must not swap // their Content-Disposition filenames). $this->assertSame('attachment; filename="class_name.csv"', $ro->headers['Content-Disposition']); - $this->assertTrue(is_string($ro->body)); + $this->assertTrue(is_string($ro->body['content'])); } public function testExportClassCategoryDownload(): void diff --git a/tests/Resource/ShoppingShippingResourceTest.php b/tests/Resource/ShoppingShippingResourceTest.php index 910ab4303..bdf1a1c7a 100644 --- a/tests/Resource/ShoppingShippingResourceTest.php +++ b/tests/Resource/ShoppingShippingResourceTest.php @@ -38,7 +38,7 @@ public function testOnGetShippingReturnsExpectedShape(): void $this->assertSame('page://self/shopping/shipping', $ro->body['submitTo']['href']); // Address data lookup is a Wave-future TODO — empty list for now. $this->assertSame([], $ro->body['addresses']); - $this->assertNull($ro->body['csrfToken']); + $this->assertSame(FakeCsrfToken::TOKEN, $ro->body['csrfToken']); } public function testOnGetShippingEditReturnsExpectedShape(): void @@ -53,7 +53,7 @@ public function testOnGetShippingEditReturnsExpectedShape(): void $this->assertContains('csrfToken', $ro->body['fields']); $this->assertSame('POST', $ro->body['submitTo']['method']); $this->assertSame('page://self/shopping/shipping-edit', $ro->body['submitTo']['href']); - $this->assertNull($ro->body['csrfToken']); + $this->assertSame(FakeCsrfToken::TOKEN, $ro->body['csrfToken']); } public function testOnGetShippingMultipleReturnsExpectedShape(): void diff --git a/tests/Resource/Sql/WithdrawResourceSqlTest.php b/tests/Resource/Sql/WithdrawResourceSqlTest.php index bb5e93781..8d74f228d 100644 --- a/tests/Resource/Sql/WithdrawResourceSqlTest.php +++ b/tests/Resource/Sql/WithdrawResourceSqlTest.php @@ -98,7 +98,7 @@ public function testOnGetReturnsFormMetadata(): void $this->assertSame(['csrfToken'], $ro->body['fields']); $this->assertSame('POST', $ro->body['submitTo']['method']); $this->assertSame('page://self/mypage/withdraw', $ro->body['submitTo']['href']); - $this->assertNull($ro->body['csrfToken']); + $this->assertSame(FakeCsrfToken::TOKEN, $ro->body['csrfToken']); } public function testOnGetShowsCurrentCustomer(): void diff --git a/tests/Resource/WithdrawResourceTest.php b/tests/Resource/WithdrawResourceTest.php index 23eb80537..0fa9e0888 100644 --- a/tests/Resource/WithdrawResourceTest.php +++ b/tests/Resource/WithdrawResourceTest.php @@ -69,7 +69,7 @@ public function testOnGetReturnsFormMetadata(): void $this->assertSame(['csrfToken'], $ro->body['fields']); $this->assertSame('POST', $ro->body['submitTo']['method']); $this->assertSame('page://self/mypage/withdraw', $ro->body['submitTo']['href']); - $this->assertNull($ro->body['csrfToken']); + $this->assertSame(FakeCsrfToken::TOKEN, $ro->body['csrfToken']); } public function testOnGetShowsCurrentCustomer(): void diff --git a/var/json_schema/get-admin-base-info.json b/var/json_schema/get-admin-base-info.json index b4e8759e8..32de01d33 100644 --- a/var/json_schema/get-admin-base-info.json +++ b/var/json_schema/get-admin-base-info.json @@ -147,6 +147,15 @@ "title": "ショップ名英語", "description": "ショップの英語名。多言語対応やメール署名等で使用 Fake観察文字長 12〜12; 観察値 'EC-CUBE SHOP'。", "example": "EC-CUBE SHOP" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -369,6 +378,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "shopKana", "businessHour", "addr01", diff --git a/var/json_schema/get-admin-category-category-list.json b/var/json_schema/get-admin-category-category-list.json index ff4778570..638a2c0b1 100644 --- a/var/json_schema/get-admin-category-category-list.json +++ b/var/json_schema/get-admin-category-category-list.json @@ -82,6 +82,15 @@ "$comment": "配列要素はFake/Resourceで観察された既知propertyに固定する。新しい列が必要になった場合はSemantic-Ex観察に追加してschemaを更新する。" }, "minItems": 0 + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -305,6 +314,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "count", - "categories" + "categories", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-category-category.json b/var/json_schema/get-admin-category-category.json index 861f36b9c..b9ae4a8fe 100644 --- a/var/json_schema/get-admin-category-category.json +++ b/var/json_schema/get-admin-category-category.json @@ -51,6 +51,15 @@ "maxLength": 128, "pattern": "^[A-Za-z0-9._:@/-]*$", "$comment": "BeMart/Fake境界で観察される不透明な文字列ID。DB採番値としての数値演算には使わない。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -273,6 +282,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "parentId", "categoryName", "sortNo", diff --git a/var/json_schema/get-admin-category-csv.json b/var/json_schema/get-admin-category-csv.json index 682ea0933..c225a822c 100644 --- a/var/json_schema/get-admin-category-csv.json +++ b/var/json_schema/get-admin-category-csv.json @@ -25,6 +25,15 @@ "$comment": "CSV列の業務妥当性はCSV互換サービスで検査する。ここではJSON境界上の文字列サイズを契約する。", "title": "輸送ペイロード", "description": "CSVインポート/エクスポート本文。列構造の詳細はCSV互換サービス境界で検査する。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -247,6 +256,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "rowCount", "csv" ] diff --git a/var/json_schema/get-admin-category-edit.json b/var/json_schema/get-admin-category-edit.json index ed45cf42d..dd499cf7f 100644 --- a/var/json_schema/get-admin-category-edit.json +++ b/var/json_schema/get-admin-category-edit.json @@ -123,6 +123,15 @@ "maxLength": 128, "pattern": "^[A-Za-z0-9._:@/-]*$", "$comment": "BeMart/Fake境界で観察される不透明な文字列ID。DB採番値としての数値演算には使わない。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -345,6 +354,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "categories", "count", "categoryId" diff --git a/var/json_schema/get-admin-change-password.json b/var/json_schema/get-admin-change-password.json index 100aa135b..7134addbd 100644 --- a/var/json_schema/get-admin-change-password.json +++ b/var/json_schema/get-admin-change-password.json @@ -38,6 +38,15 @@ "maxLength": 255, "description": "/admin/change-password のレスポンスに含まれる処理行。親コレクション `fields` の1行を表し、固定できる業務列はschema propertyで明示する。" } + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -260,6 +269,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "transitionId" ] } diff --git a/var/json_schema/get-admin-class-category-class-category-export.json b/var/json_schema/get-admin-class-category-class-category-export.json index 33627652a..d52be2376 100644 --- a/var/json_schema/get-admin-class-category-class-category-export.json +++ b/var/json_schema/get-admin-class-category-class-category-export.json @@ -5,13 +5,22 @@ "description": "GET /admin/class-category/class-category-export response の response body schema。ALPSの意味、be/var/fakeの観察値、Resource境界の実形状から導いたSemantic-Ex制約。", "type": "object", "properties": { - "value": { + "content": { "type": "string", "minLength": 0, "maxLength": 5000000, "title": "CSVエクスポート本文", "description": "/admin/class-category/class-category-export が返すCSV本文。列意味はCSV互換サービス側、JSON境界では文字列として契約する。", "$comment": "CSV列の意味検査はCSV互換サービスで扱い、ここではレスポンス本文としての文字列サイズを検査する。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -234,6 +243,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "value" + "content", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-class-name-class-name-export.json b/var/json_schema/get-admin-class-name-class-name-export.json index ed32c9b17..d1fd7d501 100644 --- a/var/json_schema/get-admin-class-name-class-name-export.json +++ b/var/json_schema/get-admin-class-name-class-name-export.json @@ -5,13 +5,22 @@ "description": "GET /admin/class-name/class-name-export response の response body schema。ALPSの意味、be/var/fakeの観察値、Resource境界の実形状から導いたSemantic-Ex制約。", "type": "object", "properties": { - "value": { + "content": { "type": "string", "minLength": 0, "maxLength": 5000000, "title": "CSVエクスポート本文", "description": "/admin/class-name/class-name-export が返すCSV本文。列意味はCSV互換サービス側、JSON境界では文字列として契約する。", "$comment": "CSV列の意味検査はCSV互換サービスで扱い、ここではレスポンス本文としての文字列サイズを検査する。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -234,6 +243,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "value" + "content", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-customer-delivery-edit.json b/var/json_schema/get-admin-customer-delivery-edit.json index 11e213792..3f6f0cf9a 100644 --- a/var/json_schema/get-admin-customer-delivery-edit.json +++ b/var/json_schema/get-admin-customer-delivery-edit.json @@ -27,6 +27,15 @@ "maxLength": 128, "pattern": "^[A-Za-z0-9._:@/-]*$", "$comment": "BeMart/Fake境界で観察される不透明な文字列ID。DB採番値としての数値演算には使わない。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -249,6 +258,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "customerId" ] } diff --git a/var/json_schema/get-admin-customer.json b/var/json_schema/get-admin-customer.json index a8bcd99d6..60cf28605 100644 --- a/var/json_schema/get-admin-customer.json +++ b/var/json_schema/get-admin-customer.json @@ -407,6 +407,15 @@ "maximum": 2147483647, "title": "注文件数", "description": "/admin/customer のレスポンスで返す注文件数。一覧・集計・処理結果の規模を表す非負整数。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -629,6 +638,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "initialPoint", "totalSpent", "name02", diff --git a/var/json_schema/get-admin-delivery-delivery-list.json b/var/json_schema/get-admin-delivery-delivery-list.json index 715e678ab..5cd41b515 100644 --- a/var/json_schema/get-admin-delivery-delivery-list.json +++ b/var/json_schema/get-admin-delivery-delivery-list.json @@ -68,6 +68,15 @@ "maximum": 2147483647, "title": "件数", "description": "/admin/delivery/delivery-list のレスポンスで返す件数。一覧・集計・処理結果の規模を表す非負整数。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -290,6 +299,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "deliveries", "count" ] diff --git a/var/json_schema/get-admin-delivery-delivery.json b/var/json_schema/get-admin-delivery-delivery.json index 434e9b243..59ff9e5ce 100644 --- a/var/json_schema/get-admin-delivery-delivery.json +++ b/var/json_schema/get-admin-delivery-delivery.json @@ -45,6 +45,15 @@ }, "minItems": 0, "$comment": "単一詳細画面では未選択/初期表示に空配列、取得済み状態にobjectが現れる。不透明な詳細構造は既知propertyを優先し、追加キーは互換境界として許容する。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -267,6 +276,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "deliveryId" ] } diff --git a/var/json_schema/get-admin-order-export-shipping.json b/var/json_schema/get-admin-order-export-shipping.json index 22c330da1..9830c259c 100644 --- a/var/json_schema/get-admin-order-export-shipping.json +++ b/var/json_schema/get-admin-order-export-shipping.json @@ -25,6 +25,15 @@ "$comment": "CSV列の業務妥当性はCSV互換サービスで検査する。ここではJSON境界上の文字列サイズを契約する。", "title": "輸送ペイロード", "description": "CSVインポート/エクスポート本文。列構造の詳細はCSV互換サービス境界で検査する。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -247,6 +256,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ + "csrfToken", "rowCount", "csv" ] diff --git a/var/json_schema/get-admin-order-import-shipping.json b/var/json_schema/get-admin-order-import-shipping.json index f4cf0a60b..f500186e6 100644 --- a/var/json_schema/get-admin-order-import-shipping.json +++ b/var/json_schema/get-admin-order-import-shipping.json @@ -4,7 +4,17 @@ "title": "GET /admin/order/import-shipping response", "description": "GET /admin/order/import-shipping response の response body schema。ALPSの意味、be/var/fakeの観察値、Resource境界の実形状から導いたSemantic-Ex制約。", "type": "object", - "properties": {}, + "properties": { + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" + } + }, "additionalProperties": false, "$defs": { "productCode": { @@ -223,5 +233,8 @@ } } }, - "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape." + "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", + "required": [ + "csrfToken" + ] } diff --git a/var/json_schema/get-admin-order-mail-confirm.json b/var/json_schema/get-admin-order-mail-confirm.json index ac4aaf047..a4826a02a 100644 --- a/var/json_schema/get-admin-order-mail-confirm.json +++ b/var/json_schema/get-admin-order-mail-confirm.json @@ -15,6 +15,15 @@ "title": "注文番号", "description": "顧客向けの注文番号。フォーマットはカスタマイズ可能 Fake観察文字長 32〜32; 観察値 'past0000000000000000000000000001'。", "example": "past0000000000000000000000000001" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -237,6 +246,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "orderNo" + "orderNo", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-order-send-mail.json b/var/json_schema/get-admin-order-send-mail.json index 55d1b49ab..effefa118 100644 --- a/var/json_schema/get-admin-order-send-mail.json +++ b/var/json_schema/get-admin-order-send-mail.json @@ -25,6 +25,15 @@ "title": "注文番号", "description": "顧客向けの注文番号。フォーマットはカスタマイズ可能 Fake観察文字長 32〜32; 観察値 'past0000000000000000000000000001'。", "example": "past0000000000000000000000000001" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -247,6 +256,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "orderNo" + "orderNo", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-order-shipping-address.json b/var/json_schema/get-admin-order-shipping-address.json index 6e9ecc7e6..356248485 100644 --- a/var/json_schema/get-admin-order-shipping-address.json +++ b/var/json_schema/get-admin-order-shipping-address.json @@ -25,6 +25,15 @@ "title": "注文番号", "description": "顧客向けの注文番号。フォーマットはカスタマイズ可能 Fake観察文字長 32〜32; 観察値 'past0000000000000000000000000001'。", "example": "past0000000000000000000000000001" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -247,6 +256,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "orderNo" + "orderNo", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-order-shipping-notify-mail.json b/var/json_schema/get-admin-order-shipping-notify-mail.json index 1795aa111..3201efe70 100644 --- a/var/json_schema/get-admin-order-shipping-notify-mail.json +++ b/var/json_schema/get-admin-order-shipping-notify-mail.json @@ -38,16 +38,13 @@ "example": "出荷通知メールを送信します。よろしいですか?" }, "csrfToken": { - "type": [ - "string", - "null" - ], + "type": "string", "title": "出荷通知メール送信フォームCSRFトークン", - "description": "POST /admin/order/shipping-notify-mail のhidden inputで送るCSRFトークン。Resource bodyではnullでも、Twigが実フォーム用トークンを補う。", - "minLength": 0, + "description": "POST /admin/order/shipping-notify-mail のhidden inputで送るCSRFトークン。", + "minLength": 8, "maxLength": 160, - "pattern": "^[A-Za-z0-9_.:-]*$", - "$comment": "CSRF値はRay.Csrf CsrfToken境界の責務。GET bodyではフォーム文脈を示すためにnullを許容する。" + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" }, "submitTo": { "type": "object", diff --git a/var/json_schema/get-admin-payment-payment.json b/var/json_schema/get-admin-payment-payment.json index 119b72bde..bb78a7d53 100644 --- a/var/json_schema/get-admin-payment-payment.json +++ b/var/json_schema/get-admin-payment-payment.json @@ -45,6 +45,15 @@ }, "minItems": 0, "$comment": "単一詳細画面では未選択/初期表示に空配列、取得済み状態にobjectが現れる。不透明な詳細構造は既知propertyを優先し、追加キーは互換境界として許容する。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -267,6 +276,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "paymentId" + "paymentId", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-product-csv-category.json b/var/json_schema/get-admin-product-csv-category.json index ecac4d39b..1b2d0ac01 100644 --- a/var/json_schema/get-admin-product-csv-category.json +++ b/var/json_schema/get-admin-product-csv-category.json @@ -76,6 +76,15 @@ "$comment": "配列要素はマスタ/CSV/option mapの動的行であり、列集合が対象種別により変わるため固定shape化しない。既知propertyは契約し、追加列は該当サービス境界で扱う。" }, "minItems": 0 + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -300,6 +309,7 @@ "required": [ "csvTitle", "skeletonRoute", - "columns" + "columns", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-product-csv-class-category.json b/var/json_schema/get-admin-product-csv-class-category.json index c76ba26de..b518eda86 100644 --- a/var/json_schema/get-admin-product-csv-class-category.json +++ b/var/json_schema/get-admin-product-csv-class-category.json @@ -76,6 +76,15 @@ "$comment": "配列要素はマスタ/CSV/option mapの動的行であり、列集合が対象種別により変わるため固定shape化しない。既知propertyは契約し、追加列は該当サービス境界で扱う。" }, "minItems": 0 + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -300,6 +309,7 @@ "required": [ "csvTitle", "skeletonRoute", - "columns" + "columns", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-product-csv-class-name.json b/var/json_schema/get-admin-product-csv-class-name.json index f5c3e8d8e..05b26d3e5 100644 --- a/var/json_schema/get-admin-product-csv-class-name.json +++ b/var/json_schema/get-admin-product-csv-class-name.json @@ -76,6 +76,15 @@ "$comment": "配列要素はマスタ/CSV/option mapの動的行であり、列集合が対象種別により変わるため固定shape化しない。既知propertyは契約し、追加列は該当サービス境界で扱う。" }, "minItems": 0 + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -300,6 +309,7 @@ "required": [ "csvTitle", "skeletonRoute", - "columns" + "columns", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-product-csv-product.json b/var/json_schema/get-admin-product-csv-product.json index 7f6276500..34caa74bc 100644 --- a/var/json_schema/get-admin-product-csv-product.json +++ b/var/json_schema/get-admin-product-csv-product.json @@ -76,6 +76,15 @@ "$comment": "配列要素はマスタ/CSV/option mapの動的行であり、列集合が対象種別により変わるため固定shape化しない。既知propertyは契約し、追加列は該当サービス境界で扱う。" }, "minItems": 0 + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -300,6 +309,7 @@ "required": [ "csvTitle", "skeletonRoute", - "columns" + "columns", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-product-csv.json b/var/json_schema/get-admin-product-csv.json index b1b8d54d9..a04c02c1a 100644 --- a/var/json_schema/get-admin-product-csv.json +++ b/var/json_schema/get-admin-product-csv.json @@ -25,6 +25,15 @@ "$comment": "CSV列の業務妥当性はCSV互換サービスで検査する。ここではJSON境界上の文字列サイズを契約する。", "title": "輸送ペイロード", "description": "CSVインポート/エクスポート本文。列構造の詳細はCSV互換サービス境界で検査する。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -248,6 +257,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "count", - "csv" + "csv", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-product-edit.json b/var/json_schema/get-admin-product-edit.json index 13db61f3f..701f389f0 100644 --- a/var/json_schema/get-admin-product-edit.json +++ b/var/json_schema/get-admin-product-edit.json @@ -40,6 +40,15 @@ "minLength": 0, "maxLength": 64, "example": "sample-001" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -263,6 +272,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "product", - "productCode" + "productCode", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-tag-tag-list.json b/var/json_schema/get-admin-tag-tag-list.json index 2022ce0fc..1dfb621fd 100644 --- a/var/json_schema/get-admin-tag-tag-list.json +++ b/var/json_schema/get-admin-tag-tag-list.json @@ -69,6 +69,15 @@ "$comment": "配列要素はFake/Resourceで観察された既知propertyに固定する。新しい列が必要になった場合はSemantic-Ex観察に追加してschemaを更新する。" }, "minItems": 0 + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -292,6 +301,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "count", - "tags" + "tags", + "csrfToken" ] } diff --git a/var/json_schema/get-admin-two-factor-auth-edit.json b/var/json_schema/get-admin-two-factor-auth-edit.json index 974d35139..c41bac262 100644 --- a/var/json_schema/get-admin-two-factor-auth-edit.json +++ b/var/json_schema/get-admin-two-factor-auth-edit.json @@ -46,6 +46,15 @@ "title": "二要素認証キー", "description": "/admin/two-factor-auth-edit のレスポンスで扱う二要素認証キー。数値演算対象ではなく、照合・URL・配送追跡などに使う不透明な文字列識別子。", "$comment": "キー/追跡番号は照合用の不透明文字列で、数値演算対象ではない。" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -269,6 +278,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "memberName", - "shopName" + "shopName", + "csrfToken" ] } diff --git a/var/json_schema/get-contact-confirm.json b/var/json_schema/get-contact-confirm.json index 618e1f2b1..7cce3916c 100644 --- a/var/json_schema/get-contact-confirm.json +++ b/var/json_schema/get-contact-confirm.json @@ -117,6 +117,15 @@ "maxLength": 96, "pattern": "^(go|do)[A-Z][A-Za-z0-9]*$", "example": "doAddCartItem" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -339,6 +348,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-entry-confirm.json b/var/json_schema/get-entry-confirm.json index 88d3d7daf..4042c7437 100644 --- a/var/json_schema/get-entry-confirm.json +++ b/var/json_schema/get-entry-confirm.json @@ -117,6 +117,15 @@ "maxLength": 96, "pattern": "^(go|do)[A-Z][A-Za-z0-9]*$", "example": "doAddCartItem" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -339,6 +348,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-forgot-password.json b/var/json_schema/get-forgot-password.json index e0815792a..d08e5ee31 100644 --- a/var/json_schema/get-forgot-password.json +++ b/var/json_schema/get-forgot-password.json @@ -86,10 +86,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -316,6 +313,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-mypage-address.json b/var/json_schema/get-mypage-address.json index 96600c31e..823b23cb7 100644 --- a/var/json_schema/get-mypage-address.json +++ b/var/json_schema/get-mypage-address.json @@ -71,10 +71,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -315,6 +312,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "transitionId", - "addressId" + "addressId", + "csrfToken" ] } diff --git a/var/json_schema/get-mypage-change.json b/var/json_schema/get-mypage-change.json index d670e03f8..da3d6689d 100644 --- a/var/json_schema/get-mypage-change.json +++ b/var/json_schema/get-mypage-change.json @@ -192,6 +192,15 @@ "title": "会社名", "description": "法人顧客の社名。B2B取引やインボイスで使用 Fake観察文字長 10〜11; 観察値 'Acme Corp.', '株式会社EC-CUBE'; null 24/32。", "example": "Acme Corp." + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -418,6 +427,7 @@ "customerId", "name01", "email", - "addr01" + "addr01", + "csrfToken" ] } diff --git a/var/json_schema/get-mypage-history.json b/var/json_schema/get-mypage-history.json index be5c49fd8..f1319e08f 100644 --- a/var/json_schema/get-mypage-history.json +++ b/var/json_schema/get-mypage-history.json @@ -418,6 +418,15 @@ "example": 12700, "minimum": 0, "maximum": 999999999 + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -655,6 +664,7 @@ "subtotal", "discount", "shippings", - "total" + "total", + "csrfToken" ] } diff --git a/var/json_schema/get-mypage-withdraw-confirm.json b/var/json_schema/get-mypage-withdraw-confirm.json index f7f6b55ad..05cc0e341 100644 --- a/var/json_schema/get-mypage-withdraw-confirm.json +++ b/var/json_schema/get-mypage-withdraw-confirm.json @@ -76,10 +76,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -306,6 +303,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-mypage-withdraw.json b/var/json_schema/get-mypage-withdraw.json index b7a42f7df..c2cac16d8 100644 --- a/var/json_schema/get-mypage-withdraw.json +++ b/var/json_schema/get-mypage-withdraw.json @@ -107,10 +107,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -354,6 +351,7 @@ "email", "name02", "transitionId", - "customerId" + "customerId", + "csrfToken" ] } diff --git a/var/json_schema/get-reset.json b/var/json_schema/get-reset.json index cbf3db1ea..3a91c72e6 100644 --- a/var/json_schema/get-reset.json +++ b/var/json_schema/get-reset.json @@ -99,10 +99,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -330,6 +327,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "resetKey", - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-shopping-login.json b/var/json_schema/get-shopping-login.json index f940b6ecb..86aca128e 100644 --- a/var/json_schema/get-shopping-login.json +++ b/var/json_schema/get-shopping-login.json @@ -58,6 +58,15 @@ "maxLength": 96, "pattern": "^(go|do)[A-Z][A-Za-z0-9]*$", "example": "doAddCartItem" + }, + "csrfToken": { + "title": "CSRFトークン", + "description": "フォーム送信元を検証するトークン。Fake環境では deterministic な値を使う。", + "type": "string", + "minLength": 8, + "maxLength": 160, + "pattern": "^[A-Za-z0-9_.:-]+$", + "example": "fake-csrf-token-bemart-2026" } }, "additionalProperties": false, @@ -280,6 +289,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-shopping-shipping-edit.json b/var/json_schema/get-shopping-shipping-edit.json index 7ad6b19e3..770d11332 100644 --- a/var/json_schema/get-shopping-shipping-edit.json +++ b/var/json_schema/get-shopping-shipping-edit.json @@ -96,10 +96,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -326,6 +323,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-shopping-shipping-multiple-edit.json b/var/json_schema/get-shopping-shipping-multiple-edit.json index 3243d8f1c..88f677699 100644 --- a/var/json_schema/get-shopping-shipping-multiple-edit.json +++ b/var/json_schema/get-shopping-shipping-multiple-edit.json @@ -96,10 +96,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -326,6 +323,7 @@ }, "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ - "transitionId" + "transitionId", + "csrfToken" ] } diff --git a/var/json_schema/get-shopping-shipping.json b/var/json_schema/get-shopping-shipping.json index 55b504000..dd0e32e3d 100644 --- a/var/json_schema/get-shopping-shipping.json +++ b/var/json_schema/get-shopping-shipping.json @@ -205,10 +205,7 @@ "csrfToken": { "title": "処理識別子", "description": "フォーム送信の偽造を防ぐために送信元画面で発行されるトークン。Fake環境では deterministic な値を使う。", - "type": [ - "string", - "null" - ], + "type": "string", "minLength": 8, "maxLength": 160, "pattern": "^[A-Za-z0-9_.:-]+$", @@ -436,6 +433,7 @@ "$comment": "Derived from ALPS meaning, be/var/fake observation, and Resource schema shape.", "required": [ "transitionId", - "addresses" + "addresses", + "csrfToken" ] } diff --git a/var/templates/Page/Admin/Category/CategoryList.html.twig b/var/templates/Page/Admin/Category/CategoryList.html.twig index 2a6c4ee19..b35340f5b 100644 --- a/var/templates/Page/Admin/Category/CategoryList.html.twig +++ b/var/templates/Page/Admin/Category/CategoryList.html.twig @@ -84,7 +84,7 @@ action="/admin/category/category-list" aria-label="カテゴリ新規登録" > - +
@@ -327,7 +327,7 @@ > - + diff --git a/var/templates/Page/Admin/Product/CsvCategory.html.twig b/var/templates/Page/Admin/Product/CsvCategory.html.twig index 2292099da..0a29cc4ce 100644 --- a/var/templates/Page/Admin/Product/CsvCategory.html.twig +++ b/var/templates/Page/Admin/Product/CsvCategory.html.twig @@ -76,7 +76,7 @@ aria-label="カテゴリCSVアップロード"> + value="{{ csrfToken }}">
diff --git a/var/templates/Page/Admin/Product/CsvClassName.html.twig b/var/templates/Page/Admin/Product/CsvClassName.html.twig index fc4fe1d9f..756bef6b2 100644 --- a/var/templates/Page/Admin/Product/CsvClassName.html.twig +++ b/var/templates/Page/Admin/Product/CsvClassName.html.twig @@ -98,7 +98,7 @@ novalidate aria-label="{{ csvTitle }}"> + value="{{ csrfToken }}"> {# ── Upload panel ──────────────────────────────────────────────────────── #}
From 4215581020880b3afb3443258dbd25e6d6f687b8 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 20 Sep 2026 12:53:59 +0900 Subject: [PATCH 05/10] Reconcile list-resource #[Link] declarations with ALPS (#136) BlockList and PaymentList declared doUpdate*/doDelete* on their own onGet - transitions ALPS assigns to the single-row Block/Payment states, not the list. Both resources' own docblocks already said as much ("Single-row affordances ... live at page://self/admin/payment/payment"). The surplus declarations advertised a Link: header target that can't actually be followed as declared either - a bare href with no bound row identifier, since the real per-row delete/update forms are rendered inline in the list HTML, unrelated to this resource-level attribute. Per-resource resolution (the two options the issue posed have different right answers depending on whether ALPS's assigned target resource is GET-reachable at all): - Block/Payment: a real single-row GET view exists (Block::onGet, Payment::onGet), so moved the declaration there - matching ALPS exactly. Payment::onGet already declared doUpdatePayment; Block::onGet was missing doUpdateBlock entirely (an oversight, not by design) and Payment::onGet was missing doDeletePayment the same way - filled both in, or removing the list's declaration would have made the transition undiscoverable via hypermedia anywhere, not just corrected. - TaxRuleList: alps.json's TaxRule state lists doDeleteTaxRule, but there is no goTaxRule transition and no onGet on TaxRule.php - "intentionally no onPut... edits flow as delete + create" per its own docblock. There is no GET-reachable resource to move the declaration to without inventing one, so this is the one case where the resource is right and ALPS was incomplete: connected #doDeleteTaxRule into TaxRuleList's descriptor set instead. Regenerated alps.json.html/alps.svg and synced the docs/ copies per AGENTS.md. Updated the two Hypermedia workflow tests that exercised the old (wrong) navigation - extracting doUpdateBlock/doUpdatePayment/doDeletePayment from the list response, the only place they used to be declared. Now: Block: testUpdatesBlock's own response already carries doUpdateBlock (no extra hop needed); testDeletesBlock re-fetches the single-row Block GET (Block::onPut doesn't redirect, so there's no Location to follow - a real client returning to a bookmarked item page would do the same). Payment: both testUpdatesPayment and testDeletesPayment now follow the Location header (Payment's create/update both redirect to the single-row GET) instead of detouring through the list. Adding doUpdateBlock/doDeletePayment to the single-row GETs surfaced two new html-link-audit-ledger entries, symmetric to the doDeleteBlock/doUpdatePayment entries already there: the "new blank form" mode (blockId/paymentId absent) doesn't render an update/delete form, so the declared link has no matching affordance (target-missing, resourceOnly - same classification as their siblings). Also removed two ledger entries that are no longer observed now that the surplus links are gone from the list resources (block-list doUpdateBlock, payment-list doUpdatePayment method-mismatch). Verified: full suite green (2806 tests, 33061 assertions), psalm clean, asd --validate alps.json clean, HtmlLinkAuditLedgerTest and both Hypermedia workflow test files pass, all four affected HTML render tests (AdminBlockHtmlRenderTest, AdminBlockListHtmlRenderTest, AdminPaymentListHtmlRenderTest, AdminTaxRuleListHtmlRenderTest) pass unchanged - the rendered per-row forms were never driven by this PHP attribute, only the Link: HTTP header and the audit ledger were. --- alps.json | 3 +- alps.json.html | 5700 ++++++++++------- alps.svg | 5623 +++++++++------- docs/alps.json.html | 5700 ++++++++++------- docs/alps.svg | 5623 +++++++++------- src/Resource/Page/Admin/Block/Block.php | 1 + src/Resource/Page/Admin/Block/BlockList.php | 2 - src/Resource/Page/Admin/Payment/Payment.php | 1 + .../Page/Admin/Payment/PaymentList.php | 2 - tests/Html/html-link-audit-ledger.json | 20 +- .../FlowAdminContentPublishTest.php | 10 +- .../FlowAdminShopConfigurationTest.php | 12 +- 12 files changed, 12810 insertions(+), 9887 deletions(-) diff --git a/alps.json b/alps.json index 90005316c..a04be3d72 100644 --- a/alps.json +++ b/alps.json @@ -1225,7 +1225,8 @@ "descriptor": [ {"href": "#TaxRule"}, {"href": "#goTaxRuleList"}, - {"href": "#doCreateTaxRule"} + {"href": "#doCreateTaxRule"}, + {"href": "#doDeleteTaxRule"} ] }, diff --git a/alps.json.html b/alps.json.html index 14276a246..b666f38f5 100644 --- a/alps.json.html +++ b/alps.json.html @@ -89,7 +89,7 @@ - - +
@@ -207,17 +206,17 @@

EC-CUBE 4.3 アプリケーションプロファイル

- - + + application_state_diagram - + Top - -Top + +Top @@ -225,21 +224,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Product - -Product + +Product Top->Product - - - + + + + + + + +■ + goProduct - -goProduct @@ -247,21 +250,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ProductList - -ProductList + +ProductList Top->ProductList - - - + + + + + + + +■ + goProductList - -goProductList @@ -269,21 +276,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Cart - -Cart + +Cart - + Top->Cart - - - + + + + + + + +■ + goCart - -goCart @@ -291,21 +302,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Login - -Login + +Login Top->Login - - - + + + + + + + +■ + goLogin - -goLogin @@ -313,21 +328,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerRegistration - -CustomerRegistration + +CustomerRegistration - + Top->CustomerRegistration - - - + + + + + + + +■ + goCustomerRegistration - -goCustomerRegistration @@ -335,21 +354,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Mypage - -Mypage + +Mypage - + Top->Mypage - - - + + + + + + + +■ + goMypage - -goMypage @@ -357,21 +380,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpAbout - -HelpAbout + +HelpAbout - + Top->HelpAbout - - - + + + + + + + +■ + goHelpAbout - -goHelpAbout @@ -379,21 +406,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpGuide - -HelpGuide + +HelpGuide - + Top->HelpGuide - - - + + + + + + + +■ + goHelpGuide - -goHelpGuide @@ -401,21 +432,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpAgreement - -HelpAgreement + +HelpAgreement - + Top->HelpAgreement - - - + + + + + + + +■ + goHelpAgreement - -goHelpAgreement @@ -423,21 +458,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpPrivacy - -HelpPrivacy + +HelpPrivacy - + Top->HelpPrivacy - - - + + + + + + + +■ + goHelpPrivacy - -goHelpPrivacy @@ -445,21 +484,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpTradeLaw - -HelpTradeLaw + +HelpTradeLaw - + Top->HelpTradeLaw - - - + + + + + + + +■ + goHelpTradeLaw - -goHelpTradeLaw @@ -467,86 +510,74 @@

EC-CUBE 4.3 アプリケーションプロファイル

ContactForm - -ContactForm + +ContactForm - + Top->ContactForm - - - - - - -goContactForm + + + - - - -Product->Product - - - + + +■ + goContactForm - -goProduct - + Product->Product - - - + + + - -doCreateProduct + + +■ + goProduct + +■ + doCreateProduct + - - -Product->Product - - - + +■ + doUpdateProduct - -doUpdateProduct Product->ProductList - - - + + + - -goProductList + + +■ + goProductList - - - -Product->ProductList - - - + +■ + doDeleteProduct - -doDeleteProduct @@ -554,34 +585,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

Category - -Category + +Category - + Product->Category - - - + + + + + + + +■ + goCategory - -goCategory - + Product->Cart - - - + + + + + + + +■ + doAddCartItem - -doAddCartItem @@ -589,21 +628,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerFavoriteProduct - -CustomerFavoriteProduct + +CustomerFavoriteProduct - + Product->CustomerFavoriteProduct - - - + + + + + + + +■ + doAddFavorite - -doAddFavorite @@ -611,73 +654,69 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerFavoriteProductList - -CustomerFavoriteProductList + +CustomerFavoriteProductList - + Product->CustomerFavoriteProductList - - - + + + - -doRemoveFavorite + + +■ + doRemoveFavorite - - - -ProductList->Product - - - - - - -goProduct - + ProductList->Product - - - + + + - -doCreateProduct + + +■ + goProduct + +■ + doCreateProduct + - - -ProductList->Product - - - + +■ + doCopyProduct - -doCopyProduct ProductList->ProductList - - - + + + + + + + +■ + goProductList - -goProductList @@ -685,112 +724,108 @@

EC-CUBE 4.3 アプリケーションプロファイル

CategoryList - -CategoryList + +CategoryList - + ProductList->CategoryList - - - + + + + + + + +■ + goCategoryList - -goCategoryList Category->ProductList - - - + + + + + + + +■ + goProductList - -goProductList - + Category->Category - - - + + + - -goCategory + + +■ + goCategory - - - -Category->Category - - - + +■ + doUpdateCategory - -doUpdateCategory - + Category->CategoryList - - - + + + - -goCategoryList + + +■ + goCategoryList - - - -Category->CategoryList - - - + +■ + doDeleteCategory - -doDeleteCategory - + CategoryList->Category - - - + + + - -goCategory + + +■ + goCategory - - - -CategoryList->Category - - - + +■ + doCreateCategory - -doCreateCategory @@ -798,8 +833,8 @@

EC-CUBE 4.3 アプリケーションプロファイル

Tag - -Tag + +Tag @@ -807,47 +842,59 @@

EC-CUBE 4.3 アプリケーションプロファイル

TagList - -TagList + +TagList - + Tag->TagList - - - + + + + + + + +■ + doDeleteTag - -doDeleteTag - + TagList->Tag - - - + + + + + + + +■ + doCreateTag - -doCreateTag - + TagList->TagList - - - + + + + + + + +■ + goTagList - -goTagList @@ -855,21 +902,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

AdminTop - -AdminTop + +AdminTop - + TagList->AdminTop - - - + + + + + + + +■ + doSortNoMove - -doSortNoMove @@ -877,21 +928,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ClassName - -ClassName + +ClassName - + ClassName->ClassName - - - + + + + + + + +■ + doUpdateClassName - -doUpdateClassName @@ -899,60 +954,76 @@

EC-CUBE 4.3 アプリケーションプロファイル

ClassNameList - -ClassNameList + +ClassNameList - + ClassName->ClassNameList - - - + + + + + + + +■ + doDeleteClassName - -doDeleteClassName - + ClassNameList->ClassName - - - + + + + + + + +■ + doCreateClassName - -doCreateClassName - + ClassNameList->ClassNameList - - - + + + + + + + +■ + goClassNameList - -goClassNameList - + ClassNameList->AdminTop - - - + + + + + + + +■ + doSortNoMove - -doSortNoMove @@ -960,21 +1031,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ClassCategory - -ClassCategory + +ClassCategory - + ClassCategory->ClassCategory - - - + + + + + + + +■ + doUpdateClassCategory - -doUpdateClassCategory @@ -982,125 +1057,113 @@

EC-CUBE 4.3 アプリケーションプロファイル

ClassCategoryList - -ClassCategoryList + +ClassCategoryList - + ClassCategory->ClassCategoryList - - - + + + + + + + +■ + doDeleteClassCategory - -doDeleteClassCategory - + ClassCategoryList->ClassCategory - - - + + + + + + + +■ + doCreateClassCategory - -doCreateClassCategory - + ClassCategoryList->ClassCategoryList - - - + + + - -goClassCategoryList + + +■ + goClassCategoryList - - - -ClassCategoryList->AdminTop - - - - - - -doSortNoMove - + ClassCategoryList->AdminTop - - - + + + - -doToggleVisible + + +■ + doSortNoMove - - - -Cart->Cart - - - + +■ + doToggleVisible - -goCart - + Cart->Cart - - - + + + - -doAddCartItem + + +■ + goCart - - - -Cart->Cart - - - + +■ + doAddCartItem - -doUpdateCartItemQuantity + +■ + doUpdateCartItemQuantity - - - -Cart->Cart - - - + +■ + doRemoveCartItem - -doRemoveCartItem @@ -1108,47 +1171,47 @@

EC-CUBE 4.3 アプリケーションプロファイル

CheckoutEntry - -CheckoutEntry + +CheckoutEntry - + Cart->CheckoutEntry - - - + + + - -doSelectCartForCheckout + + +■ + doSelectCartForCheckout - - - -Cart->CheckoutEntry - - - + +■ + goCheckoutEntry - -goCheckoutEntry - + CheckoutEntry->Cart - - - + + + + + + + +■ + goCart - -goCart @@ -1156,21 +1219,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingLogin - -ShoppingLogin + +ShoppingLogin - + CheckoutEntry->ShoppingLogin - - - + + + + + + + +■ + goShoppingLogin - -goShoppingLogin @@ -1178,21 +1245,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingNonMember - -ShoppingNonMember + +ShoppingNonMember - + CheckoutEntry->ShoppingNonMember - - - + + + + + + + +■ + goShoppingNonMember - -goShoppingNonMember @@ -1200,99 +1271,115 @@

EC-CUBE 4.3 アプリケーションプロファイル

Shopping - -Shopping + +Shopping - + CheckoutEntry->Shopping - - - + + + + + + + +■ + goShopping - -goShopping - + ShoppingLogin->ShoppingNonMember - - - + + + + + + + +■ + goShoppingNonMember - -goShoppingNonMember - + ShoppingLogin->CustomerRegistration - - - + + + + + + + +■ + goCustomerRegistration - -goCustomerRegistration - + ShoppingLogin->Mypage - - - + + + + + + + +■ + doLogin - -doLogin - + ShoppingNonMember->Shopping - - - + + + + + + + +■ + doSubmitNonMember - -doSubmitNonMember - + Shopping->Shopping - - - + + + - -doShoppingRedirectTo + + +■ + doShoppingRedirectTo - - - -Shopping->Shopping - - - + +■ + goShoppingShippingMultiple - -goShoppingShippingMultiple @@ -1300,21 +1387,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingShipping - -ShoppingShipping + +ShoppingShipping - + Shopping->ShoppingShipping - - - + + + + + + + +■ + goShoppingShipping - -goShoppingShipping @@ -1322,21 +1413,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingShippingEdit - -ShoppingShippingEdit + +ShoppingShippingEdit - + Shopping->ShoppingShippingEdit - - - + + + + + + + +■ + goShoppingShippingEdit - -goShoppingShippingEdit @@ -1344,21 +1439,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingConfirm - -ShoppingConfirm + +ShoppingConfirm - + Shopping->ShoppingConfirm - - - + + + + + + + +■ + doConfirmOrder - -doConfirmOrder @@ -1366,47 +1465,59 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingError - -ShoppingError + +ShoppingError - + Shopping->ShoppingError - - - + + + + + + + +■ + goShoppingError - -goShoppingError - + ShoppingShipping->Shopping - - - + + + + + + + +■ + doSelectShippingAddress - -doSelectShippingAddress - + ShoppingShippingEdit->Shopping - - - + + + + + + + +■ + doUpdateShippingAddress - -doUpdateShippingAddress @@ -1414,73 +1525,93 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingComplete - -ShoppingComplete + +ShoppingComplete - + ShoppingConfirm->ShoppingComplete - - - + + + + + + + +■ + doCheckout - -doCheckout - + ShoppingConfirm->ShoppingError - - - + + + + + + + +■ + goShoppingError - -goShoppingError ShoppingComplete->Top - - - + + + + + + + +■ + goTop - -goTop - + ShoppingComplete->Cart - - - + + + + + + + +■ + goCart - -goCart - + ShoppingError->Cart - - - + + + + + + + +■ + goCart - -goCart @@ -1488,86 +1619,62 @@

EC-CUBE 4.3 アプリケーションプロファイル

Order - -Order + +Order - + Order->Cart - - - + + + - -doReorder + + +■ + doReorder - - - -Order->Order - - - - - - -goOrder - + Order->Order - - - + + + - -doUpdateOrder + + +■ + goOrder - - - -Order->Order - - - + +■ + doUpdateOrder - -doUpdateOrderStatus + +■ + doUpdateOrderStatus - - - -Order->Order - - - - - - -doUpdateTrackingNumber + +■ + doUpdateTrackingNumber - - - -Order->Order - - - + +■ + doSendShippingNotifyMail - -doSendShippingNotifyMail @@ -1575,34 +1682,30 @@

EC-CUBE 4.3 アプリケーションプロファイル

OrderList - -OrderList + +OrderList - + Order->OrderList - - - + + + - -goOrderList + + +■ + goOrderList - - - -Order->OrderList - - - + +■ + goExportOrderPdf - -goExportOrderPdf @@ -1610,21 +1713,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

MailHistory - -MailHistory + +MailHistory - + Order->MailHistory - - - + + + + + + + +■ + doSendOrderMail - -doSendOrderMail @@ -1632,60 +1739,64 @@

EC-CUBE 4.3 アプリケーションプロファイル

OrderShippingAddress - -OrderShippingAddress + +OrderShippingAddress - + Order->OrderShippingAddress - - - + + + + + + + +■ + goOrderShippingAddress - -goOrderShippingAddress - + OrderList->Order - - - + + + - -goOrder + + +■ + goOrder - - - -OrderList->Order - - - + +■ + doCreateOrder - -doCreateOrder - + OrderList->OrderList - - - + + + + + + + +■ + goOrderList - -goOrderList @@ -1693,47 +1804,59 @@

EC-CUBE 4.3 アプリケーションプロファイル

Customer - -Customer + +Customer - + Customer->Top - - - + + + + + + + +■ + doWithdrawCustomer - -doWithdrawCustomer - + Customer->OrderList - - - + + + + + + + +■ + goOrderHistory - -goOrderHistory - + Customer->Customer - - - + + + + + + + +■ + goCustomer - -goCustomer @@ -1741,34 +1864,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerAddressList - -CustomerAddressList + +CustomerAddressList - + Customer->CustomerAddressList - - - + + + + + + + +■ + goCustomerAddressList - -goCustomerAddressList - + Customer->CustomerFavoriteProductList - - - + + + + + + + +■ + goFavoriteList - -goFavoriteList @@ -1776,21 +1907,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageChange - -MypageChange + +MypageChange - + Customer->MypageChange - - - + + + + + + + +■ + doUpdateCustomer - -doUpdateCustomer @@ -1798,60 +1933,52 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerList - -CustomerList + +CustomerList - + CustomerList->Customer - - - + + + - -goCustomer + + +■ + goCustomer - - - -CustomerList->Customer - - - + +■ + doCreateCustomer - -doCreateCustomer - + CustomerList->CustomerList - - - + + + - -goCustomerList + + +■ + goCustomerList - - - -CustomerList->CustomerList - - - + +■ + doResendActivationMail - -doResendActivationMail @@ -1859,125 +1986,161 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerAddress - -CustomerAddress + +CustomerAddress - + CustomerAddress->CustomerAddress - - - + + + + + + + +■ + doUpdateCustomerAddress - -doUpdateCustomerAddress - + CustomerAddress->CustomerAddressList - - - + + + + + + + +■ + doDeleteCustomerAddress - -doDeleteCustomerAddress - + CustomerAddressList->CustomerAddress - - - + + + + + + + +■ + doCreateCustomerAddress - -doCreateCustomerAddress - + CustomerAddressList->CustomerFavoriteProductList - - - + + + + + + + +■ + goFavoriteList - -goFavoriteList CustomerFavoriteProduct->Product - - - + + + + + + + +■ + goProduct - -goProduct - + CustomerFavoriteProduct->CustomerFavoriteProductList - - - + + + + + + + +■ + doRemoveFavorite - -doRemoveFavorite - + CustomerFavoriteProductList->CustomerFavoriteProductList - - - + + + + + + + +■ + goFavoriteList - -goFavoriteList - + Login->CustomerRegistration - - - + + + + + + + +■ + goCustomerRegistration - -goCustomerRegistration - + Login->Mypage - - - + + + + + + + +■ + doLogin - -doLogin @@ -1985,34 +2148,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

PasswordReset - -PasswordReset + +PasswordReset - + PasswordReset->Login - - - + + + + + + + +■ + doResetPassword - -doResetPassword - + CustomerRegistration->CustomerRegistration - - - + + + + + + + +■ + goCustomerRegistration - -goCustomerRegistration @@ -2020,21 +2191,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerRegistrationComplete - -CustomerRegistrationComplete + +CustomerRegistrationComplete - + CustomerRegistration->CustomerRegistrationComplete - - - + + + + + + + +■ + doRegisterCustomer - -doRegisterCustomer @@ -2042,60 +2217,76 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerRegistrationConfirm - -CustomerRegistrationConfirm + +CustomerRegistrationConfirm - + CustomerRegistration->CustomerRegistrationConfirm - - - + + + + + + + +■ + goCustomerRegistrationConfirm - -goCustomerRegistrationConfirm CustomerRegistrationComplete->Top - - - + + + + + + + +■ + goTop - -goTop - + Mypage->CustomerAddressList - - - + + + + + + + +■ + goCustomerAddressList - -goCustomerAddressList - + Mypage->CustomerFavoriteProductList - - - + + + + + + + +■ + goFavoriteList - -goFavoriteList @@ -2103,34 +2294,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageHistory - -MypageHistory + +MypageHistory - + Mypage->MypageHistory - - - + + + + + + + +■ + goMypageHistory - -goMypageHistory - + Mypage->MypageChange - - - + + + + + + + +■ + goMypageChange - -goMypageChange @@ -2138,73 +2337,93 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageWithdraw - -MypageWithdraw + +MypageWithdraw - + Mypage->MypageWithdraw - - - + + + + + + + +■ + goMypageWithdraw - -goMypageWithdraw MypageHistory->Product - - - + + + + + + + +■ + goProduct - -goProduct - + MypageHistory->Cart - - - + + + + + + + +■ + doReorder - -doReorder - + MypageHistory->Mypage - - - + + + + + + + +■ + goMypage - -goMypage - + MypageChange->MypageChange - - - + + + + + + + +■ + doUpdateCustomer - -doUpdateCustomer @@ -2212,47 +2431,59 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageChangeComplete - -MypageChangeComplete + +MypageChangeComplete - + MypageChangeComplete->CustomerAddressList - - - + + + + + + + +■ + goCustomerAddressList - -goCustomerAddressList - + MypageChangeComplete->Mypage - - - + + + + + + + +■ + goMypage - -goMypage - + MypageWithdraw->Top - - - + + + + + + + +■ + doWithdrawCustomer - -doWithdrawCustomer @@ -2260,47 +2491,59 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageWithdrawConfirm - -MypageWithdrawConfirm + +MypageWithdrawConfirm - + MypageWithdraw->MypageWithdrawConfirm - - - + + + + + + + +■ + goMypageWithdrawConfirm - -goMypageWithdrawConfirm - + MypageWithdrawConfirm->Top - - - + + + + + + + +■ + doWithdrawCustomer - -doWithdrawCustomer - + MypageWithdrawConfirm->Mypage - - - + + + + + + + +■ + goMypage - -goMypage @@ -2308,86 +2551,110 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageWithdrawComplete - -MypageWithdrawComplete + +MypageWithdrawComplete MypageWithdrawComplete->Top - - - + + + + + + + +■ + goTop - -goTop HelpAbout->Top - - - + + + + + + + +■ + goTop - -goTop HelpGuide->Top - - - + + + + + + + +■ + goTop - -goTop HelpAgreement->Top - - - + + + + + + + +■ + goTop - -goTop HelpPrivacy->Top - - - + + + + + + + +■ + goTop - -goTop HelpTradeLaw->Top - - - + + + + + + + +■ + goTop - -goTop @@ -2395,34 +2662,30 @@

EC-CUBE 4.3 アプリケーションプロファイル

BaseInfo - -BaseInfo + +BaseInfo - + BaseInfo->BaseInfo - - - + + + - -goBaseInfo + + +■ + goBaseInfo - - - -BaseInfo->BaseInfo - - - + +■ + doUpdateBaseInfo - -doUpdateBaseInfo @@ -2430,21 +2693,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

PaymentList - -PaymentList + +PaymentList - + BaseInfo->PaymentList - - - + + + + + + + +■ + goPaymentList - -goPaymentList @@ -2452,99 +2719,103 @@

EC-CUBE 4.3 アプリケーションプロファイル

Payment - -Payment + +Payment - + Payment->Payment - - - + + + + + + + +■ + doUpdatePayment - -doUpdatePayment - + Payment->PaymentList - - - + + + + + + + +■ + doDeletePayment - -doDeletePayment - + PaymentList->Payment - - - + + + - -doCreatePayment + + +■ + doCreatePayment - - - -PaymentList->Payment - - - + +■ + goPayment - -goPayment - + PaymentList->PaymentList - - - + + + + + + + +■ + goPaymentList - -goPaymentList - + PaymentList->AdminTop - - - + + + - -doSortNoMove + + +■ + doSortNoMove - - - -PaymentList->AdminTop - - - + +■ + doToggleVisible - -doToggleVisible @@ -2552,21 +2823,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Delivery - -Delivery + +Delivery - + Delivery->Delivery - - - + + + + + + + +■ + doUpdateDelivery - -doUpdateDelivery @@ -2574,86 +2849,86 @@

EC-CUBE 4.3 アプリケーションプロファイル

DeliveryList - -DeliveryList + +DeliveryList - + Delivery->DeliveryList - - - + + + + + + + +■ + doDeleteDelivery - -doDeleteDelivery - + DeliveryList->Delivery - - - + + + - -doCreateDelivery + + +■ + doCreateDelivery - - - -DeliveryList->Delivery - - - + +■ + goDelivery - -goDelivery - + DeliveryList->DeliveryList - - - + + + + + + + +■ + goDeliveryList - -goDeliveryList - + DeliveryList->AdminTop - - - + + + - -doSortNoMove + + +■ + doSortNoMove - - - -DeliveryList->AdminTop - - - + +■ + doToggleVisible - -doToggleVisible @@ -2661,8 +2936,8 @@

EC-CUBE 4.3 アプリケーションプロファイル

TaxRule - -TaxRule + +TaxRule @@ -2670,47 +2945,64 @@

EC-CUBE 4.3 アプリケーションプロファイル

TaxRuleList - -TaxRuleList + +TaxRuleList - + TaxRule->TaxRuleList - - - + + + + + + + +■ + doDeleteTaxRule - -doDeleteTaxRule - + TaxRuleList->TaxRule - - - + + + + + + + +■ + doCreateTaxRule - -doCreateTaxRule - + TaxRuleList->TaxRuleList - - - + + + + + + + +■ + goTaxRuleList + + + +■ + doDeleteTaxRule - -goTaxRuleList @@ -2718,34 +3010,30 @@

EC-CUBE 4.3 アプリケーションプロファイル

News - -News + +News - + News->News - - - + + + - -goNews + + +■ + goNews - - - -News->News - - - + +■ + doUpdateNews - -doUpdateNews @@ -2753,21 +3041,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

NewsList - -NewsList + +NewsList - + News->NewsList - - - + + + + + + + +■ + doDeleteNews - -doDeleteNews @@ -2775,73 +3067,81 @@

EC-CUBE 4.3 アプリケーションプロファイル

PageList - -PageList + +PageList - + News->PageList - - - + + + + + + + +■ + goPageList - -goPageList - + NewsList->News - - - + + + - -goNews + + +■ + goNews - - - -NewsList->News - - - + +■ + doCreateNews - -doCreateNews - + NewsList->NewsList - - - + + + + + + + +■ + goNewsList - -goNewsList - + NewsList->AdminTop - - - + + + + + + + +■ + doToggleVisible - -doToggleVisible @@ -2849,47 +3149,47 @@

EC-CUBE 4.3 アプリケーションプロファイル

Page - -Page + +Page - + Page->Page - - - + + + - -goPage + + +■ + goPage - - - -Page->Page - - - + +■ + doUpdatePage - -doUpdatePage - + Page->PageList - - - + + + + + + + +■ + doDeletePage - -doDeletePage @@ -2897,73 +3197,81 @@

EC-CUBE 4.3 アプリケーションプロファイル

BlockList - -BlockList + +BlockList - + Page->BlockList - - - + + + + + + + +■ + goBlockList - -goBlockList - + PageList->Page - - - + + + - -goPage + + +■ + goPage - - - -PageList->Page - - - + +■ + doCreatePage - -doCreatePage - + PageList->PageList - - - + + + + + + + +■ + goPageList - -goPageList - + ContactForm->ContactForm - - - + + + + + + + +■ + goContactForm - -goContactForm @@ -2971,34 +3279,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

ContactComplete - -ContactComplete + +ContactComplete - + ContactForm->ContactComplete - - - + + + + + + + +■ + doSubmitContact - -doSubmitContact ContactComplete->Top - - - + + + + + + + +■ + goTop - -goTop @@ -3006,34 +3322,30 @@

EC-CUBE 4.3 アプリケーションプロファイル

Member - -Member + +Member - + Member->Member - - - + + + - -goMember + + +■ + goMember - - - -Member->Member - - - + +■ + doUpdateMember - -doUpdateMember @@ -3041,60 +3353,64 @@

EC-CUBE 4.3 アプリケーションプロファイル

MemberList - -MemberList + +MemberList - + Member->MemberList - - - + + + + + + + +■ + doDeleteMember - -doDeleteMember - + MemberList->Member - - - + + + - -goMember + + +■ + goMember - - - -MemberList->Member - - - + +■ + doCreateMember - -doCreateMember - + MemberList->MemberList - - - + + + + + + + +■ + goMemberList - -goMemberList @@ -3102,21 +3418,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

AuthorityRole - -AuthorityRole + +AuthorityRole - + AuthorityRole->AuthorityRole - - - + + + + + + + +■ + doUpdateAuthorityRole - -doUpdateAuthorityRole @@ -3124,21 +3444,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

MailTemplate - -MailTemplate + +MailTemplate - + MailTemplate->MailTemplate - - - + + + + + + + +■ + doUpdateMailTemplate - -doUpdateMailTemplate @@ -3146,21 +3470,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

MailTemplateList - -MailTemplateList + +MailTemplateList - + MailTemplate->MailTemplateList - - - + + + + + + + +■ + doDeleteMailTemplate - -doDeleteMailTemplate @@ -3168,34 +3496,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

OrderMail - -OrderMail + +OrderMail - + MailTemplate->OrderMail - - - + + + + + + + +■ + goOrderMail - -goOrderMail - + MailTemplateList->MailTemplateList - - - + + + + + + + +■ + goMailTemplateList - -goMailTemplateList @@ -3203,21 +3539,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

LoginHistoryList - -LoginHistoryList + +LoginHistoryList - + LoginHistoryList->LoginHistoryList - - - + + + + + + + +■ + goLoginHistoryList - -goLoginHistoryList @@ -3225,21 +3565,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Security - -Security + +Security - + LoginHistoryList->Security - - - + + + + + + + +■ + goSecurity - -goSecurity @@ -3247,34 +3591,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

Csv - -Csv + +Csv - + Csv->ProductList - - - + + + + + + + +■ + goExportProduct - -goExportProduct - + Csv->Csv - - - + + + + + + + +■ + doUpdateCsv - -doUpdateCsv @@ -3282,34 +3634,30 @@

EC-CUBE 4.3 アプリケーションプロファイル

Plugin - -Plugin + +Plugin - + Plugin->Plugin - - - + + + - -doEnablePlugin + + +■ + doEnablePlugin - - - -Plugin->Plugin - - - + +■ + doDisablePlugin - -doDisablePlugin @@ -3317,47 +3665,59 @@

EC-CUBE 4.3 アプリケーションプロファイル

PluginList - -PluginList + +PluginList - + Plugin->PluginList - - - + + + + + + + +■ + doUninstallPlugin - -doUninstallPlugin - + PluginList->Plugin - - - + + + + + + + +■ + doInstallPlugin - -doInstallPlugin - + PluginList->PluginList - - - + + + + + + + +■ + goPluginList - -goPluginList @@ -3365,60 +3725,40 @@

EC-CUBE 4.3 アプリケーションプロファイル

TemplateList - -TemplateList + +TemplateList - + TemplateList->TemplateList - - - + + + - -goTemplateList + + +■ + goTemplateList - - - -TemplateList->TemplateList - - - + +■ + doDeleteTemplate - -doDeleteTemplate + +■ + doDownloadTemplate - - - -TemplateList->TemplateList - - - + +■ + doSelectTemplate - -doDownloadTemplate - - - - - -TemplateList->TemplateList - - - - - - -doSelectTemplate @@ -3426,21 +3766,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

TemplateInstall - -TemplateInstall + +TemplateInstall - + TemplateList->TemplateInstall - - - + + + + + + + +■ + goTemplateInstall - -goTemplateInstall @@ -3448,21 +3792,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Layout - -Layout + +Layout - + Layout->Layout - - - + + + + + + + +■ + doUpdateLayout - -doUpdateLayout @@ -3470,21 +3818,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

TradeLawList - -TradeLawList + +TradeLawList - + Layout->TradeLawList - - - + + + + + + + +■ + goTradeLawList - -goTradeLawList @@ -3492,21 +3844,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

LayoutList - -LayoutList + +LayoutList - + LayoutList->LayoutList - - - + + + + + + + +■ + goLayoutList - -goLayoutList @@ -3514,99 +3870,115 @@

EC-CUBE 4.3 アプリケーションプロファイル

Block - -Block + +Block - + Block->LayoutList - - - + + + + + + + +■ + goLayoutList - -goLayoutList - + Block->Block - - - + + + + + + + +■ + doUpdateBlock - -doUpdateBlock - + Block->BlockList - - - + + + + + + + +■ + doDeleteBlock - -doDeleteBlock - + BlockList->Block - - - + + + + + + + +■ + doCreateBlock - -doCreateBlock - + BlockList->BlockList - - - + + + + + + + +■ + goBlockList - -goBlockList - + TradeLawList->TradeLawList - - - + + + - -goTradeLawList + + +■ + goTradeLawList - - - -TradeLawList->TradeLawList - - - + +■ + doUpdateTradeLaw - -doUpdateTradeLaw @@ -3614,21 +3986,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ContentCss - -ContentCss + +ContentCss - + TradeLawList->ContentCss - - - + + + + + + + +■ + goContentCss - -goContentCss @@ -3636,294 +4012,382 @@

EC-CUBE 4.3 アプリケーションプロファイル

AdminLogin - -AdminLogin + +AdminLogin - + AdminLogin->AdminTop - - - + + + + + + + +■ + doAdminLogin - -doAdminLogin AdminTop->ProductList - - - + + + + + + + +■ + goProductList - -goProductList - + AdminTop->TagList - - - + + + + + + + +■ + goTagList - -goTagList - + AdminTop->ClassNameList - - - + + + + + + + +■ + goClassNameList - -goClassNameList - + AdminTop->ClassCategoryList - - - + + + + + + + +■ + goClassCategoryList - -goClassCategoryList - + AdminTop->OrderList - - - + + + + + + + +■ + goOrderList - -goOrderList - + AdminTop->CustomerList - - - + + + + + + + +■ + goCustomerList - -goCustomerList - + AdminTop->BaseInfo - - - + + + + + + + +■ + goBaseInfo - -goBaseInfo - + AdminTop->PaymentList - - - + + + + + + + +■ + goPaymentList - -goPaymentList - + AdminTop->DeliveryList - - - + + + + + + + +■ + goDeliveryList - -goDeliveryList - + AdminTop->TaxRuleList - - - + + + + + + + +■ + goTaxRuleList - -goTaxRuleList - + AdminTop->NewsList - - - + + + + + + + +■ + goNewsList - -goNewsList - + AdminTop->PageList - - - + + + + + + + +■ + goPageList - -goPageList - + AdminTop->MemberList - - - + + + + + + + +■ + goMemberList - -goMemberList - + AdminTop->MailTemplateList - - - + + + + + + + +■ + goMailTemplateList - -goMailTemplateList - + AdminTop->LoginHistoryList - - - + + + + + + + +■ + goLoginHistoryList - -goLoginHistoryList - + AdminTop->PluginList - - - + + + + + + + +■ + goPluginList - -goPluginList - + AdminTop->TemplateList - - - + + + + + + + +■ + goTemplateList - -goTemplateList - + AdminTop->LayoutList - - - + + + + + + + +■ + goLayoutList - -goLayoutList - + AdminTop->BlockList - - - + + + + + + + +■ + goBlockList - -goBlockList - + AdminTop->TradeLawList - - - + + + + + + + +■ + goTradeLawList - -goTradeLawList - + AdminTop->AdminLogin - - - + + + + + + + +■ + doAdminLogout - -doAdminLogout @@ -3931,21 +4395,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

ContentCache - -ContentCache + +ContentCache - + AdminTop->ContentCache - - - + + + + + + + +■ + goContentCache - -goContentCache @@ -3953,60 +4421,40 @@

EC-CUBE 4.3 アプリケーションプロファイル

Calendar - -Calendar + +Calendar - + Calendar->Calendar - - - + + + - -doCreateCalendarHoliday + + +■ + doCreateCalendarHoliday - - - -Calendar->Calendar - - - - - - -doDeleteCalendarHoliday - - - - - -Calendar->Calendar - - - + +■ + doDeleteCalendarHoliday - -doUpdateCalendar + +■ + doUpdateCalendar - - - -Calendar->Calendar - - - + +■ + goCalendar - -goCalendar @@ -4014,34 +4462,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

ChangePassword - -ChangePassword + +ChangePassword - + ContentCache->ContentCache - - - + + + + + + + +■ + doClearCache - -doClearCache - + ContentCss->ContentCss - - - + + + + + + + +■ + doUpdateContentCss - -doUpdateContentCss @@ -4049,34 +4505,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

ContentJs - -ContentJs + +ContentJs - + ContentCss->ContentJs - - - + + + + + + + +■ + goContentJs - -goContentJs - + ContentJs->ContentJs - - - + + + + + + + +■ + doUpdateContentJs - -doUpdateContentJs @@ -4084,21 +4548,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Maintenance - -Maintenance + +Maintenance - + Maintenance->Maintenance - - - + + + + + + + +■ + doToggleMaintenance - -doToggleMaintenance @@ -4106,21 +4574,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

MasterData - -MasterData + +MasterData - + OrderMail->MailHistory - - - + + + + + + + +■ + doSendOrderMail - -doSendOrderMail @@ -4128,60 +4600,64 @@

EC-CUBE 4.3 アプリケーションプロファイル

OrderMailConfirm - -OrderMailConfirm + +OrderMailConfirm - + OrderMail->OrderMailConfirm - - - + + + + + + + +■ + goOrderMailConfirm - -goOrderMailConfirm - + OrderMailConfirm->MailHistory - - - + + + + + + + +■ + doSendOrderMail - -doSendOrderMail - + OrderShippingAddress->Order - - - + + + - -doUpdateTrackingNumber + + +■ + doUpdateTrackingNumber - - - -OrderShippingAddress->Order - - - + +■ + doUpdateOrderShippingAddress - -doUpdateOrderShippingAddress @@ -4189,8 +4665,8 @@

EC-CUBE 4.3 アプリケーションプロファイル

OrderStatusList - -OrderStatusList + +OrderStatusList @@ -4198,8 +4674,8 @@

EC-CUBE 4.3 アプリケーションプロファイル

PasswordResetRequest - -PasswordResetRequest + +PasswordResetRequest @@ -4207,21 +4683,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

PasswordResetRequestComplete - -PasswordResetRequestComplete + +PasswordResetRequestComplete - + Security->Security - - - + + + + + + + +■ + doUpdateSecurity - -doUpdateSecurity @@ -4229,34 +4709,42 @@

EC-CUBE 4.3 アプリケーションプロファイル

SystemInfo - -SystemInfo + +SystemInfo - + SystemInfo->AdminLogin - - - + + + + + + + +■ + doAdminLogout - -doAdminLogout - + TemplateInstall->TemplateList - - - + + + + + + + +■ + doInstallTemplate - -doInstallTemplate @@ -4264,21 +4752,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

TwoFactorAuth - -TwoFactorAuth + +TwoFactorAuth - + TwoFactorAuth->TwoFactorAuth - - - + + + + + + + +■ + doVerifyTwoFactorAuth - -doVerifyTwoFactorAuth @@ -4286,1432 +4778,1650 @@

EC-CUBE 4.3 アプリケーションプロファイル

TwoFactorAuthSet - -TwoFactorAuthSet + +TwoFactorAuthSet - + TwoFactorAuthSet->TwoFactorAuthSet - - - + + + + + + + +■ + doSetTwoFactorAuth - -doSetTwoFactorAuth doUpdateProduct - -doUpdateProduct + +doUpdateProduct doUpdateProduct->ProductList - - - + + + + + + + +■ + goProductList - -goProductList CartItem - -CartItem + +CartItem CartItem->Product - - - + + + + + + + +■ + goProduct - -goProduct UnknownState - -UnknownState + +UnknownState - + UnknownState->Top - - - + + + + + + + +■ + doLogout - -doLogout - + UnknownState->ProductList - - - + + + - -doBulkUpdateProductStatus + + +■ + doBulkUpdateProductStatus - - - -UnknownState->ProductList - - - + +■ + doImportProductCsv - -doImportProductCsv - + UnknownState->ClassCategory - - - + + + + + + + +■ + goClassCategory - -goClassCategory - + UnknownState->ShoppingComplete - - - + + + + + + + +■ + goShoppingComplete - -goShoppingComplete - + UnknownState->OrderList - - - + + + - -doBulkDeleteOrder + + +■ + doBulkDeleteOrder - - - -UnknownState->OrderList - - - + +■ + goImportShippingCsv - -goImportShippingCsv - + UnknownState->Customer - - - + + + + + + + +■ + doActivateCustomer - -doActivateCustomer - + UnknownState->CustomerAddress - - - + + + + + + + +■ + goCustomerAddress - -goCustomerAddress - + UnknownState->PasswordReset - - - + + + - -doRequestPasswordReset + + +■ + doRequestPasswordReset - - - -UnknownState->PasswordReset - - - + +■ + goPasswordReset - -goPasswordReset - + UnknownState->CustomerRegistrationComplete - - - + + + + + + + +■ + goCustomerRegistrationComplete - -goCustomerRegistrationComplete - + UnknownState->ContactComplete - - - + + + + + + + +■ + goContactComplete - -goContactComplete - + UnknownState->AuthorityRole - - - + + + + + + + +■ + goAuthorityRole - -goAuthorityRole - + UnknownState->Csv - - - + + + + + + + +■ + goCsv - -goCsv - + UnknownState->Layout - - - + + + + + + + +■ + goLayout - -goLayout - + UnknownState->Block - - - + + + + + + + +■ + goBlock - -goBlock - + UnknownState->AdminLogin - - - + + + + + + + +■ + goAdminLogin - -goAdminLogin - + UnknownState->AdminTop - - - + + + + + + + +■ + doChangePassword - -doChangePassword - + UnknownState->ChangePassword - - - - - - -goChangePassword + + + - - - -UnknownState->MasterData - - - + + +■ + goChangePassword - -doSelectMasterData - + UnknownState->MasterData - - - + + + - -doUpdateMasterData + + +■ + doSelectMasterData + +■ + doUpdateMasterData + - - -UnknownState->MasterData - - - + +■ + goMasterData - -goMasterData - + UnknownState->OrderStatusList - - - + + + - -doUpdateOrderStatusList + + +■ + doUpdateOrderStatusList - - - -UnknownState->OrderStatusList - - - + +■ + goOrderStatusList - -goOrderStatusList - + UnknownState->PasswordResetRequest - - - + + + + + + + +■ + goPasswordResetRequest - -goPasswordResetRequest - + UnknownState->PasswordResetRequestComplete - - - + + + + + + + +■ + goPasswordResetRequestComplete - -goPasswordResetRequestComplete doUpdateCsv - -doUpdateCsv + +doUpdateCsv - + doUpdateCsv->ProductList - - - + + + + + + + +■ + goExportProduct - -goExportProduct goExportCategory - -goExportCategory + +goExportCategory - + goExportCategory->CategoryList - - - + + + + + + + +■ + doImportCategoryCsv - -doImportCategoryCsv goExportProduct - -goExportProduct + +goExportProduct - + goExportProduct->CategoryList - - - + + + + + + + +■ + goExportCategory - -goExportCategory AdminOrderEditPage - -AdminOrderEditPage - - - -AdminOrderEditPage->Order - - - - - - -doUpdateOrder - - + +AdminOrderEditPage - + AdminOrderEditPage->Order - - - + + + - -doUpdateOrderStatus + + +■ + doUpdateOrder - - - -AdminOrderEditPage->Order - - - + +■ + doUpdateOrderStatus - -doUpdateTrackingNumber + +■ + doUpdateTrackingNumber - - - -AdminOrderEditPage->Order - - - + +■ + doSendShippingNotifyMail - -doSendShippingNotifyMail - + AdminOrderEditPage->OrderList - - - + + + + + + + +■ + goOrderList - -goOrderList - + AdminOrderEditPage->MailHistory - - - + + + + + + + +■ + doSendOrderMail - -doSendOrderMail doImportCategoryCsv - -doImportCategoryCsv + +doImportCategoryCsv - + doImportCategoryCsv->OrderList - - - + + + + + + + +■ + goExportOrder - -goExportOrder goExportOrderPdf - -goExportOrderPdf + +goExportOrderPdf - + goExportOrderPdf->OrderList - - - + + + + + + + +■ + goExportOrder - -goExportOrder doSendOrderMail - -doSendOrderMail + +doSendOrderMail - + doSendOrderMail->OrderList - - - + + + - -goExportOrder + + +■ + goExportOrder - - - -doSendOrderMail->OrderList - - - + +■ + goExportOrderPdf - -goExportOrderPdf goExportOrder - -goExportOrder + +goExportOrder - + goExportOrder->OrderList - - - + + + + + + + +■ + goExportShipping - -goExportShipping goExportShipping - -goExportShipping + +goExportShipping - + goExportShipping->OrderList - - - + + + + + + + +■ + doImportShippingCsv - -doImportShippingCsv doUpdateOrderShippingAddress - -doUpdateOrderShippingAddress + +doUpdateOrderShippingAddress - + doUpdateOrderShippingAddress->Order - - - + + + + + + + +■ + doUpdateTrackingNumber - -doUpdateTrackingNumber doRemoveFavorite - -doRemoveFavorite + +doRemoveFavorite - + doRemoveFavorite->MypageWithdraw - - - + + + + + + + +■ + goMypageWithdraw - -goMypageWithdraw AdminCustomerEditPage - -AdminCustomerEditPage + +AdminCustomerEditPage - + AdminCustomerEditPage->Customer - - - + + + + + + + +■ + doCreateCustomer - -doCreateCustomer - + AdminCustomerEditPage->CustomerList - - - + + + - -goCustomerList + + +■ + goCustomerList - - - -AdminCustomerEditPage->CustomerList - - - + +■ + doDeleteCustomer - -doDeleteCustomer doImportShippingCsv - -doImportShippingCsv + +doImportShippingCsv - + doImportShippingCsv->CustomerList - - - + + + + + + + +■ + goExportCustomer - -goExportCustomer doDeleteCustomerAddress - -doDeleteCustomerAddress + +doDeleteCustomerAddress - + doDeleteCustomerAddress->CustomerFavoriteProductList - - - + + + + + + + +■ + goFavoriteList - -goFavoriteList doAddFavorite - -doAddFavorite + +doAddFavorite - + doAddFavorite->CustomerFavoriteProductList - - - + + + + + + + +■ + doRemoveFavorite - -doRemoveFavorite doUpdateBaseInfo - -doUpdateBaseInfo + +doUpdateBaseInfo - + doUpdateBaseInfo->PaymentList - - - + + + + + + + +■ + goPaymentList - -goPaymentList doDeletePayment - -doDeletePayment + +doDeletePayment - + doDeletePayment->DeliveryList - - - + + + + + + + +■ + goDeliveryList - -goDeliveryList doDeleteDelivery - -doDeleteDelivery + +doDeleteDelivery - + doDeleteDelivery->TaxRuleList - - - + + + + + + + +■ + goTaxRuleList - -goTaxRuleList doUpdateAuthorityRole - -doUpdateAuthorityRole + +doUpdateAuthorityRole - + doUpdateAuthorityRole->LoginHistoryList - - - + + + + + + + +■ + goLoginHistoryList - -goLoginHistoryList doDeleteMailTemplate - -doDeleteMailTemplate + +doDeleteMailTemplate - + doDeleteMailTemplate->MailTemplateList - - - + + + + + + + +■ + goMailTemplateList - -goMailTemplateList doDeleteBlock - -doDeleteBlock + +doDeleteBlock - + doDeleteBlock->LayoutList - - - + + + + + + + +■ + goLayoutList - -goLayoutList doDeletePage - -doDeletePage + +doDeletePage - + doDeletePage->BlockList - - - + + + + + + + +■ + goBlockList - -goBlockList doUpdateLayout - -doUpdateLayout + +doUpdateLayout - + doUpdateLayout->TradeLawList - - - + + + + + + + +■ + goTradeLawList - -goTradeLawList doDeleteNews - -doDeleteNews + +doDeleteNews - + doDeleteNews->PageList - - - + + + + + + + +■ + goPageList - -goPageList doDeleteTemplate - -doDeleteTemplate + +doDeleteTemplate - + doDeleteTemplate->TemplateList - - - + + + + + + + +■ + goTemplateList - -goTemplateList doUpdateMailTemplate - -doUpdateMailTemplate + +doUpdateMailTemplate - + doUpdateMailTemplate->MailTemplateList - - - + + + + + + + +■ + doDeleteMailTemplate - -doDeleteMailTemplate - + doUpdateMailTemplate->OrderMail - - - + + + + + + + +■ + goOrderMail - -goOrderMail doDownloadTemplate - -doDownloadTemplate + +doDownloadTemplate - + doDownloadTemplate->TemplateList - - - + + + + + + + +■ + doDeleteTemplate - -doDeleteTemplate doSelectTemplate - -doSelectTemplate + +doSelectTemplate - + doSelectTemplate->TemplateList - - - + + + + + + + +■ + doDownloadTemplate - -doDownloadTemplate goExportClassCategory - -goExportClassCategory + +goExportClassCategory - + goExportClassCategory->ClassCategoryList - - - + + + + + + + +■ + doImportClassCategoryCsv - -doImportClassCategoryCsv goExportClassName - -goExportClassName + +goExportClassName - + goExportClassName->ClassNameList - - - + + + + + + + +■ + doImportClassNameCsv - -doImportClassNameCsv doInstallTemplate - -doInstallTemplate + +doInstallTemplate - + doInstallTemplate->TemplateList - - - + + + + + + + +■ + doSelectTemplate - -doSelectTemplate doAdminLogin - -doAdminLogin + +doAdminLogin - + doAdminLogin->AdminTop - - - + + + + + + + +■ + goAdminTop - -goAdminTop doDeleteTaxRule - -doDeleteTaxRule + +doDeleteTaxRule - + doDeleteTaxRule->Calendar - - - + + + + + + + +■ + goCalendar - -goCalendar doVerifyTwoFactorAuth - -doVerifyTwoFactorAuth + +doVerifyTwoFactorAuth - + doVerifyTwoFactorAuth->ContentCache - - - + + + + + + + +■ + goContentCache - -goContentCache doUpdateTradeLaw - -doUpdateTradeLaw + +doUpdateTradeLaw - + doUpdateTradeLaw->ContentCss - - - + + + + + + + +■ + goContentCss - -goContentCss doUpdateContentCss - -doUpdateContentCss + +doUpdateContentCss - + doUpdateContentCss->ContentJs - - - + + + + + + + +■ + goContentJs - -goContentJs doImportClassNameCsv - -doImportClassNameCsv + +doImportClassNameCsv - + doImportClassNameCsv->ClassCategoryList - - - + + + + + + + +■ + goExportClassCategory - -goExportClassCategory goExportCustomer - -goExportCustomer + +goExportCustomer - + goExportCustomer->ClassNameList - - - + + + + + + + +■ + goExportClassName - -goExportClassName doClearCache - -doClearCache + +doClearCache - + doClearCache->Maintenance - - - + + + + + + + +■ + goMaintenance - -goMaintenance doUpdateCustomer - -doUpdateCustomer + +doUpdateCustomer - + doUpdateCustomer->MypageChangeComplete - - - + + + + + + + +■ + goMypageChangeComplete - -goMypageChangeComplete doWithdrawCustomer - -doWithdrawCustomer + +doWithdrawCustomer - + doWithdrawCustomer->MypageWithdrawComplete - - - + + + + + + + +■ + goMypageWithdrawComplete - -goMypageWithdrawComplete doUpdateTrackingNumber - -doUpdateTrackingNumber + +doUpdateTrackingNumber - + doUpdateTrackingNumber->OrderMail - - - + + + + + + + +■ + goOrderMail - -goOrderMail goMailTemplateList - -goMailTemplateList + +goMailTemplateList - + goMailTemplateList->OrderMail - - - + + + + + + + +■ + goOrderMail - -goOrderMail doUpdateOrderStatus - -doUpdateOrderStatus + +doUpdateOrderStatus - + doUpdateOrderStatus->OrderShippingAddress - - - + + + + + + + +■ + goOrderShippingAddress - -goOrderShippingAddress doToggleMaintenance - -doToggleMaintenance + +doToggleMaintenance - + doToggleMaintenance->SystemInfo - - - + + + + + + + +■ + goSystemInfo - -goSystemInfo doSetTwoFactorAuth - -doSetTwoFactorAuth + +doSetTwoFactorAuth - + doSetTwoFactorAuth->TwoFactorAuth - - - + + + + + + + +■ + goTwoFactorAuth - -goTwoFactorAuth doUpdateSecurity - -doUpdateSecurity + +doUpdateSecurity - + doUpdateSecurity->TwoFactorAuthSet - - - + + + + + + + +■ + goTwoFactorAuthSet - -goTwoFactorAuthSet
+
+
Semantic
+
Safe
+
Unsafe
+
Idempotent
+
Label: @@ -9621,7 +10331,7 @@

Semantic Descriptors

TaxRuleList 税率ルール一覧 - TaxRule
goTaxRuleList
doCreateTaxRule + TaxRule
goTaxRuleList
doCreateTaxRule
doDeleteTaxRule tag:shop src-template flow-admin-shop-configuration @@ -9808,12 +10518,6 @@

Semantic Descriptors

-
-
Semantic
-
Safe
-
Unsafe
-
Idempotent
-

Links

+
+
Semantic
+
Safe
+
Unsafe
+
Idempotent
+
Label: @@ -9621,7 +10331,7 @@

Semantic Descriptors

TaxRuleList 税率ルール一覧 - TaxRule
goTaxRuleList
doCreateTaxRule + TaxRule
goTaxRuleList
doCreateTaxRule
doDeleteTaxRule tag:shop src-template flow-admin-shop-configuration @@ -9808,12 +10518,6 @@

Semantic Descriptors

-
-
Semantic
-
Safe
-
Unsafe
-
Idempotent
-

Links

@@ -275,7 +275,7 @@ value="{{ Product.productCode }}" id="check_{{ Product.productCode }}" data-delete-url="/admin/product?productCode={{ Product.productCode }}&_method=delete" - token-for-anchor="{{ csrf_token_for_anchor('admin_product_delete') }}"> + token-for-anchor="{{ csrfToken }}"> @@ -369,7 +369,7 @@ class="idea-admin-action idea-admin-action--primary" data-confirm="false" data-method="post" - token-for-anchor="{{ csrf_token_for_anchor('admin_product_product_copy') }}"> + token-for-anchor="{{ csrfToken }}"> 複製
From 716a8a446da981139b9d902696562b215567670b Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sun, 20 Sep 2026 16:53:54 +0900 Subject: [PATCH 07/10] Fix 3 of 5 dead admin forms and resolve 15 of 19 ALPS reference drifts (#143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Admin `/admin/customer`, `/admin/customer-delivery-edit`, and `/admin/product/product-class` rendered `
` with no onPost/onPut/onDelete to answer it (405). The reference implementation lives on the unmerged `origin/post-redirect-get-303` branch (same merge-base as this branch, `4beee6a7`); cherry-picked `894a92df` and `5e05cb19` for exactly these three resources and reverted everything else those commits touched that was out of #143's scope: - TwoFactorAuthEdit.php / FileManager.php / CustomerList.php: scope decisions #143 explicitly defers to a separate issue. - A whole admin "flash message" feature (AdminFlash.php, admin-base.html.twig calling `admin_flashes()`): the Twig extension never defined that function, so every admin page render would have thrown. Reverted in full rather than half-wire it. - All three template conflicts (Customer/CustomerDeliveryEdit/ ProductClass) resolved to the current idea-admin-* design already on this branch, not the older Bootstrap-table markup the reference branch had — this branch's templates are the newer ones. Each write path got its own admin-specific Be Input/Final (AdminUpdateCustomerInput → AdminCustomerUpdated, Admin{Create,Update,Delete}CustomerDeliveryAddressInput, RegisterProductClassInput → ProductClassRegistered) rather than reusing the storefront transitions: `UpdateCustomerAddressInput` derives the owner from the customer session by design (a customer cannot reassign someone else's address by tampering with the body), and an admin editing a different customer's data is the opposite authorization model. This also resolves #143's actor-naming question in favor of option (B) — separate ids for the admin path (doUpdateCustomerProfile, doUpdateCustomerDeliveryAddress, doRegisterProductClass) rather than widening the storefront ids' docs. ProductClass.php's onGet was never publishing `csrfToken` (same gap #139 fixed elsewhere) — wired `CsrfTokenInterface` and added it to the GET JSON schema. Its template had two bugs: the hidden parent-id field was named `parentProductCode` but onPost reads `productCode`, and the CSRF token had no hidden field to carry it — both fixed. Added 8 new alps.json descriptors for the ids these fixes introduced (goCustomerDeliveryEdit, doUpdateCustomerDeliveryAddress, doDeleteCustomerDeliveryAddress, doUpdateCustomerProfile, goProductClass, doRegisterProductClass, goLog, goOrderPdf) plus the CustomerDeliveryEdit/Log/OrderPdf states they return to; validated with `asd --validate` and regenerated alps.json.html/alps.svg (root + docs/ copies). Dropped `#[Alps]` from the 8 route-gate/fallback ids (doActionRedirect, doAdminActionRedirect, doAdminUnsupportedRoute, doUnsupportedRoute, goActionRedirect, goAdminActionRedirect, goAdminUnsupportedRoute, goUnsupportedRoute) and the goAdminEmptyPage placeholder — these answer URLs EC-CUBE has that BeMart deliberately doesn't model as application transitions, so a client can't discover them anyway. goAdminLog/goAdminOrderOrderPdf/goAdminOrderMailConfirm/ goAdminTemplateTemplateAdd were renamed in the cherry-picked commits (the last two to already-existing profile ids goOrderMailConfirm/ goTemplateInstall; the first two are new — goAdminOrderOrderPdf is NOT a rename of goExportOrderPdf, it's the distinct options-form screen that links to it). Net: 19 drifted references down to 4 (doCreateMailTemplate, goAdminContentFileManager, goAdminTwoFactorAuthEdit, goShoppingShippingMultipleEdit) — updated `AlpsReferenceTest`'s SCREEN_GAP/ROUTE_GATE/PLACEHOLDER lists and `TemplateFormActionTest`'s KNOWN_DEAD list to match, and refreshed `docs/migration-status.md` §2.1/§2.2 and the feature matrix. Fixes made during verification, beyond the cherry-pick: - Customer::onPost($password), AdminUpdateCustomerInput::$password, and AdminCustomerUpdated::$passwordHash were missing #[SensitiveParameter] (CredentialParameterSensitiveParameterTest / CredentialConstructorParameterSensitiveParameterTest caught this). - Password/PasswordHash Semantic validators made nullable: the admin edit flow passes null to mean "leave the current hash untouched" (EC-CUBE's default-password sentinel); a supplied empty string still fails the length floor. - ExportOrderPdf gained an onPost (EC-CUBE's admin_order_pdf_download route) so OrderPdf.php's submit button reaches a real handler instead of 405 — reuses the existing goExportOrderPdf id since both verbs perform the same transition. The cherry-picked smoke-test fixture expected this to return 200, but OrderPdfCompatibilityService::export() unconditionally throws OrderPdfNotSupportedException (a Phase-A stub, tracked in docs/migration-status.md §4 item 5) — fixed the fixture to expect 501, and dropped an unrelated `?category_id=` the cherry-pick had added to the GET /products fixture line (broke JSON Schema validation; unrelated to this issue). - Removed the stale `POST admin/two-factor-auth-edit` smoke-test fixture entry the cherry-pick added — that resource still has no onPost since TwoFactorAuthEdit stays deferred. - HttpSqlAdminProductClassFormTest (a new real-browser/real-MySQL regression from the cherry-pick) assumed a pre-existing `admin-active-001` product/class row that nothing in this environment seeds; added setUp/tearDown that inserts and cleans up the parent dtb_product + dtb_product_class rows directly, since the fixture helper it was written against (SqlFixturesTrait) doesn't exist in this repo (removed by `47016e64`, already documented in #139's commit). - HttpSqlAdminProductClassFormTest's two markup assertions pinned the reverted Bootstrap-table template's `id="product_class_new_row"` and "登録" button text; updated to the kept idea-admin-* template's actual id and "追加" label. - The new #[Link] declarations on Customer/CustomerDeliveryEdit/ ProductClass introduced 5 HTML Link Audit warnings (the templates don't render a matching `rel="..."` token); classified all 5 in html-link-audit-ledger.json — 4 as semantic-token-missing/fail (real markup gaps, tracked), 1 (doDeleteCustomerDeliveryAddress) as method-mismatch/resourceOnly (the edit form has no delete affordance at all; deleting a delivery address is out of this editor's scope). Deferred, per #143: `/admin/content/file-manager` and `/admin/two-factor-auth-edit` stay dead forms (multipart file I/O and admin-editing-another-member 2FA semantics both need their own scope decision first). Verified: full `vendor/bin/phpunit` suite green (2836 tests, 0 failures/errors; the one pre-existing risky test — CsrfTokenRenderedTest::testLedgerEntriesAreWellFormed — is #139's closed-ledger side effect, unrelated), `vendor/bin/psalm` clean (no errors), `asd --validate alps.json` clean. --- alps.json | 30 + alps.json.html | 5929 +++++++++-------- alps.svg | 5818 ++++++++-------- be/src/Being/AdminCustomerUpdating.php | 92 + .../AdminCustomerDeliveryAddressCreated.php | 107 + .../AdminCustomerDeliveryAddressDeleted.php | 61 + .../AdminCustomerDeliveryAddressUpdated.php | 119 + be/src/Final/AdminCustomerUpdated.php | 105 + be/src/Final/ProductClassRegistered.php | 59 + ...dminCreateCustomerDeliveryAddressInput.php | 56 + ...dminDeleteCustomerDeliveryAddressInput.php | 34 + ...dminUpdateCustomerDeliveryAddressInput.php | 57 + be/src/Input/AdminUpdateCustomerInput.php | 90 + be/src/Input/RegisterProductClassInput.php | 33 + .../Entity/RegisteredProductClassEntity.php | 35 + .../ProductClassRegisterIdProvider.php | 24 + .../ProductClassRegisterIdQueryInterface.php | 18 + .../Query/ProductClassStorageInterface.php | 28 + be/src/Semantic/Password.php | 15 +- be/src/Semantic/PasswordHash.php | 8 +- be/var/fake/query/productClass_next_id.jsonl | 1 + be/var/fake/query/tproduct_class_get.jsonl | 1 + docs/alps.json.html | 5929 +++++++++-------- docs/alps.svg | 5818 ++++++++-------- docs/migration-status.md | 84 +- src/Resource/Page/ActionRedirect.php | 5 - src/Resource/Page/Admin/ActionRedirect.php | 5 - src/Resource/Page/Admin/Customer.php | 104 + .../Page/Admin/CustomerDeliveryEdit.php | 166 +- src/Resource/Page/Admin/EmptyPage.php | 2 - src/Resource/Page/Admin/Log.php | 4 +- .../Page/Admin/Order/ExportOrderPdf.php | 26 + src/Resource/Page/Admin/Order/MailConfirm.php | 4 +- src/Resource/Page/Admin/Order/OrderPdf.php | 4 +- .../Page/Admin/Product/ProductClass.php | 115 +- .../Page/Admin/Template/TemplateAdd.php | 4 +- src/Resource/Page/Admin/UnsupportedRoute.php | 5 - src/Resource/Page/UnsupportedRoute.php | 5 - tests/Alps/AlpsReferenceTest.php | 53 +- tests/Html/html-link-audit-ledger.json | 25 + .../Http/HttpSqlAdminProductClassFormTest.php | 301 + .../FlowAdminCustomerMaintenanceTest.php | 99 +- .../AdminCustomerDeliveryEditResourceTest.php | 136 +- .../AdminProductClassResourceTest.php | 36 + .../AdminUpdateCustomerResourceTest.php | 141 + tests/Router/TemplateFormActionTest.php | 3 - tests/Smoke/ResourceSmokeTest.php | 5 + .../delete-admin-customer-delivery-edit.json | 255 + .../get-admin-product-product-class.json | 10 + .../post-admin-customer-delivery-edit.json | 372 ++ .../post-admin-product-product-class.json | 32 + .../post-admin-update-customer.json | 278 + ...te-admin-customer-delivery-edit.param.json | 252 + ...st-admin-customer-delivery-edit.param.json | 360 + ...ost-admin-product-product-class.param.json | 93 + .../post-admin-update-customer.param.json | 414 ++ var/sql/productClass_next_id.sql | 7 + var/sql/tproduct_class_get.sql | 17 + var/sql/tproduct_class_put.sql | 92 + .../Page/Admin/Product/ProductClass.html.twig | 4 +- 60 files changed, 16460 insertions(+), 11525 deletions(-) create mode 100644 be/src/Being/AdminCustomerUpdating.php create mode 100644 be/src/Final/AdminCustomerDeliveryAddressCreated.php create mode 100644 be/src/Final/AdminCustomerDeliveryAddressDeleted.php create mode 100644 be/src/Final/AdminCustomerDeliveryAddressUpdated.php create mode 100644 be/src/Final/AdminCustomerUpdated.php create mode 100644 be/src/Final/ProductClassRegistered.php create mode 100644 be/src/Input/AdminCreateCustomerDeliveryAddressInput.php create mode 100644 be/src/Input/AdminDeleteCustomerDeliveryAddressInput.php create mode 100644 be/src/Input/AdminUpdateCustomerDeliveryAddressInput.php create mode 100644 be/src/Input/AdminUpdateCustomerInput.php create mode 100644 be/src/Input/RegisterProductClassInput.php create mode 100644 be/src/Reason/Entity/RegisteredProductClassEntity.php create mode 100644 be/src/Reason/Provider/ProductClassRegisterIdProvider.php create mode 100644 be/src/Reason/Query/ProductClassRegisterIdQueryInterface.php create mode 100644 be/src/Reason/Query/ProductClassStorageInterface.php create mode 100644 be/var/fake/query/productClass_next_id.jsonl create mode 100644 be/var/fake/query/tproduct_class_get.jsonl create mode 100644 tests/Http/HttpSqlAdminProductClassFormTest.php create mode 100644 tests/Resource/AdminUpdateCustomerResourceTest.php create mode 100644 var/json_schema/delete-admin-customer-delivery-edit.json create mode 100644 var/json_schema/post-admin-customer-delivery-edit.json create mode 100644 var/json_schema/post-admin-product-product-class.json create mode 100644 var/json_schema/post-admin-update-customer.json create mode 100644 var/json_validate/delete-admin-customer-delivery-edit.param.json create mode 100644 var/json_validate/post-admin-customer-delivery-edit.param.json create mode 100644 var/json_validate/post-admin-product-product-class.param.json create mode 100644 var/json_validate/post-admin-update-customer.param.json create mode 100644 var/sql/productClass_next_id.sql create mode 100644 var/sql/tproduct_class_get.sql create mode 100644 var/sql/tproduct_class_put.sql diff --git a/alps.json b/alps.json index a04be3d72..d76eccd41 100644 --- a/alps.json +++ b/alps.json @@ -1570,6 +1570,12 @@ "tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog", "doc": {"value": "商品マスタを複製する。基本情報・規格(ProductClass)・画像を新規 Product として複製。タイトルは「(コピー) 」プレフィクス付き。"}, "descriptor": [{"href": "#productName"}]}, + {"id": "goProductClass", "title": "商品規格編集を見る", "type": "safe", "rt": "#ProductClass", + "tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog flow-admin-product-publish", + "doc": {"value": "商品規格(バリエーション)の登録フォームを表示する(管理画面)。"}}, + {"id": "doRegisterProductClass", "title": "商品規格を登録する", "type": "unsafe", "rt": "#ProductClass", + "tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog flow-admin-product-publish", + "doc": {"value": "商品に新しい規格(バリエーション)行を登録する(管理画面)。"}}, {"id": "doBulkUpdateProductStatus", "title": "商品ステータスを一括変更する", "type": "unsafe", "rt": "#ProductList", "tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog", "doc": {"value": "選択した商品のステータス(公開・非公開・廃止)を一括変更する。"}, @@ -1735,6 +1741,11 @@ {"id": "doSendShippingNotifyMail", "title": "出荷通知メールを送信する", "type": "unsafe", "rt": "#Order", "tag": "order flow-manage-order actor-admin src-router feature-admin-order flow-admin-order-fulfillment", "doc": {"value": "受注一覧画面(admin/Order/index.twig)から配送(Shipping)単位の出荷通知メールを顧客へ送信する。EC-CUBE の admin_shipping_notify_mail ルートから導出。受注メール手動送信(doSendOrderMail)とは別物で、出荷済みの配送に対する顧客通知。送信のたびにメールが発生するため unsafe。"}}, + {"id": "OrderPdf", "title": "帳票PDF出力オプション", "tag": "order flow-manage-order actor-admin feature-admin-order flow-admin-order-fulfillment", + "doc": {"value": "納品書PDFのタイトル・挨拶文・備考・発行日を設定するオプション画面。実際のPDF生成は goExportOrderPdf が担う。"}}, + {"id": "goOrderPdf", "title": "帳票PDF出力オプションを見る", "type": "safe", "rt": "#OrderPdf", + "tag": "order flow-manage-order actor-admin src-router feature-admin-order flow-admin-order-fulfillment", + "doc": {"value": "納品書PDFのタイトル・挨拶文・備考・発行日を設定するオプションフォームを表示する(管理画面)。"}}, {"id": "goExportOrderPdf", "title": "帳票PDFをエクスポートする", "type": "safe", "rt": "#OrderList", "tag": "order flow-manage-order actor-admin src-router feature-admin-order flow-admin-order-fulfillment", "doc": {"value": "選択受注の納品書・領収書PDFを出力する。テンプレートは設定で変更可能。"}, @@ -1816,6 +1827,9 @@ "tag": "account flow-manage-customer src-router feature-admin-customer", "doc": {"value": "会員詳細を表示する(管理画面)。基本情報・購入履歴・お気に入り・配送先・ポイント残高を含む。"}, "descriptor": [{"href": "#email"}]}, + {"id": "doUpdateCustomerProfile", "title": "会員情報を更新する", "type": "idempotent", "rt": "#Customer", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "管理画面から会員の基本情報(氏名・メール・住所・生年月日・性別・職業・パスワード等)を更新する。"}}, {"id": "doCreateCustomer", "title": "会員を作成する", "type": "unsafe", "rt": "#Customer", "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", "doc": {"value": "管理画面から会員を新規作成する。仮会員フラグなしで即時本会員として登録。"}, @@ -1832,6 +1846,17 @@ "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer flow-admin-csv-exchange", "doc": {"value": "会員データをCSV形式でダウンロードする。検索条件で絞り込み可能。"}, "descriptor": [{"href": "#goExportClassName"}]}, + {"id": "CustomerDeliveryEdit", "title": "お届け先編集", "tag": "account src-template flow-manage-customer actor-admin feature-admin-customer", + "doc": {"value": "管理画面での会員お届け先(配送先住所)編集画面。氏名・フリガナ・会社名・郵便番号・都道府県・住所・電話番号を保持し、追加・更新・削除を行う。"}}, + {"id": "goCustomerDeliveryEdit", "title": "お届け先編集を見る", "type": "safe", "rt": "#CustomerDeliveryEdit", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "会員のお届け先編集フォームを表示する(管理画面)。"}}, + {"id": "doUpdateCustomerDeliveryAddress", "title": "お届け先を登録・更新する", "type": "unsafe", "rt": "#Customer", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "会員のお届け先を追加または更新する(管理画面)。addressId が空なら新規追加、指定があれば既存行を更新。"}}, + {"id": "doDeleteCustomerDeliveryAddress", "title": "お届け先を削除する", "type": "idempotent", "rt": "#Customer", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "会員のお届け先を1件削除する(管理画面)。"}}, {"id": "goCustomerAddressList", "title": "配送先一覧を見る", "type": "safe", "rt": "#CustomerAddressList", "tag": "account flow-account actor-customer src-router feature-account flow-customer-account-maintenance", @@ -2163,6 +2188,8 @@ {"id": "SystemInfo", "title": "システム情報", "tag": "src-template alps-route-gate flow-admin-system-operation", "doc": {"value": "システム情報を表す画面状態。"}, "descriptor": [{"href": "#doAdminLogout"}]}, + {"id": "Log", "title": "ログ表示", "tag": "src-template alps-route-gate flow-admin-system-operation", + "doc": {"value": "モジュールが固定するログファイルパスから直近の行を tail 表示する読み取り専用画面(Setting/System Tier-2)。"}}, {"id": "TemplateInstall", "title": "テンプレート追加", "tag": "src-template alps-route-gate flow-admin-template-lifecycle", "doc": {"value": "テンプレート追加を表す画面状態。"}, "descriptor": [{"href": "#doInstallTemplate"}]}, @@ -2352,6 +2379,9 @@ {"id": "goSecurity", "title": "セキュリティ設定を見る", "type": "safe", "rt": "#Security", "tag": "src-router alps-route-gate flow-admin-system-operation", "doc": {"value": "ユーザーが見る状態または行う操作をALPS上で表す。"}}, + {"id": "goLog", "title": "ログを見る", "type": "safe", "rt": "#Log", + "tag": "src-router alps-route-gate flow-admin-system-operation", + "doc": {"value": "モジュール固定パスのログファイル末尾を表示する(管理画面、読み取り専用)。"}}, {"id": "goShoppingComplete", "title": "購入完了を見る", "type": "safe", "rt": "#ShoppingComplete", "tag": "src-router alps-route-gate flow-customer-purchase", "doc": {"value": "ユーザーが見る状態または行う操作をALPS上で表す。"}}, diff --git a/alps.json.html b/alps.json.html index b666f38f5..a64191657 100644 --- a/alps.json.html +++ b/alps.json.html @@ -206,26 +206,26 @@

EC-CUBE 4.3 アプリケーションプロファイル

- - + + application_state_diagram - + Top - -Top + +Top - + Product - - -Product + + +Product @@ -233,25 +233,25 @@

EC-CUBE 4.3 アプリケーションプロファイル

Top->Product - - + + -■ - goProduct +■ + goProduct - + ProductList - - -ProductList + + +ProductList @@ -259,51 +259,51 @@

EC-CUBE 4.3 アプリケーションプロファイル

Top->ProductList - - + + -■ - goProductList +■ + goProductList
- + Cart - - -Cart + + +Cart - + Top->Cart - - - + + + - - -■ - goCart + + +■ + goCart - + Login - - -Login + + +Login @@ -311,249 +311,258 @@

EC-CUBE 4.3 アプリケーションプロファイル

Top->Login - - + + -■ - goLogin +■ + goLogin
- + CustomerRegistration - - -CustomerRegistration + + +CustomerRegistration - + Top->CustomerRegistration - - - + + + - - -■ - goCustomerRegistration + + +■ + goCustomerRegistration - + Mypage - - -Mypage + + +Mypage - + Top->Mypage - - - + + + - - -■ - goMypage + + +■ + goMypage - + HelpAbout - - -HelpAbout + + +HelpAbout - + Top->HelpAbout - - - + + + - - -■ - goHelpAbout + + +■ + goHelpAbout - + HelpGuide - - -HelpGuide + + +HelpGuide - + Top->HelpGuide - - - + + + - - -■ - goHelpGuide + + +■ + goHelpGuide - + HelpAgreement - - -HelpAgreement + + +HelpAgreement - + Top->HelpAgreement - - - + + + - - -■ - goHelpAgreement + + +■ + goHelpAgreement - + HelpPrivacy - - -HelpPrivacy + + +HelpPrivacy - + Top->HelpPrivacy - - - + + + - - -■ - goHelpPrivacy + + +■ + goHelpPrivacy - + HelpTradeLaw - - -HelpTradeLaw + + +HelpTradeLaw - + Top->HelpTradeLaw - - - + + + - - -■ - goHelpTradeLaw + + +■ + goHelpTradeLaw - + ContactForm - - -ContactForm + + +ContactForm - + Top->ContactForm - - - + + + - - -■ - goContactForm + + +■ + goContactForm + + +ProductClass + + +ProductClass + + + Product->Product - - + + -■ - goProduct +■ + goProduct -■ - doCreateProduct +■ + doCreateProduct -■ - doUpdateProduct +■ + doUpdateProduct @@ -563,114 +572,114 @@

EC-CUBE 4.3 アプリケーションプロファイル

Product->ProductList - - + + -■ - goProductList +■ + goProductList -■ - doDeleteProduct +■ + doDeleteProduct
- + Category - - -Category + + +Category - + Product->Category - - - + + + - - -■ - goCategory + + +■ + goCategory - + Product->Cart - - - + + + - - -■ - doAddCartItem + + +■ + doAddCartItem - + CustomerFavoriteProduct - - -CustomerFavoriteProduct + + +CustomerFavoriteProduct - + Product->CustomerFavoriteProduct - - - + + + - - -■ - doAddFavorite + + +■ + doAddFavorite - + CustomerFavoriteProductList - - -CustomerFavoriteProductList + + +CustomerFavoriteProductList - + Product->CustomerFavoriteProductList - - - + + + - - -■ - doRemoveFavorite + + +■ + doRemoveFavorite @@ -680,24 +689,24 @@

EC-CUBE 4.3 アプリケーションプロファイル

ProductList->Product - - + + -■ - goProduct +■ + goProduct -■ - doCreateProduct +■ + doCreateProduct -■ - doCopyProduct +■ + doCopyProduct @@ -707,40 +716,40 @@

EC-CUBE 4.3 アプリケーションプロファイル

ProductList->ProductList - - + + -■ - goProductList +■ + goProductList
- + CategoryList - - -CategoryList + + +CategoryList - + ProductList->CategoryList - - - + + + - - -■ - goCategoryList + + +■ + goCategoryList @@ -750,815 +759,815 @@

EC-CUBE 4.3 アプリケーションプロファイル

Category->ProductList - - + + -■ - goProductList +■ + goProductList
- + Category->Category - - - + + + - - -■ - goCategory + + +■ + goCategory - -■ - doUpdateCategory + +■ + doUpdateCategory - + Category->CategoryList - - - + + + - - -■ - goCategoryList + + +■ + goCategoryList - -■ - doDeleteCategory + +■ + doDeleteCategory - + CategoryList->Category - - - + + + - - -■ - goCategory + + +■ + goCategory - -■ - doCreateCategory + +■ + doCreateCategory - + Tag - - -Tag + + +Tag - + TagList - - -TagList + + +TagList - + Tag->TagList - - - + + + - - -■ - doDeleteTag + + +■ + doDeleteTag - + TagList->Tag - - - + + + - - -■ - doCreateTag + + +■ + doCreateTag - + TagList->TagList - - - + + + - - -■ - goTagList + + +■ + goTagList - + AdminTop - - -AdminTop + + +AdminTop - + TagList->AdminTop - - - + + + - - -■ - doSortNoMove + + +■ + doSortNoMove - + ClassName - - -ClassName + + +ClassName - + ClassName->ClassName - - - + + + - - -■ - doUpdateClassName + + +■ + doUpdateClassName - + ClassNameList - - -ClassNameList + + +ClassNameList - + ClassName->ClassNameList - - - + + + - - -■ - doDeleteClassName + + +■ + doDeleteClassName - + ClassNameList->ClassName - - - + + + - - -■ - doCreateClassName + + +■ + doCreateClassName - + ClassNameList->ClassNameList - - - + + + - - -■ - goClassNameList + + +■ + goClassNameList - + ClassNameList->AdminTop - - - + + + - - -■ - doSortNoMove + + +■ + doSortNoMove - + ClassCategory - - -ClassCategory + + +ClassCategory - + ClassCategory->ClassCategory - - - + + + - - -■ - doUpdateClassCategory + + +■ + doUpdateClassCategory - + ClassCategoryList - - -ClassCategoryList + + +ClassCategoryList - + ClassCategory->ClassCategoryList - - - + + + - - -■ - doDeleteClassCategory + + +■ + doDeleteClassCategory - + ClassCategoryList->ClassCategory - - - + + + - - -■ - doCreateClassCategory + + +■ + doCreateClassCategory - + ClassCategoryList->ClassCategoryList - - - + + + - - -■ - goClassCategoryList + + +■ + goClassCategoryList - + ClassCategoryList->AdminTop - - - + + + - - -■ - doSortNoMove + + +■ + doSortNoMove - -■ - doToggleVisible + +■ + doToggleVisible - + Cart->Cart - - - + + + - - -■ - goCart + + +■ + goCart - -■ - doAddCartItem + +■ + doAddCartItem - -■ - doUpdateCartItemQuantity + +■ + doUpdateCartItemQuantity - -■ - doRemoveCartItem + +■ + doRemoveCartItem - + CheckoutEntry - - -CheckoutEntry + + +CheckoutEntry - + Cart->CheckoutEntry - - - + + + - - -■ - doSelectCartForCheckout + + +■ + doSelectCartForCheckout - -■ - goCheckoutEntry + +■ + goCheckoutEntry - + CheckoutEntry->Cart - - - + + + - - -■ - goCart + + +■ + goCart - + ShoppingLogin - - -ShoppingLogin + + +ShoppingLogin - + CheckoutEntry->ShoppingLogin - - - + + + - - -■ - goShoppingLogin + + +■ + goShoppingLogin - + ShoppingNonMember - - -ShoppingNonMember + + +ShoppingNonMember - + CheckoutEntry->ShoppingNonMember - - - + + + - - -■ - goShoppingNonMember + + +■ + goShoppingNonMember - + Shopping - - -Shopping + + +Shopping - + CheckoutEntry->Shopping - - - + + + - - -■ - goShopping + + +■ + goShopping - + ShoppingLogin->ShoppingNonMember - - - + + + - - -■ - goShoppingNonMember + + +■ + goShoppingNonMember - + ShoppingLogin->CustomerRegistration - - - + + + - - -■ - goCustomerRegistration + + +■ + goCustomerRegistration - + ShoppingLogin->Mypage - - - + + + - - -■ - doLogin + + +■ + doLogin - + ShoppingNonMember->Shopping - - - + + + - - -■ - doSubmitNonMember + + +■ + doSubmitNonMember - + Shopping->Shopping - - - + + + - - -■ - doShoppingRedirectTo + + +■ + doShoppingRedirectTo - -■ - goShoppingShippingMultiple + +■ + goShoppingShippingMultiple - + ShoppingShipping - - -ShoppingShipping + + +ShoppingShipping - + Shopping->ShoppingShipping - - - + + + - - -■ - goShoppingShipping + + +■ + goShoppingShipping - + ShoppingShippingEdit - - -ShoppingShippingEdit + + +ShoppingShippingEdit - + Shopping->ShoppingShippingEdit - - - + + + - - -■ - goShoppingShippingEdit + + +■ + goShoppingShippingEdit - + ShoppingConfirm - - -ShoppingConfirm + + +ShoppingConfirm - + Shopping->ShoppingConfirm - - - + + + - - -■ - doConfirmOrder + + +■ + doConfirmOrder - + ShoppingError - - -ShoppingError + + +ShoppingError - + Shopping->ShoppingError - - - + + + - - -■ - goShoppingError + + +■ + goShoppingError - + ShoppingShipping->Shopping - - - + + + - - -■ - doSelectShippingAddress + + +■ + doSelectShippingAddress - + ShoppingShippingEdit->Shopping - - - + + + - - -■ - doUpdateShippingAddress + + +■ + doUpdateShippingAddress - + ShoppingComplete - - -ShoppingComplete + + +ShoppingComplete - + ShoppingConfirm->ShoppingComplete - - - + + + - - -■ - doCheckout + + +■ + doCheckout - + ShoppingConfirm->ShoppingError - - - + + + - - -■ - goShoppingError + + +■ + goShoppingError @@ -1568,492 +1577,492 @@

EC-CUBE 4.3 アプリケーションプロファイル

ShoppingComplete->Top - - + + -■ - goTop +■ + goTop
- + ShoppingComplete->Cart - - - + + + - - -■ - goCart + + +■ + goCart - + ShoppingError->Cart - - - + + + - - -■ - goCart + + +■ + goCart - + Order - - -Order + + +Order - + Order->Cart - - - + + + - - -■ - doReorder + + +■ + doReorder - + Order->Order - - - + + + - - -■ - goOrder + + +■ + goOrder - -■ - doUpdateOrder + +■ + doUpdateOrder - -■ - doUpdateOrderStatus + +■ + doUpdateOrderStatus - -■ - doUpdateTrackingNumber + +■ + doUpdateTrackingNumber - -■ - doSendShippingNotifyMail + +■ + doSendShippingNotifyMail - + OrderList - - -OrderList + + +OrderList - + Order->OrderList - - - + + + - - -■ - goOrderList + + +■ + goOrderList - -■ - goExportOrderPdf + +■ + goExportOrderPdf - + MailHistory - - -MailHistory + + +MailHistory - + Order->MailHistory - - - + + + - - -■ - doSendOrderMail + + +■ + doSendOrderMail - + OrderShippingAddress - - -OrderShippingAddress + + +OrderShippingAddress - + Order->OrderShippingAddress - - - + + + - - -■ - goOrderShippingAddress + + +■ + goOrderShippingAddress - + OrderList->Order - - - + + + - - -■ - goOrder + + +■ + goOrder - -■ - doCreateOrder + +■ + doCreateOrder - + OrderList->OrderList - - - + + + - - -■ - goOrderList + + +■ + goOrderList - + Customer - - -Customer + + +Customer - + Customer->Top - - - + + + - - -■ - doWithdrawCustomer + + +■ + doWithdrawCustomer - + Customer->OrderList - - - + + + - - -■ - goOrderHistory + + +■ + goOrderHistory - + Customer->Customer - - - + + + - - -■ - goCustomer + + +■ + goCustomer - + CustomerAddressList - - -CustomerAddressList + + +CustomerAddressList - + Customer->CustomerAddressList - - - + + + - - -■ - goCustomerAddressList + + +■ + goCustomerAddressList - + Customer->CustomerFavoriteProductList - - - + + + - - -■ - goFavoriteList + + +■ + goFavoriteList - + MypageChange - - -MypageChange + + +MypageChange - + Customer->MypageChange - - - + + + - - -■ - doUpdateCustomer + + +■ + doUpdateCustomer - + CustomerList - - -CustomerList + + +CustomerList - + CustomerList->Customer - - - + + + - - -■ - goCustomer + + +■ + goCustomer - -■ - doCreateCustomer + +■ + doCreateCustomer - + CustomerList->CustomerList - - - + + + - - -■ - goCustomerList + + +■ + goCustomerList - -■ - doResendActivationMail + +■ + doResendActivationMail - + CustomerAddress - - -CustomerAddress + + +CustomerAddress - + CustomerAddress->CustomerAddress - - - + + + - - -■ - doUpdateCustomerAddress + + +■ + doUpdateCustomerAddress - + CustomerAddress->CustomerAddressList - - - + + + - - -■ - doDeleteCustomerAddress + + +■ + doDeleteCustomerAddress - + CustomerAddressList->CustomerAddress - - - + + + - - -■ - doCreateCustomerAddress + + +■ + doCreateCustomerAddress - + CustomerAddressList->CustomerFavoriteProductList - - - + + + - - -■ - goFavoriteList + + +■ + goFavoriteList @@ -2063,177 +2072,177 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerFavoriteProduct->Product - - + + -■ - goProduct +■ + goProduct
- + CustomerFavoriteProduct->CustomerFavoriteProductList - - - + + + - - -■ - doRemoveFavorite + + +■ + doRemoveFavorite - + CustomerFavoriteProductList->CustomerFavoriteProductList - - - + + + - - -■ - goFavoriteList + + +■ + goFavoriteList - + Login->CustomerRegistration - - - + + + - - -■ - goCustomerRegistration + + +■ + goCustomerRegistration - + Login->Mypage - - - + + + - - -■ - doLogin + + +■ + doLogin - + PasswordReset - - -PasswordReset + + +PasswordReset - + PasswordReset->Login - - - + + + - - -■ - doResetPassword + + +■ + doResetPassword - + CustomerRegistration->CustomerRegistration - - - + + + - - -■ - goCustomerRegistration + + +■ + goCustomerRegistration - + CustomerRegistrationComplete - - -CustomerRegistrationComplete + + +CustomerRegistrationComplete - + CustomerRegistration->CustomerRegistrationComplete - - - + + + - - -■ - doRegisterCustomer + + +■ + doRegisterCustomer - + CustomerRegistrationConfirm - - -CustomerRegistrationConfirm + + +CustomerRegistrationConfirm - + CustomerRegistration->CustomerRegistrationConfirm - - - + + + - - -■ - goCustomerRegistrationConfirm + + +■ + goCustomerRegistrationConfirm @@ -2243,117 +2252,117 @@

EC-CUBE 4.3 アプリケーションプロファイル

CustomerRegistrationComplete->Top - - + + -■ - goTop +■ + goTop
- + Mypage->CustomerAddressList - - - + + + - - -■ - goCustomerAddressList + + +■ + goCustomerAddressList - + Mypage->CustomerFavoriteProductList - - - + + + - - -■ - goFavoriteList + + +■ + goFavoriteList - + MypageHistory - - -MypageHistory + + +MypageHistory - + Mypage->MypageHistory - - - + + + - - -■ - goMypageHistory + + +■ + goMypageHistory - + Mypage->MypageChange - - - + + + - - -■ - goMypageChange + + +■ + goMypageChange - + MypageWithdraw - - -MypageWithdraw + + +MypageWithdraw - + Mypage->MypageWithdraw - - - + + + - - -■ - goMypageWithdraw + + +■ + goMypageWithdraw @@ -2363,196 +2372,196 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageHistory->Product - - + + -■ - goProduct +■ + goProduct
- + MypageHistory->Cart - - - + + + - - -■ - doReorder + + +■ + doReorder - + MypageHistory->Mypage - - - + + + - - -■ - goMypage + + +■ + goMypage - + MypageChange->MypageChange - - - + + + - - -■ - doUpdateCustomer + + +■ + doUpdateCustomer - + MypageChangeComplete - - -MypageChangeComplete + + +MypageChangeComplete - + MypageChangeComplete->CustomerAddressList - - - + + + - - -■ - goCustomerAddressList + + +■ + goCustomerAddressList - + MypageChangeComplete->Mypage - - - + + + - - -■ - goMypage + + +■ + goMypage - + MypageWithdraw->Top - - - + + + - - -■ - doWithdrawCustomer + + +■ + doWithdrawCustomer - + MypageWithdrawConfirm - - -MypageWithdrawConfirm + + +MypageWithdrawConfirm - + MypageWithdraw->MypageWithdrawConfirm - - - + + + - - -■ - goMypageWithdrawConfirm + + +■ + goMypageWithdrawConfirm - + MypageWithdrawConfirm->Top - - - + + + - - -■ - doWithdrawCustomer + + +■ + doWithdrawCustomer - + MypageWithdrawConfirm->Mypage - - - + + + - - -■ - goMypage + + +■ + goMypage - + MypageWithdrawComplete - - -MypageWithdrawComplete + + +MypageWithdrawComplete @@ -2560,14 +2569,14 @@

EC-CUBE 4.3 アプリケーションプロファイル

MypageWithdrawComplete->Top - - + + -■ - goTop +■ + goTop @@ -2577,14 +2586,14 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpAbout->Top - - + + -■ - goTop +■ + goTop @@ -2594,14 +2603,14 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpGuide->Top - - + + -■ - goTop +■ + goTop @@ -2611,14 +2620,14 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpAgreement->Top - - + + -■ - goTop +■ + goTop @@ -2628,14 +2637,14 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpPrivacy->Top - - + + -■ - goTop +■ + goTop @@ -2645,657 +2654,657 @@

EC-CUBE 4.3 アプリケーションプロファイル

HelpTradeLaw->Top - - + + -■ - goTop +■ + goTop
- + BaseInfo - - -BaseInfo + + +BaseInfo - + BaseInfo->BaseInfo - - - + + + - - -■ - goBaseInfo + + +■ + goBaseInfo - -■ - doUpdateBaseInfo + +■ + doUpdateBaseInfo - + PaymentList - - -PaymentList + + +PaymentList - + BaseInfo->PaymentList - - - + + + - - -■ - goPaymentList + + +■ + goPaymentList - + Payment - - -Payment + + +Payment - + Payment->Payment - - - + + + - - -■ - doUpdatePayment + + +■ + doUpdatePayment - + Payment->PaymentList - - - + + + - - -■ - doDeletePayment + + +■ + doDeletePayment - + PaymentList->Payment - - - + + + - - -■ - doCreatePayment + + +■ + doCreatePayment - -■ - goPayment + +■ + goPayment - + PaymentList->PaymentList - - - + + + - - -■ - goPaymentList + + +■ + goPaymentList - + PaymentList->AdminTop - - - + + + - - -■ - doSortNoMove + + +■ + doSortNoMove - -■ - doToggleVisible + +■ + doToggleVisible - + Delivery - - -Delivery + + +Delivery - + Delivery->Delivery - - - + + + - - -■ - doUpdateDelivery + + +■ + doUpdateDelivery - + DeliveryList - - -DeliveryList + + +DeliveryList - + Delivery->DeliveryList - - - + + + - - -■ - doDeleteDelivery + + +■ + doDeleteDelivery - + DeliveryList->Delivery - - - + + + - - -■ - doCreateDelivery + + +■ + doCreateDelivery - -■ - goDelivery + +■ + goDelivery - + DeliveryList->DeliveryList - - - + + + - - -■ - goDeliveryList + + +■ + goDeliveryList - + DeliveryList->AdminTop - - - + + + - - -■ - doSortNoMove + + +■ + doSortNoMove - -■ - doToggleVisible + +■ + doToggleVisible - + TaxRule - - -TaxRule + + +TaxRule - + TaxRuleList - - -TaxRuleList + + +TaxRuleList - + TaxRule->TaxRuleList - - - + + + - - -■ - doDeleteTaxRule + + +■ + doDeleteTaxRule - + TaxRuleList->TaxRule - - - + + + - - -■ - doCreateTaxRule + + +■ + doCreateTaxRule - + TaxRuleList->TaxRuleList - - - + + + - - -■ - goTaxRuleList + + +■ + goTaxRuleList - -■ - doDeleteTaxRule + +■ + doDeleteTaxRule - + News - - -News + + +News - + News->News - - - + + + - - -■ - goNews + + +■ + goNews - -■ - doUpdateNews + +■ + doUpdateNews - + NewsList - - -NewsList + + +NewsList - + News->NewsList - - - + + + - - -■ - doDeleteNews + + +■ + doDeleteNews - + PageList - - -PageList + + +PageList - + News->PageList - - - + + + - - -■ - goPageList + + +■ + goPageList - + NewsList->News - - - + + + - - -■ - goNews + + +■ + goNews - -■ - doCreateNews + +■ + doCreateNews - + NewsList->NewsList - - - + + + - - -■ - goNewsList + + +■ + goNewsList - + NewsList->AdminTop - - - + + + - - -■ - doToggleVisible + + +■ + doToggleVisible - + Page - - -Page + + +Page - + Page->Page - - - + + + - - -■ - goPage + + +■ + goPage - -■ - doUpdatePage + +■ + doUpdatePage - + Page->PageList - - - + + + - - -■ - doDeletePage + + +■ + doDeletePage - + BlockList - - -BlockList + + +BlockList - + Page->BlockList - - - + + + - - -■ - goBlockList + + +■ + goBlockList - + PageList->Page - - - + + + - - -■ - goPage + + +■ + goPage - -■ - doCreatePage + +■ + doCreatePage - + PageList->PageList - - - + + + - - -■ - goPageList + + +■ + goPageList - + ContactForm->ContactForm - - - + + + - - -■ - goContactForm + + +■ + goContactForm - + ContactComplete - - -ContactComplete + + +ContactComplete - + ContactForm->ContactComplete - - - + + + - - -■ - doSubmitContact + + +■ + doSubmitContact @@ -3305,730 +3314,739 @@

EC-CUBE 4.3 アプリケーションプロファイル

ContactComplete->Top - - + + -■ - goTop +■ + goTop
- + Member - - -Member + + +Member - + Member->Member - - - + + + - - -■ - goMember + + +■ + goMember - -■ - doUpdateMember + +■ + doUpdateMember - + MemberList - - -MemberList + + +MemberList - + Member->MemberList - - - + + + - - -■ - doDeleteMember + + +■ + doDeleteMember - + MemberList->Member - - - + + + - - -■ - goMember + + +■ + goMember - -■ - doCreateMember + +■ + doCreateMember - + MemberList->MemberList - - - + + + - - -■ - goMemberList + + +■ + goMemberList - + AuthorityRole - - -AuthorityRole + + +AuthorityRole - + AuthorityRole->AuthorityRole - - - + + + - - -■ - doUpdateAuthorityRole + + +■ + doUpdateAuthorityRole - + MailTemplate - - -MailTemplate + + +MailTemplate - + MailTemplate->MailTemplate - - - + + + - - -■ - doUpdateMailTemplate + + +■ + doUpdateMailTemplate - + MailTemplateList - - -MailTemplateList + + +MailTemplateList - + MailTemplate->MailTemplateList - - - + + + - - -■ - doDeleteMailTemplate + + +■ + doDeleteMailTemplate - + OrderMail - - -OrderMail + + +OrderMail - + MailTemplate->OrderMail - - - + + + - - -■ - goOrderMail + + +■ + goOrderMail - + MailTemplateList->MailTemplateList - - - + + + - - -■ - goMailTemplateList + + +■ + goMailTemplateList - + LoginHistoryList - - -LoginHistoryList + + +LoginHistoryList - + LoginHistoryList->LoginHistoryList - - - + + + - - -■ - goLoginHistoryList + + +■ + goLoginHistoryList - + Security - - -Security + + +Security - + LoginHistoryList->Security - - - + + + - - -■ - goSecurity + + +■ + goSecurity - + Csv - - -Csv + + +Csv - + Csv->ProductList - - - + + + - - -■ - goExportProduct + + +■ + goExportProduct - + Csv->Csv - - - + + + - - -■ - doUpdateCsv + + +■ + doUpdateCsv - + Plugin - - -Plugin + + +Plugin - + Plugin->Plugin - - - + + + - - -■ - doEnablePlugin + + +■ + doEnablePlugin - -■ - doDisablePlugin + +■ + doDisablePlugin - + PluginList - - -PluginList + + +PluginList - + Plugin->PluginList - - - + + + - - -■ - doUninstallPlugin + + +■ + doUninstallPlugin - + PluginList->Plugin - - - + + + - - -■ - doInstallPlugin + + +■ + doInstallPlugin - + PluginList->PluginList - - - + + + - - -■ - goPluginList + + +■ + goPluginList - + TemplateList - - -TemplateList + + +TemplateList - + TemplateList->TemplateList - - - + + + - - -■ - goTemplateList + + +■ + goTemplateList - -■ - doDeleteTemplate + +■ + doDeleteTemplate - -■ - doDownloadTemplate + +■ + doDownloadTemplate - -■ - doSelectTemplate + +■ + doSelectTemplate - + TemplateInstall - - -TemplateInstall + + +TemplateInstall - + TemplateList->TemplateInstall - - - + + + - - -■ - goTemplateInstall + + +■ + goTemplateInstall - + Layout - - -Layout + + +Layout - + Layout->Layout - - - + + + - - -■ - doUpdateLayout + + +■ + doUpdateLayout - + TradeLawList - - -TradeLawList + + +TradeLawList - + Layout->TradeLawList - - - + + + - - -■ - goTradeLawList + + +■ + goTradeLawList - + LayoutList - - -LayoutList + + +LayoutList - + LayoutList->LayoutList - - - + + + - - -■ - goLayoutList + + +■ + goLayoutList - + Block - - -Block + + +Block - + Block->LayoutList - - - + + + - - -■ - goLayoutList + + +■ + goLayoutList - + Block->Block - - - + + + - - -■ - doUpdateBlock + + +■ + doUpdateBlock - + Block->BlockList - - - + + + - - -■ - doDeleteBlock + + +■ + doDeleteBlock - + BlockList->Block - - - + + + - - -■ - doCreateBlock + + +■ + doCreateBlock - + BlockList->BlockList - - - + + + - - -■ - goBlockList + + +■ + goBlockList - + TradeLawList->TradeLawList - - - + + + - - -■ - goTradeLawList + + +■ + goTradeLawList - -■ - doUpdateTradeLaw + +■ + doUpdateTradeLaw - + ContentCss - - -ContentCss + + +ContentCss - + TradeLawList->ContentCss - - - + + + - - -■ - goContentCss + + +■ + goContentCss + + +OrderPdf + + +OrderPdf + + + - + AdminLogin - - -AdminLogin + + +AdminLogin - + AdminLogin->AdminTop - - - + + + - - -■ - doAdminLogin + + +■ + doAdminLogin @@ -4038,886 +4056,926 @@

EC-CUBE 4.3 アプリケーションプロファイル

AdminTop->ProductList - - + + -■ - goProductList +■ + goProductList
- + AdminTop->TagList - - - + + + - - -■ - goTagList + + +■ + goTagList - + AdminTop->ClassNameList - - - + + + - - -■ - goClassNameList + + +■ + goClassNameList - + AdminTop->ClassCategoryList - - - + + + - - -■ - goClassCategoryList + + +■ + goClassCategoryList - + AdminTop->OrderList - - - + + + - - -■ - goOrderList + + +■ + goOrderList - + AdminTop->CustomerList - - - + + + - - -■ - goCustomerList + + +■ + goCustomerList - + AdminTop->BaseInfo - - - + + + - - -■ - goBaseInfo + + +■ + goBaseInfo - + AdminTop->PaymentList - - - + + + - - -■ - goPaymentList + + +■ + goPaymentList - + AdminTop->DeliveryList - - - + + + - - -■ - goDeliveryList + + +■ + goDeliveryList - + AdminTop->TaxRuleList - - - + + + - - -■ - goTaxRuleList + + +■ + goTaxRuleList - + AdminTop->NewsList - - - + + + - - -■ - goNewsList + + +■ + goNewsList - + AdminTop->PageList - - - + + + - - -■ - goPageList + + +■ + goPageList - + AdminTop->MemberList - - - + + + - - -■ - goMemberList + + +■ + goMemberList - + AdminTop->MailTemplateList - - - + + + - - -■ - goMailTemplateList + + +■ + goMailTemplateList - + AdminTop->LoginHistoryList - - - + + + - - -■ - goLoginHistoryList + + +■ + goLoginHistoryList - + AdminTop->PluginList - - - + + + - - -■ - goPluginList + + +■ + goPluginList - + AdminTop->TemplateList - - - + + + - - -■ - goTemplateList + + +■ + goTemplateList - + AdminTop->LayoutList - - - + + + - - -■ - goLayoutList + + +■ + goLayoutList - + AdminTop->BlockList - - - + + + - - -■ - goBlockList + + +■ + goBlockList - + AdminTop->TradeLawList - - - + + + - - -■ - goTradeLawList + + +■ + goTradeLawList - + AdminTop->AdminLogin - - - + + + - - -■ - doAdminLogout + + +■ + doAdminLogout - + ContentCache - - -ContentCache + + +ContentCache - + AdminTop->ContentCache - - - + + + + + + + +■ + goContentCache - - -■ - goContentCache + + + +CustomerDeliveryEdit + + +CustomerDeliveryEdit - + Calendar - - -Calendar + + +Calendar - + Calendar->Calendar - - - + + + - - -■ - doCreateCalendarHoliday + + +■ + doCreateCalendarHoliday - -■ - doDeleteCalendarHoliday + +■ + doDeleteCalendarHoliday - -■ - doUpdateCalendar + +■ + doUpdateCalendar - -■ - goCalendar + +■ + goCalendar - + ChangePassword - - -ChangePassword + + +ChangePassword - + ContentCache->ContentCache - - - + + + - - -■ - doClearCache + + +■ + doClearCache - + ContentCss->ContentCss - - - + + + - - -■ - doUpdateContentCss + + +■ + doUpdateContentCss - + ContentJs - - -ContentJs + + +ContentJs - + ContentCss->ContentJs - - - + + + - - -■ - goContentJs + + +■ + goContentJs - + ContentJs->ContentJs - - - + + + - - -■ - doUpdateContentJs + + +■ + doUpdateContentJs - + Maintenance - - -Maintenance + + +Maintenance - + Maintenance->Maintenance - - - + + + - - -■ - doToggleMaintenance + + +■ + doToggleMaintenance - + MasterData - - -MasterData + + +MasterData - + OrderMail->MailHistory - - - + + + - - -■ - doSendOrderMail + + +■ + doSendOrderMail - + OrderMailConfirm - - -OrderMailConfirm + + +OrderMailConfirm - + OrderMail->OrderMailConfirm - - - + + + - - -■ - goOrderMailConfirm + + +■ + goOrderMailConfirm - + OrderMailConfirm->MailHistory - - - + + + - - -■ - doSendOrderMail + + +■ + doSendOrderMail - + OrderShippingAddress->Order - - - + + + - - -■ - doUpdateTrackingNumber + + +■ + doUpdateTrackingNumber - -■ - doUpdateOrderShippingAddress + +■ + doUpdateOrderShippingAddress - + OrderStatusList - - -OrderStatusList + + +OrderStatusList - + PasswordResetRequest - - -PasswordResetRequest + + +PasswordResetRequest - + PasswordResetRequestComplete - - -PasswordResetRequestComplete + + +PasswordResetRequestComplete - + Security->Security - - - + + + - - -■ - doUpdateSecurity + + +■ + doUpdateSecurity - + SystemInfo - - -SystemInfo + + +SystemInfo - + SystemInfo->AdminLogin - - - + + + + + + + +■ + doAdminLogout - - -■ - doAdminLogout + + + +Log + + +Log - + TemplateInstall->TemplateList - - - + + + - - -■ - doInstallTemplate + + +■ + doInstallTemplate - + TwoFactorAuth - - -TwoFactorAuth + + +TwoFactorAuth - + TwoFactorAuth->TwoFactorAuth - - - + + + - - -■ - doVerifyTwoFactorAuth + + +■ + doVerifyTwoFactorAuth - + TwoFactorAuthSet - - -TwoFactorAuthSet + + +TwoFactorAuthSet - + TwoFactorAuthSet->TwoFactorAuthSet - - - + + + - - -■ - doSetTwoFactorAuth + + +■ + doSetTwoFactorAuth - + doUpdateProduct - -doUpdateProduct + +doUpdateProduct doUpdateProduct->ProductList - - + + -■ - goProductList +■ + goProductList - + CartItem - -CartItem + +CartItem CartItem->Product - - + + -■ - goProduct +■ + goProduct - + UnknownState - -UnknownState + +UnknownState - + UnknownState->Top - - - + + + + + + + +■ + doLogout + + + + + + + +UnknownState->ProductClass + + + + + + + +■ + goProductClass - - -■ - doLogout + +■ + doRegisterProductClass - + UnknownState->ProductList - - - + + + - - -■ - doBulkUpdateProductStatus + + +■ + doBulkUpdateProductStatus - -■ - doImportProductCsv + +■ + doImportProductCsv - + UnknownState->ClassCategory - - - + + + - - -■ - goClassCategory + + +■ + goClassCategory - + UnknownState->ShoppingComplete - - - + + + - - + + ■ goShoppingComplete @@ -4926,1488 +4984,1554 @@

EC-CUBE 4.3 アプリケーションプロファイル

- + UnknownState->OrderList - - - + + + - - -■ - doBulkDeleteOrder + + +■ + doBulkDeleteOrder - -■ - goImportShippingCsv + +■ + goImportShippingCsv - + UnknownState->Customer - - - + + + + + + + +■ + doActivateCustomer + + + +■ + doUpdateCustomerProfile - - -■ - doActivateCustomer + +■ + doUpdateCustomerDeliveryAddress + + + +■ + doDeleteCustomerDeliveryAddress - + UnknownState->CustomerAddress - - - + + + - - -■ - goCustomerAddress + + +■ + goCustomerAddress - + UnknownState->PasswordReset - - - + + + - - -■ - doRequestPasswordReset + + +■ + doRequestPasswordReset - -■ - goPasswordReset + +■ + goPasswordReset - + UnknownState->CustomerRegistrationComplete - - - + + + - - -■ - goCustomerRegistrationComplete + + +■ + goCustomerRegistrationComplete - + UnknownState->ContactComplete - - - + + + - - -■ - goContactComplete + + +■ + goContactComplete - + UnknownState->AuthorityRole - - - + + + - - -■ - goAuthorityRole + + +■ + goAuthorityRole - + UnknownState->Csv - - - + + + - - -■ - goCsv + + +■ + goCsv - + UnknownState->Layout - - - + + + - - -■ - goLayout + + +■ + goLayout - + UnknownState->Block - - - + + + + + + + +■ + goBlock + + + + + + + +UnknownState->OrderPdf + + + - - -■ - goBlock + + +■ + goOrderPdf
- + UnknownState->AdminLogin - - - + + + - - -■ - goAdminLogin + + +■ + goAdminLogin - + UnknownState->AdminTop - - - + + + + + + + +■ + doChangePassword + + + + + + + +UnknownState->CustomerDeliveryEdit + + + - - -■ - doChangePassword + + +■ + goCustomerDeliveryEdit
- + UnknownState->ChangePassword - - - + + + - - -■ - goChangePassword + + +■ + goChangePassword - + UnknownState->MasterData - - - + + + - - -■ - doSelectMasterData + + +■ + doSelectMasterData - -■ - doUpdateMasterData + +■ + doUpdateMasterData - -■ - goMasterData + +■ + goMasterData - + UnknownState->OrderStatusList - - - + + + - - -■ - doUpdateOrderStatusList + + +■ + doUpdateOrderStatusList - -■ - goOrderStatusList + +■ + goOrderStatusList - + UnknownState->PasswordResetRequest - - - + + + - - -■ - goPasswordResetRequest + + +■ + goPasswordResetRequest - + UnknownState->PasswordResetRequestComplete - - - + + + - - -■ - goPasswordResetRequestComplete + + +■ + goPasswordResetRequestComplete + + + + + + + +UnknownState->Log + + + + + + + +■ + goLog
- + doUpdateCsv - -doUpdateCsv + +doUpdateCsv - + doUpdateCsv->ProductList - - - + + + - - -■ - goExportProduct + + +■ + goExportProduct - + goExportCategory - -goExportCategory + +goExportCategory - + goExportCategory->CategoryList - - - + + + - - -■ - doImportCategoryCsv + + +■ + doImportCategoryCsv - + goExportProduct - -goExportProduct + +goExportProduct - + goExportProduct->CategoryList - - - + + + - - -■ - goExportCategory + + +■ + goExportCategory - + AdminOrderEditPage - -AdminOrderEditPage + +AdminOrderEditPage - + AdminOrderEditPage->Order - - - + + + - - -■ - doUpdateOrder + + +■ + doUpdateOrder - -■ - doUpdateOrderStatus + +■ + doUpdateOrderStatus - -■ - doUpdateTrackingNumber + +■ + doUpdateTrackingNumber - -■ - doSendShippingNotifyMail + +■ + doSendShippingNotifyMail - + AdminOrderEditPage->OrderList - - - + + + - - -■ - goOrderList + + +■ + goOrderList - + AdminOrderEditPage->MailHistory - - - + + + - - -■ - doSendOrderMail + + +■ + doSendOrderMail - + doImportCategoryCsv - -doImportCategoryCsv + +doImportCategoryCsv - + doImportCategoryCsv->OrderList - - - + + + - - -■ - goExportOrder + + +■ + goExportOrder - + goExportOrderPdf - -goExportOrderPdf + +goExportOrderPdf - + goExportOrderPdf->OrderList - - - + + + - - -■ - goExportOrder + + +■ + goExportOrder - + doSendOrderMail - -doSendOrderMail + +doSendOrderMail - + doSendOrderMail->OrderList - - - + + + - - -■ - goExportOrder + + +■ + goExportOrder - -■ - goExportOrderPdf + +■ + goExportOrderPdf - + goExportOrder - -goExportOrder + +goExportOrder - + goExportOrder->OrderList - - - + + + - - -■ - goExportShipping + + +■ + goExportShipping - + goExportShipping - -goExportShipping + +goExportShipping - + goExportShipping->OrderList - - - + + + - - -■ - doImportShippingCsv + + +■ + doImportShippingCsv - + doUpdateOrderShippingAddress - -doUpdateOrderShippingAddress + +doUpdateOrderShippingAddress - + doUpdateOrderShippingAddress->Order - - - + + + - - -■ - doUpdateTrackingNumber + + +■ + doUpdateTrackingNumber - + doRemoveFavorite - -doRemoveFavorite + +doRemoveFavorite - + doRemoveFavorite->MypageWithdraw - - - + + + - - -■ - goMypageWithdraw + + +■ + goMypageWithdraw - + AdminCustomerEditPage - -AdminCustomerEditPage + +AdminCustomerEditPage - + AdminCustomerEditPage->Customer - - - + + + - - -■ - doCreateCustomer + + +■ + doCreateCustomer - + AdminCustomerEditPage->CustomerList - - - + + + - - -■ - goCustomerList + + +■ + goCustomerList - -■ - doDeleteCustomer + +■ + doDeleteCustomer - + doImportShippingCsv - -doImportShippingCsv + +doImportShippingCsv - + doImportShippingCsv->CustomerList - - - + + + - - -■ - goExportCustomer + + +■ + goExportCustomer - + doDeleteCustomerAddress - -doDeleteCustomerAddress + +doDeleteCustomerAddress - + doDeleteCustomerAddress->CustomerFavoriteProductList - - - + + + - - -■ - goFavoriteList + + +■ + goFavoriteList - + doAddFavorite - -doAddFavorite + +doAddFavorite - + doAddFavorite->CustomerFavoriteProductList - - - + + + - - -■ - doRemoveFavorite + + +■ + doRemoveFavorite - + doUpdateBaseInfo - -doUpdateBaseInfo + +doUpdateBaseInfo - + doUpdateBaseInfo->PaymentList - - - + + + - - -■ - goPaymentList + + +■ + goPaymentList - + doDeletePayment - -doDeletePayment + +doDeletePayment - + doDeletePayment->DeliveryList - - - + + + - - -■ - goDeliveryList + + +■ + goDeliveryList - + doDeleteDelivery - -doDeleteDelivery + +doDeleteDelivery - + doDeleteDelivery->TaxRuleList - - - + + + - - -■ - goTaxRuleList + + +■ + goTaxRuleList - + doUpdateAuthorityRole - -doUpdateAuthorityRole + +doUpdateAuthorityRole - + doUpdateAuthorityRole->LoginHistoryList - - - + + + - - -■ - goLoginHistoryList + + +■ + goLoginHistoryList - + doDeleteMailTemplate - -doDeleteMailTemplate + +doDeleteMailTemplate - + doDeleteMailTemplate->MailTemplateList - - - + + + - - -■ - goMailTemplateList + + +■ + goMailTemplateList - + doDeleteBlock - -doDeleteBlock + +doDeleteBlock - + doDeleteBlock->LayoutList - - - + + + - - -■ - goLayoutList + + +■ + goLayoutList - + doDeletePage - -doDeletePage + +doDeletePage - + doDeletePage->BlockList - - - + + + - - -■ - goBlockList + + +■ + goBlockList - + doUpdateLayout - -doUpdateLayout + +doUpdateLayout - + doUpdateLayout->TradeLawList - - - + + + - - -■ - goTradeLawList + + +■ + goTradeLawList - + doDeleteNews - -doDeleteNews + +doDeleteNews - + doDeleteNews->PageList - - - + + + - - -■ - goPageList + + +■ + goPageList - + doDeleteTemplate - -doDeleteTemplate + +doDeleteTemplate - + doDeleteTemplate->TemplateList - - - + + + - - -■ - goTemplateList + + +■ + goTemplateList - + doUpdateMailTemplate - -doUpdateMailTemplate + +doUpdateMailTemplate - + doUpdateMailTemplate->MailTemplateList - - - + + + - - -■ - doDeleteMailTemplate + + +■ + doDeleteMailTemplate - + doUpdateMailTemplate->OrderMail - - - + + + - - -■ - goOrderMail + + +■ + goOrderMail - + doDownloadTemplate - -doDownloadTemplate + +doDownloadTemplate - + doDownloadTemplate->TemplateList - - - + + + - - -■ - doDeleteTemplate + + +■ + doDeleteTemplate - + doSelectTemplate - -doSelectTemplate + +doSelectTemplate - + doSelectTemplate->TemplateList - - - + + + - - -■ - doDownloadTemplate + + +■ + doDownloadTemplate - + goExportClassCategory - -goExportClassCategory + +goExportClassCategory - + goExportClassCategory->ClassCategoryList - - - + + + - - -■ - doImportClassCategoryCsv + + +■ + doImportClassCategoryCsv - + goExportClassName - -goExportClassName + +goExportClassName - + goExportClassName->ClassNameList - - - + + + - - -■ - doImportClassNameCsv + + +■ + doImportClassNameCsv - + doInstallTemplate - -doInstallTemplate + +doInstallTemplate - + doInstallTemplate->TemplateList - - - + + + - - -■ - doSelectTemplate + + +■ + doSelectTemplate - + doAdminLogin - -doAdminLogin + +doAdminLogin - + doAdminLogin->AdminTop - - - + + + - - -■ - goAdminTop + + +■ + goAdminTop - + doDeleteTaxRule - -doDeleteTaxRule + +doDeleteTaxRule - + doDeleteTaxRule->Calendar - - - + + + - - -■ - goCalendar + + +■ + goCalendar - + doVerifyTwoFactorAuth - -doVerifyTwoFactorAuth + +doVerifyTwoFactorAuth - + doVerifyTwoFactorAuth->ContentCache - - - + + + - - -■ - goContentCache + + +■ + goContentCache - + doUpdateTradeLaw - -doUpdateTradeLaw + +doUpdateTradeLaw - + doUpdateTradeLaw->ContentCss - - - + + + - - -■ - goContentCss + + +■ + goContentCss - + doUpdateContentCss - -doUpdateContentCss + +doUpdateContentCss - + doUpdateContentCss->ContentJs - - - + + + - - -■ - goContentJs + + +■ + goContentJs - + doImportClassNameCsv - -doImportClassNameCsv + +doImportClassNameCsv - + doImportClassNameCsv->ClassCategoryList - - - + + + - - -■ - goExportClassCategory + + +■ + goExportClassCategory - + goExportCustomer - -goExportCustomer + +goExportCustomer - + goExportCustomer->ClassNameList - - - + + + - - -■ - goExportClassName + + +■ + goExportClassName - + doClearCache - -doClearCache + +doClearCache - + doClearCache->Maintenance - - - + + + - - -■ - goMaintenance + + +■ + goMaintenance - + doUpdateCustomer - -doUpdateCustomer + +doUpdateCustomer - + doUpdateCustomer->MypageChangeComplete - - - + + + - - -■ - goMypageChangeComplete + + +■ + goMypageChangeComplete - + doWithdrawCustomer - -doWithdrawCustomer + +doWithdrawCustomer - + doWithdrawCustomer->MypageWithdrawComplete - - - + + + - - -■ - goMypageWithdrawComplete + + +■ + goMypageWithdrawComplete - + doUpdateTrackingNumber - -doUpdateTrackingNumber + +doUpdateTrackingNumber - + doUpdateTrackingNumber->OrderMail - - - + + + - - -■ - goOrderMail + + +■ + goOrderMail - + goMailTemplateList - -goMailTemplateList + +goMailTemplateList - + goMailTemplateList->OrderMail - - - + + + - - -■ - goOrderMail + + +■ + goOrderMail - + doUpdateOrderStatus - -doUpdateOrderStatus + +doUpdateOrderStatus - + doUpdateOrderStatus->OrderShippingAddress - - - + + + - - -■ - goOrderShippingAddress + + +■ + goOrderShippingAddress - + doToggleMaintenance - -doToggleMaintenance + +doToggleMaintenance - + doToggleMaintenance->SystemInfo - - - + + + - - -■ - goSystemInfo + + +■ + goSystemInfo - + doSetTwoFactorAuth - -doSetTwoFactorAuth + +doSetTwoFactorAuth - + doSetTwoFactorAuth->TwoFactorAuth - - - + + + - - -■ - goTwoFactorAuth + + +■ + goTwoFactorAuth - + doUpdateSecurity - -doUpdateSecurity + +doUpdateSecurity - + doUpdateSecurity->TwoFactorAuthSet - - - + + + - - -■ - goTwoFactorAuthSet + + +■ + goTwoFactorAuthSet @@ -7240,6 +7364,13 @@

Semantic Descriptors

CustomerAddress
goFavoriteList
doCreateCustomerAddress tag:account src-template flow-customer-account-maintenance + + + CustomerDeliveryEdit + お届け先編集 + + tag:account src-template flow-manage-customer actor-admin feature-admin-customerdoc:管理画面での会員お届け先(配送先住所)編集画面。氏名・フリガナ・会社名・郵便番号・都道府県・住所・電話番号を保持し、追加・更新・削除を行う。 + CustomerFavoriteProduct @@ -7737,6 +7868,13 @@

Semantic Descriptors

goFavoriteList tag:account flow-account actor-customer src-router feature-account flow-customer-account-maintenancert:#CustomerAddressListdoc:登録済みの配送先を削除する。既存受注の配送先には影響しない。 + + + doDeleteCustomerDeliveryAddress + お届け先を削除する + + tag:account flow-manage-customer actor-admin src-router feature-admin-customerrt:#Customerdoc:会員のお届け先を1件削除する(管理画面)。 + doDeleteDelivery @@ -7898,6 +8036,13 @@

Semantic Descriptors

email
password
name01
name02 tag:account flow-register actor-customer src-router src-controller feature-register flow-customer-registrationrt:#CustomerRegistrationCompletedoc:会員メール認証オプション有効時は仮会員として登録し認証メールを送信。無効時は即座に本会員。 + + + doRegisterProductClass + 商品規格を登録する + + tag:catalog flow-manage-product actor-admin src-router feature-admin-catalog flow-admin-product-publishrt:#ProductClassdoc:商品に新しい規格(バリエーション)行を登録する(管理画面)。 + doRemoveCartItem @@ -8129,6 +8274,20 @@

Semantic Descriptors

tag:account flow-account actor-customer src-router feature-account flow-customer-account-maintenancert:#CustomerAddressdoc:登録済みの配送先(住所・氏名・連絡先)を更新する。 + + + doUpdateCustomerDeliveryAddress + お届け先を登録・更新する + + tag:account flow-manage-customer actor-admin src-router feature-admin-customerrt:#Customerdoc:会員のお届け先を追加または更新する(管理画面)。addressId が空なら新規追加、指定があれば既存行を更新。 + + + + doUpdateCustomerProfile + 会員情報を更新する + + tag:account flow-manage-customer actor-admin src-router feature-admin-customerrt:#Customerdoc:管理画面から会員の基本情報(氏名・メール・住所・生年月日・性別・職業・パスワード等)を更新する。 + doUpdateDelivery @@ -8465,6 +8624,13 @@

Semantic Descriptors

tag:account flow-account actor-customer src-router feature-account flow-customer-account-maintenancert:#CustomerAddressListdoc:会員の登録済み配送先一覧を表示する(最大20件)。追加・編集・削除の起点。 + + + goCustomerDeliveryEdit + お届け先編集を見る + + tag:account flow-manage-customer actor-admin src-router feature-admin-customerrt:#CustomerDeliveryEditdoc:会員のお届け先編集フォームを表示する(管理画面)。 + goCustomerList @@ -8626,6 +8792,13 @@

Semantic Descriptors

tag:cms flow-manage-cms actor-admin src-router feature-admin-cms flow-admin-content-publishrt:#LayoutListdoc:ページレイアウトの一覧を表示する。レイアウトは PC/SP・ヘッダー/フッター/サイドカラム等のブロック配置を定義する。 + + + goLog + ログを見る + + tag:src-router alps-route-gate flow-admin-system-operationrt:#Logdoc:モジュール固定パスのログファイル末尾を表示する(管理画面、読み取り専用)。 + goLogin @@ -8780,6 +8953,13 @@

Semantic Descriptors

tag:src-router alps-route-gate flow-admin-order-fulfillment flow-admin-mail-template-maintenancert:#OrderMailConfirmdoc:ユーザーが見る状態または行う操作をALPS上で表す。 + + + goOrderPdf + 帳票PDF出力オプションを見る + + tag:order flow-manage-order actor-admin src-router feature-admin-order flow-admin-order-fulfillmentrt:#OrderPdfdoc:納品書PDFのタイトル・挨拶文・備考・発行日を設定するオプションフォームを表示する(管理画面)。 + goOrderShippingAddress @@ -8857,6 +9037,13 @@

Semantic Descriptors

productName tag:catalog flow-browse flow-manage-product src-router feature-browse feature-admin-catalog flow-admin-product-publish flow-customer-purchasert:#Productdoc:商品詳細を表示する。価格・在庫・規格選択・関連カテゴリ・タグ・カートへ追加操作を含む。 + + + goProductClass + 商品規格編集を見る + + tag:catalog flow-manage-product actor-admin src-router feature-admin-catalog flow-admin-product-publishrt:#ProductClassdoc:商品規格(バリエーション)の登録フォームを表示する(管理画面)。 + goProductList @@ -9123,6 +9310,13 @@

Semantic Descriptors

tag:src-entitydoc:外部URLのリンク開き方(boolean)。false=同一ウィンドウ, true=新規ウィンドウ(target="_blank")。テンプレートでtarget属性の出力制御に使用 + + + Log + ログ表示 + + tag:src-template alps-route-gate flow-admin-system-operationdoc:モジュールが固定するログファイルパスから直近の行を tail 表示する読み取り専用画面(Setting/System Tier-2)。 + Login @@ -9578,6 +9772,13 @@

Semantic Descriptors

tag:src-entitydoc:管理者用の内部メモ。顧客には表示されない + + + OrderPdf + 帳票PDF出力オプション + + tag:order flow-manage-order actor-admin feature-admin-order flow-admin-order-fulfillmentdoc:納品書PDFのタイトル・挨拶文・備考・発行日を設定するオプション画面。実際のPDF生成は goExportOrderPdf が担う。 + OrderShippingAddress @@ -12094,6 +12295,12 @@

Links

"tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog", "doc": {"value": "商品マスタを複製する。基本情報・規格(ProductClass)・画像を新規 Product として複製。タイトルは「(コピー) 」プレフィクス付き。"}, "descriptor": [{"href": "#productName"}]}, + {"id": "goProductClass", "title": "商品規格編集を見る", "type": "safe", "rt": "#ProductClass", + "tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog flow-admin-product-publish", + "doc": {"value": "商品規格(バリエーション)の登録フォームを表示する(管理画面)。"}}, + {"id": "doRegisterProductClass", "title": "商品規格を登録する", "type": "unsafe", "rt": "#ProductClass", + "tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog flow-admin-product-publish", + "doc": {"value": "商品に新しい規格(バリエーション)行を登録する(管理画面)。"}}, {"id": "doBulkUpdateProductStatus", "title": "商品ステータスを一括変更する", "type": "unsafe", "rt": "#ProductList", "tag": "catalog flow-manage-product actor-admin src-router feature-admin-catalog", "doc": {"value": "選択した商品のステータス(公開・非公開・廃止)を一括変更する。"}, @@ -12259,6 +12466,11 @@

Links

{"id": "doSendShippingNotifyMail", "title": "出荷通知メールを送信する", "type": "unsafe", "rt": "#Order", "tag": "order flow-manage-order actor-admin src-router feature-admin-order flow-admin-order-fulfillment", "doc": {"value": "受注一覧画面(admin/Order/index.twig)から配送(Shipping)単位の出荷通知メールを顧客へ送信する。EC-CUBE の admin_shipping_notify_mail ルートから導出。受注メール手動送信(doSendOrderMail)とは別物で、出荷済みの配送に対する顧客通知。送信のたびにメールが発生するため unsafe。"}}, + {"id": "OrderPdf", "title": "帳票PDF出力オプション", "tag": "order flow-manage-order actor-admin feature-admin-order flow-admin-order-fulfillment", + "doc": {"value": "納品書PDFのタイトル・挨拶文・備考・発行日を設定するオプション画面。実際のPDF生成は goExportOrderPdf が担う。"}}, + {"id": "goOrderPdf", "title": "帳票PDF出力オプションを見る", "type": "safe", "rt": "#OrderPdf", + "tag": "order flow-manage-order actor-admin src-router feature-admin-order flow-admin-order-fulfillment", + "doc": {"value": "納品書PDFのタイトル・挨拶文・備考・発行日を設定するオプションフォームを表示する(管理画面)。"}}, {"id": "goExportOrderPdf", "title": "帳票PDFをエクスポートする", "type": "safe", "rt": "#OrderList", "tag": "order flow-manage-order actor-admin src-router feature-admin-order flow-admin-order-fulfillment", "doc": {"value": "選択受注の納品書・領収書PDFを出力する。テンプレートは設定で変更可能。"}, @@ -12340,6 +12552,9 @@

Links

"tag": "account flow-manage-customer src-router feature-admin-customer", "doc": {"value": "会員詳細を表示する(管理画面)。基本情報・購入履歴・お気に入り・配送先・ポイント残高を含む。"}, "descriptor": [{"href": "#email"}]}, + {"id": "doUpdateCustomerProfile", "title": "会員情報を更新する", "type": "idempotent", "rt": "#Customer", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "管理画面から会員の基本情報(氏名・メール・住所・生年月日・性別・職業・パスワード等)を更新する。"}}, {"id": "doCreateCustomer", "title": "会員を作成する", "type": "unsafe", "rt": "#Customer", "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", "doc": {"value": "管理画面から会員を新規作成する。仮会員フラグなしで即時本会員として登録。"}, @@ -12356,6 +12571,17 @@

Links

"tag": "account flow-manage-customer actor-admin src-router feature-admin-customer flow-admin-csv-exchange", "doc": {"value": "会員データをCSV形式でダウンロードする。検索条件で絞り込み可能。"}, "descriptor": [{"href": "#goExportClassName"}]}, + {"id": "CustomerDeliveryEdit", "title": "お届け先編集", "tag": "account src-template flow-manage-customer actor-admin feature-admin-customer", + "doc": {"value": "管理画面での会員お届け先(配送先住所)編集画面。氏名・フリガナ・会社名・郵便番号・都道府県・住所・電話番号を保持し、追加・更新・削除を行う。"}}, + {"id": "goCustomerDeliveryEdit", "title": "お届け先編集を見る", "type": "safe", "rt": "#CustomerDeliveryEdit", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "会員のお届け先編集フォームを表示する(管理画面)。"}}, + {"id": "doUpdateCustomerDeliveryAddress", "title": "お届け先を登録・更新する", "type": "unsafe", "rt": "#Customer", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "会員のお届け先を追加または更新する(管理画面)。addressId が空なら新規追加、指定があれば既存行を更新。"}}, + {"id": "doDeleteCustomerDeliveryAddress", "title": "お届け先を削除する", "type": "idempotent", "rt": "#Customer", + "tag": "account flow-manage-customer actor-admin src-router feature-admin-customer", + "doc": {"value": "会員のお届け先を1件削除する(管理画面)。"}}, {"id": "goCustomerAddressList", "title": "配送先一覧を見る", "type": "safe", "rt": "#CustomerAddressList", "tag": "account flow-account actor-customer src-router feature-account flow-customer-account-maintenance", @@ -12687,6 +12913,8 @@

Links

{"id": "SystemInfo", "title": "システム情報", "tag": "src-template alps-route-gate flow-admin-system-operation", "doc": {"value": "システム情報を表す画面状態。"}, "descriptor": [{"href": "#doAdminLogout"}]}, + {"id": "Log", "title": "ログ表示", "tag": "src-template alps-route-gate flow-admin-system-operation", + "doc": {"value": "モジュールが固定するログファイルパスから直近の行を tail 表示する読み取り専用画面(Setting/System Tier-2)。"}}, {"id": "TemplateInstall", "title": "テンプレート追加", "tag": "src-template alps-route-gate flow-admin-template-lifecycle", "doc": {"value": "テンプレート追加を表す画面状態。"}, "descriptor": [{"href": "#doInstallTemplate"}]}, @@ -12876,6 +13104,9 @@

Links

{"id": "goSecurity", "title": "セキュリティ設定を見る", "type": "safe", "rt": "#Security", "tag": "src-router alps-route-gate flow-admin-system-operation", "doc": {"value": "ユーザーが見る状態または行う操作をALPS上で表す。"}}, + {"id": "goLog", "title": "ログを見る", "type": "safe", "rt": "#Log", + "tag": "src-router alps-route-gate flow-admin-system-operation", + "doc": {"value": "モジュール固定パスのログファイル末尾を表示する(管理画面、読み取り専用)。"}}, {"id": "goShoppingComplete", "title": "購入完了を見る", "type": "safe", "rt": "#ShoppingComplete", "tag": "src-router alps-route-gate flow-customer-purchase", "doc": {"value": "ユーザーが見る状態または行う操作をALPS上で表す。"}}, @@ -12904,7 +13135,7 @@

Links