Skip to content

Use StructArmed on QA - #228

Open
samsonasik wants to merge 1 commit into
php-db:0.6.xfrom
samsonasik:use-structarmed-on-qa
Open

samsonasik wants to merge 1 commit into
php-db:0.6.xfrom
samsonasik:use-structarmed-on-qa

Conversation

@samsonasik

Copy link
Copy Markdown
Contributor

Types of changes

  • QA improvement (unit/integration tests, CS fixes, etc.) that does not change code behavior

Checklist:

  • All new and existing tests passed.
  • This pull request targets the correct branch.

Description

Hi, this PR add StructArmed to QA

https://github.com/boundwize/structarmed

It is a configurable PHP architecture guards with built in presets (psr4, mvc, and so on).

It already used by PHP frameworks:

Project Configuration
CakePHP https://github.com/cakephp/cakephp/blob/5.x/structarmed.php
CodeIgniter 4 https://github.com/codeigniter4/CodeIgniter4/blob/develop/structarmed.php
Spiral Framework https://github.com/spiral/framework/blob/master/structarmed.php
Mezzio Framework https://github.com/mezzio/mezzio/blob/3.29.x/structarmed.php

This PR apply StructArmed with register:

  • PSR4, CodeQuality preset and already help fixes 1 violations to fix registered namespace -> path in composer.json that never exists in the disk.

Applied with single command:

vendor/bin/structarmed analyze --fix
  • I also enable ruleset so it show more ability of layering setup to define which layers each layer is allowed to depend on.

  • Register to github workflow.

Motivation and Context

phpdb already enforces formatting, linting, static analysis, and mutation score, but nothing enforces the layering between Adapter, Sql, ResultSet, Metadata, and the gateways. Today a use PhpDb\Adapter\... added to a predicate or a DDL column would pass every existing check. StructArmed makes that layering an executable rule: changing the architecture on purpose becomes a one-line diff in structarmed.php reviewed in the same PR, while changing it by accident fails CI with a message naming the class, the dependency, and both layers.

The PSR4 preset already paid for itself once: it caught the stale PhpDbBenchmark\ mapping in composer.json pointing at a test/benchmark/ directory that does not exist and a namespace nothing references.

How the layers and ruleset are set up:

  • Every directory under src/ is its own layer via layer(), plus ConfigProvider.php on its own (34 layers in total). Where a directory contains sub-directories that are layers themselves, the parent uses the third exclude argument so each class belongs to exactly one layer, for example Sql excludes Argument, Ddl, Exception, Platform, and Predicate.
  • The ruleset uses +Layer wherever a layer builds on another, so it inherits the base layer's allowed dependencies and the lists stay short, for example 'SqlPredicate' => ['+SqlArgument', '+SqlPredicateException'].
  • The ruleset describes the code as it is today, not an aspirational design. Existing cycles such as Adapter ↔ Adapter\Driver ↔ ResultSet and Sql ↔ Sql\Argument / Sql\Platform / Sql\Predicate are allowed as-is but are now explicit and visible in one file.

Some of what it guarantees going forward:

  • All *\Exception namespaces and Metadata\Object stay leaf layers.
  • Sql\Argument, Sql\Predicate, and Sql\Ddl\* stay pure SQL abstraction and cannot reach Adapter, ResultSet, or the gateways.
  • ResultSet only knows Adapter\Driver; Metadata only reaches Adapter.
  • Container and ConfigProvider are the only layers allowed to see the whole wiring.

How has this been tested?

  • vendor/bin/structarmed analyse on this branch reports No violations found. (StructArmed 0.18.11, PHP 8.3).
  • The ruleset was derived from the real dependency graph: running with every layer allowed to depend on nothing reports 944 violations, those were collapsed into layer-to-layer edges, and the ruleset covers exactly that graph. A check of the expanded + references confirms the only over-allowance is the base Exception layer for layers that use their own *Exception sub-layer, plus three small ones (AdapterDriver → AdapterException, SqlDdlIndex → SqlException, RowGatewayFeature → Adapter).
  • composer test passes: OK (2089 tests, 4038 assertions).
  • The new qa-structarmed job runs on this PR in the existing continuous-integration.yml workflow.

Screenshots (if appropriate):

Screenshot 2026-10-07 at 15 36 42

Please let me know if this need simplification, reduce config, or split into multiple PRs.

Signed-off-by: Abdul Malik Ikhsan <samsonasik@gmail.com>
@codecov

codecov Bot commented Oct 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@samsonasik

Copy link
Copy Markdown
Contributor Author

Ready for review 👍

@tyrsson

tyrsson commented Oct 7, 2026

Copy link
Copy Markdown
Member

Hey @samsonasik thanks for the PR and the consideration!! It may take a couple days for us to make a decision on this. We need that time to take a look at what StructArmed provides beyond what Mago Guard will provide.

@samsonasik

Copy link
Copy Markdown
Contributor Author

@tyrsson that's fine 👍 , for additional information, StructArmed can do guard + more additional features to support it, like finalize classes, clean up unused class/functions, etc), also, it is already very fast, here StructArmed speed, in action, analyze 2215 files only in 0.6 seconds :)

structarmed-speed-in-action.mov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants