Skip to content

TriadDiagnosticsScanner

Diagnoses the Action/View/Template triad convention (Actions/{Action}Action.php <-> Views/{Action}{ViewName}View.php <-> Templates/{Action}{ViewName}.php) for every action ModuleActionDiscovery finds, independent of whether the action is ever actually routed to.

Three checks, each only attempted once the prior one succeeds (a missing action class means there is nothing to reflect a view name from, etc.):

  • MISSING_ACTION_CLASS: the Actions/*Action.php file does not define the class its own path/namespace convention implies. - MISSING_VIEW: getDefaultViewName() names a view with no matching {Action}{ViewName}View class and no legacy view file on disk. - MISSING_TEMPLATE: the view exists, but at least one of its execute()/execute{OutputType}() methods (per TriadViewResolver::executeMethodsFor()) has no matching template file for the extension its output type renders with (per TriadViewResolver::templateExtensionFor() — the app’s real renderer configuration when a Controller is supplied, .php otherwise). Convention-only, not a bug: it can only false-flag as missing, never hide a real gap, so it stays a warning. A method whose declared return type proves it always returns non-null content is skipped automatically (TriadViewResolver::alwaysReturnsContent() — per ActionExecutor::renderView(), a non-null return is the response body and the template/layer path is never reached, however the method body itself got there, e.g. via a shared base class’s setupHtml()/loadLayout()). Whatever that can’t prove (untyped or nullable return, mixed, void) falls back to an explicit opt-out via @quiote-viewmethod-has-no-template in the method’s own docblock — TriadViewResolver::declaresNoTemplate().

getDefaultViewName() is read via newInstanceWithoutConstructor() (TriadViewResolver) so no constructor/DI side effects run; an action whose base classes make even this unsafe (an uncatchable fatal, not a Throwable) is simply the one gap this scanner cannot see — no diagnostic is produced for that action, but no false one either.

final class TriadDiagnosticsScanner

Since1.0.0
SourceRouting/Compiler/TriadDiagnosticsScanner.php

public function __construct(TriadViewResolver $views = new TriadViewResolver(…), ?Controller $controller = null): mixed

ParameterTypeDescription
$viewsTriadViewResolver
$controller?Controller

Returns mixed

MethodDescription
scan(list<ModuleActionEntry> $entries): list<Diagnostic>

public function scan(list<ModuleActionEntry> $entries): list<Diagnostic>

ParameterTypeDescription
$entrieslist``<ModuleActionEntry>

Returns list``<Diagnostic>