PHPArkitect architectural rules and custom expressions for the Valkyrja project.
| Linting |
|
|
| Coding Rules |
|
|
| Static Analysis |
|
|
| Testing |
|
This repository contains two things:
-
Valkyrja\Arkitect\Rules— a reusable rule set that encodes the naming and namespace conventions used across the Valkyrja project. Drop it into any PHPArkitect config to enforce those conventions on your own code. -
Custom expressions — PHPArkitect
Expressionimplementations that fill gaps in the built-in expression library.
composer require valkyrja/phparkitectReference Rules::getRules() from your phparkitect.php configuration file:
// phparkitect.php
use Valkyrja\Arkitect\Rules;
return Rules::getRules();getRules() returns a closure that receives a PHPArkitect Config object and
registers all rules against two class sets:
src/— source rules (naming, namespaces, architectural constraints)tests/— test rules (finality, naming conventions for test helpers)
The paths are resolved relative to the directory three levels above
src/Arkitect/Rules.php (i.e. the project root), matching the standard
Valkyrja monorepo layout.
Run PHPArkitect as normal:
vendor/bin/phparkitect checkAll classes must not contain an @author docblock annotation.
| Rule | Constraint |
|---|---|
Classes with #[Attribute] must reside in *Attribute\ namespaces |
Attributes belong in dedicated namespaces |
Classes in *Attribute\ namespaces must carry #[Attribute] |
Only attributes live in attribute namespaces |
Classes outside *Attribute\* must not carry #[Attribute] |
Non-attributes must not be attributed |
| Rule | Constraint |
|---|---|
Final classes (excluding *Security and *Provider) must reside in *Constant\ |
Constants namespace |
Classes in *Constant\ must be final |
Constants are sealed |
| Type | Naming | Namespace |
|---|---|---|
ServiceProviderContract |
*ServiceProvider |
*Provider\ |
ComponentProviderContract |
*ComponentProvider |
*Provider\ |
CliRouteProviderContract |
*RouteProvider |
*Provider\ |
ListenerProviderContract |
*ListenerProvider |
*Provider\ |
HttpRouteProviderContract |
*RouteProvider |
*Provider\ |
All classes in *Provider\ |
*Provider suffix |
— |
| Rule | Constraint |
|---|---|
Classes named *Factory must reside in *Factory\ |
Factories belong in factory namespaces |
Classes in *Factory\ must be named *Factory |
Only factories live in factory namespaces |
Classes named *Command (outside Valkyrja\Cli\*, and not *Handler or
*Middleware) must reside in *Cli\Command\ namespaces.
Classes named *Security must reside in *Security\ namespaces and must be
final.
| Rule | Constraint |
|---|---|
Classes named *Exception must reside in *Exception\ |
Exceptions namespace |
Classes extending Throwable must reside in *Throwable\ |
Throwable objects belong in throwable namespaces |
Classes implementing Throwable must be named *Exception |
Throwables are exceptions |
Classes named *RuntimeException must reside in *Abstract\ and be abstract |
Base runtime exceptions are abstract |
Classes named *InvalidArgumentException must reside in *Abstract\ and be abstract |
Base invalid argument exceptions are abstract |
| Rule | Constraint |
|---|---|
Classes extending Type (outside Config, Entity, Model namespaces) must reside in *Type\ |
Types namespace |
Classes extending Model (outside Config, Entity namespaces) must reside in *Model\ |
Models namespace |
Classes extending Entity must reside in *Entity\ |
Entities namespace |
| Rule | Constraint |
|---|---|
Interfaces must reside in *Contract\ namespaces |
Contracts namespace |
Classes in *Contract\ must be interfaces |
Only interfaces are contracts |
Interfaces (except *Throwable) must be named *Contract |
Contract naming convention |
Classes named *Contract must be interfaces |
Naming implies interface |
| Rule | Constraint |
|---|---|
Traits must reside in *Trait\ namespaces |
Traits namespace |
Classes in *Trait\ must be traits |
Only traits live in trait namespaces |
Traits must not be named *Trait* |
No "Trait" in the name |
All classes must not be named *Trait* |
No "Trait" in any name |
| Rule | Constraint |
|---|---|
Abstract classes (outside *Factory and specific routing controller namespaces) must reside in *Abstract\ |
Abstract namespace |
Classes in *Abstract\ must be abstract |
Only abstract classes live there |
Abstract classes must not be named *Abstract* |
No "Abstract" in the name |
Non-abstract classes must not be named *Abstract* |
No "Abstract" in any name |
| Rule | Constraint |
|---|---|
Enums must reside in *Enum\ namespaces |
Enums namespace |
Classes in *Enum\ (outside Valkyrja\Type\Enum) must be enums |
Only enums live in enum namespaces |
Enums must not be named *Enum* |
No "Enum" in enum names |
Non-enums (outside Valkyrja\Type\Enum, excluding EnhancedEnumSupport) must not be named *Enum* |
No "Enum" in non-enum names |
| Rule | Constraint |
|---|---|
All classes must not contain @author docblocks |
Same as src |
Test classes (in *Tests\, not *TestCase, *AttributeClass, *EnvClass, non-abstract, non-trait, outside Vendor) must be final |
Tests are sealed |
Classes in *Classes\ (non-enum, non-trait) must be named *Class |
Test helper class naming |
Classes in *Classes\ must not be named *Test |
Test helpers are not tests |
Classes not named *Test must not reside in *Unit\ or *Functional\ |
Only tests live in test namespaces |
Traits (not TestCase) in tests must reside in *Trait\ and be named *Trait |
Test trait conventions |
Valkyrja\Arkitect\Expression\ForClasses\NotHaveAttribute
The inverse of PHPArkitect's built-in HaveAttribute. Evaluates to a violation
when the target class does carry the specified PHP attribute.
use Valkyrja\Arkitect\Expression\ForClasses\NotHaveAttribute;
Rule::allClasses()
->that(new NotResideInTheseNamespaces('*Attribute\\*'))
->should(new NotHaveAttribute(Attribute::class))
->because('Non-attribute classes must not carry #[Attribute]');Constructor:
new NotHaveAttribute(string $attribute)| Parameter | Description |
|---|---|
$attribute |
Fully qualified class name of the PHP attribute to check |
Violation message format:
<FQCN> should not have the attribute <attribute> because <reason>
The _workflow-call.yml reusable
workflow runs PHPArkitect against the calling repository's source. It is
designed to be called from other repositories via workflow_call.
| Input | Type | Default | Description |
|---|---|---|---|
paths |
string | — | Required. YAML filter spec with two keys: ci (CI config files that trigger a base-branch fetch) and files (all files that trigger the check). |
post-pr-comment |
boolean | true |
Post a PR comment on failure and remove it on success. Disable when the calling workflow handles its own reporting. |
composer-options |
string | '' |
Extra flags passed to every composer install step (e.g. --ignore-platform-req=ext-openswoole). |
php-version |
string | '8.4' |
PHP version to use. |
ci-directory |
string | '.github/ci/phparkitect' |
Path to the CI directory containing composer.json and the tool config. |
extensions |
string | 'mbstring, intl' |
PHP extensions to install via shivammathur/setup-php. |
jobs:
phparkitect:
uses: valkyrjaio/phparkitect/.github/workflows/_workflow-call.yml@26.x
permissions:
pull-requests: write
contents: read
with:
php-version: '8.4'
paths: |
ci:
- '.github/ci/phparkitect/**'
- '.github/workflows/phparkitect.yml'
files:
- '.github/ci/phparkitect/**'
- '.github/workflows/phparkitect.yml'
- 'src/**/*.php'
- 'composer.json'
secrets: inheritsecrets: inherit is required to pass the VALKYRJA_GHA_APP_ID and
VALKYRJA_GHA_PRIVATE_KEY org secrets used for PR comments.
