You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add 12 Tier 2 PHPStan rules for deeper convention enforcement
Adds method-body analysis, constructor inspection, scope checking, and
cache usage rules. Total rule count is now 29. All rules pass PHPStan
level 8 self-analysis and produce no false positives against phpnomad/cli.
New rules: AdaptersMustImplement, CanSetContainerMustUseTrait,
InitializerUseHasInterfaces, ListenerNoBroadcastInHandle,
DatastoreTypeHintInterface, DatabaseScope, ControllerMustSetStatus,
TaskDispatchViaStrategy, NoCacheStrategyInBusiness,
CacheGetMustCatchException, NoHardcodedTtl, CacheKeyViaInterface.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+33-1Lines changed: 33 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
3
3
Custom [PHPStan](https://phpstan.org/) rules that enforce [PHPNomad](https://github.com/phpnomad) framework conventions.
4
4
5
-
These rules catch architectural anti-patterns at static analysis time, including models with inline serialization, service locator usage, raw SQL, singleton abuse, and missing interface implementations.
5
+
These rules catch architectural anti-patterns at static analysis time, including models with inline serialization, service locator usage, raw SQL, singleton abuse, missing interface implementations, database scope violations, cache misuse, and more.
6
6
7
7
## Installation
8
8
@@ -29,6 +29,12 @@ includes:
29
29
|`phpnomad.model.setter`| Models must not have setter methods (`set*`). Models are immutable. |
30
30
|`phpnomad.model.arrayMethod`| Models must not have `toArray()` or `fromArray()`. Use a separate adapter class. |
31
31
32
+
### Adapters
33
+
34
+
| Identifier | Description |
35
+
|---|---|
36
+
|`phpnomad.adapter.notImplementing`| Classes named `*Adapter` or in `Adapters` namespaces must implement `ModelAdapter`. Exempts `MutationAdapter` implementations. |
37
+
32
38
### Events
33
39
34
40
| Identifier | Description |
@@ -37,12 +43,20 @@ includes:
37
43
|`phpnomad.event.notFinal`| Event classes should be declared `final`. |
38
44
|`phpnomad.event.notReadonly`| Event properties and promoted constructor parameters should be `readonly`. |
39
45
|`phpnomad.listener.notImplementing`| Classes in `Listeners` namespaces or named `*Listener` must implement `CanHandle`. |
46
+
|`phpnomad.listener.broadcastInHandle`| Listeners must not call `EventStrategy::broadcast()` from within their `handle()` method. Prevents infinite loops. |
40
47
41
48
### DI / Container
42
49
43
50
| Identifier | Description |
44
51
|---|---|
45
52
|`phpnomad.di.serviceLocator`|`InstanceProvider::get()` must not be called inside business classes. Use constructor injection. Calls inside initializers and bootstrappers are allowed. |
53
+
|`phpnomad.di.missingTrait`| Classes implementing `CanSetContainer` must use the `HasSettableContainer` trait. |
54
+
55
+
### Initializers
56
+
57
+
| Identifier | Description |
58
+
|---|---|
59
+
|`phpnomad.initializer.useInterface`| Initializers should use `Has*` interfaces (e.g., `HasListeners`, `HasTaskHandlers`) instead of manually calling registration methods like `EventStrategy::attach()`. |
46
60
47
61
### Facades
48
62
@@ -56,6 +70,14 @@ includes:
56
70
| Identifier | Description |
57
71
|---|---|
58
72
|`phpnomad.database.rawSql`| Raw SQL strings (`SELECT ... FROM`, `INSERT INTO`, etc.) must not appear in code. Use PHPNomad datastore patterns. |
73
+
|`phpnomad.database.scope`|`QueryBuilder`, `ClauseBuilder`, and `QueryStrategy` must only be used inside Datastore classes. |
74
+
|`phpnomad.database.concreteTableHint`| Constructor parameters should type-hint the `Datastore` interface, not concrete `Table` subclasses. |
75
+
76
+
### Controllers
77
+
78
+
| Identifier | Description |
79
+
|---|---|
80
+
|`phpnomad.controller.noStatus`| Controller `getResponse()` must explicitly set an HTTP status code via `setStatus()` or `setError()`. |
59
81
60
82
### Console
61
83
@@ -70,6 +92,16 @@ includes:
70
92
|---|---|
71
93
|`phpnomad.task.notImplementing`| Classes in `Tasks` namespaces or named `*Task` must implement `PHPNomad\Tasks\Interfaces\Task`. |
72
94
|`phpnomad.taskHandler.notImplementing`| Task handler classes must implement `PHPNomad\Tasks\Interfaces\CanHandleTask`. |
95
+
|`phpnomad.task.directHandle`| Task handlers must be dispatched via `TaskStrategy::dispatch()`, not by calling `handle()` directly. |
96
+
97
+
### Cache
98
+
99
+
| Identifier | Description |
100
+
|---|---|
101
+
|`phpnomad.cache.directStrategy`| Business classes should not inject `CacheStrategy` directly. Use `CacheableService` or a Facade. |
102
+
|`phpnomad.cache.uncaughtException`|`CacheStrategy::get()` throws `CachedItemNotFoundException`. Ensure the call is wrapped in a try/catch. |
103
+
|`phpnomad.cache.hardcodedTtl`| Do not hardcode TTL values as integer literals. Use a `CachePolicy` or configuration constant. |
104
+
|`phpnomad.cache.stringConcatKey`| Use the `HasCacheKey` interface for cache key generation instead of string concatenation. |
0 commit comments