Skip to content

TriadViewResolver

Shared Action -> View -> Template resolution for the triad convention (Actions/{Action}Action.php <-> Views/{Action}{ViewName}View.php <-> Templates/{Action}{ViewName}.php), used by both TriadDiagnosticsScanner (which only needs existence) and Quiote\Introspection\AppIntrospectionCompiler (which needs the resolved file paths for the introspection artifact), so the naming convention is decoded in exactly one place.

final class TriadViewResolver

Since1.0.0
SourceRouting/Compiler/TriadViewResolver.php
MethodDescription
actionExecuteMethodsFor(ReflectionClass<TAction> $action): list<ReflectionMethod>The execute*() methods an action can be dispatched to — execute() plus the execute{Method}() variants ActionResolver looks for.
alwaysReturnsContent(ReflectionMethod $method): boolWhether this execute*() method’s declared return type guarantees it always returns a non-null value on every path — per ActionExecutor::renderView(), a non-null return becomes the response body directly and the template/layer path (View::renderLayers()) is never reached, regardless of what the method body does internally (e.g.
canonicalViewToken(ModuleActionEntry $entry, string $viewToken): stringThe canonical form of a view token for the given module/action pair.
declaresNoTemplate(ReflectionMethod $method): boolWhether this specific execute*() method opts out of the MISSING_TEMPLATE check via @quiote-viewmethod-has-no-template in its own docblock (inherited from whichever class actually declares it, same as ordinary method resolution).
executeMethodsFor(ReflectionClass<object> $view): list<ReflectionMethod>The execute()/execute{OutputType}() methods a view class declares (own or inherited from an app-level base view), one per output type it handles — mirrors ActionExecutor’s own `‘execute’ .
legacyViewFileFor(ModuleActionEntry $entry, string $canonicalViewToken): stringThe file path of the non-class view for a module/view token pair.
literalReturnViewTokens(ReflectionClass<object> $action): list<string>Every view token an action’s execute*() methods return as a bare string literal, in declaration order and de-duplicated.
outputTypeNameFor(ReflectionMethod $method): ?stringThe output type name an execute*() method is resolved for, or null for the bare execute() method, which stands in for whichever output type is otherwise in effect (the app’s configured default, absent further context).
resolveExistingViewFile(ModuleActionEntry $entry, string $canonicalViewToken, string $namespacePrefix): ?stringExisting view class name, or the legacy view file path if only that exists, or null if neither does.
resolveViewToken(ReflectionClass<object> $reflection): ?stringThe view an action declares as its default, for triad/diagnostic purposes — deliberately narrower than “whatever getDefaultViewName() * returns”.
templateExtensionFor(ReflectionMethod $method, ?Controller $controller): stringThe template file extension (leading dot included) that a given execute*() method’s output type renders with, resolved from the app’s real, already-initialized output type/renderer configuration when available.
templateFileFor(ModuleActionEntry $entry, string $canonicalViewToken, string $extension = '.php'): stringThe template file path a canonical view token renders from.
viewClassFor(ModuleActionEntry $entry, string $canonicalViewToken, string $namespacePrefix): stringThe fully qualified view class name the triad convention expects.

public function actionExecuteMethodsFor(ReflectionClass<TAction> $action): list<ReflectionMethod>

The execute*() methods an action can be dispatched to — execute() plus the execute{Method}() variants ActionResolver looks for.

ParameterTypeDescription
$actionReflectionClass``<``TAction``>

Returns list``<``ReflectionMethod``>

public function alwaysReturnsContent(ReflectionMethod $method): bool

Whether this execute*() method’s declared return type guarantees it always returns a non-null value on every path — per ActionExecutor::renderView(), a non-null return becomes the response body directly and the template/layer path (View::renderLayers()) is never reached, regardless of what the method body does internally (e.g.

setupHtml()/loadLayout() calls in a shared base class this scanner has no visibility into). Deliberately conservative: no declared return type, a nullable type, void, or mixed all count as “can’t prove it”, so the caller falls back to TriadViewResolver::declaresNoTemplate() instead of guessing wrong in the direction that would hide a real missing template.

ParameterTypeDescription
$methodReflectionMethod

Returns bool

public function canonicalViewToken(ModuleActionEntry $entry, string $viewToken): string

The canonical form of a view token for the given module/action pair.

Runs the token through the module’s quiote.view.name directive so an app can rewrite view names per module, keeping the raw token when that directive evaluates to an empty string, then canonicalises the result via Toolkit::canonicalName(). The result is what the class, view file and template lookups below all key off, so they stay consistent.

ParameterTypeDescription
$entryModuleActionEntry
$viewTokenstring

Returns string

public function declaresNoTemplate(ReflectionMethod $method): bool

Whether this specific execute*() method opts out of the MISSING_TEMPLATE check via @quiote-viewmethod-has-no-template in its own docblock (inherited from whichever class actually declares it, same as ordinary method resolution).

Intended for a method whose output type returns content directly (e.g. executeJson() returning json_encode(...)) and therefore never renders a template by design — TriadDiagnosticsScanner has no way to see that statically, so it would otherwise always false-flag a template that will never exist. Scoped per method, not per class, since one view can freely mix template-backed and template-less execute*() methods.

Most methods that return content directly don’t need this at all — TriadViewResolver::alwaysReturnsContent() detects the common case (a declared, non-nullable return type) automatically. This annotation is the fallback for whatever that can’t prove statically, e.g. an untyped or nullable return.

ParameterTypeDescription
$methodReflectionMethod

Returns bool

public function executeMethodsFor(ReflectionClass<object> $view): list<ReflectionMethod>

The execute()/execute{OutputType}() methods a view class declares (own or inherited from an app-level base view), one per output type it handles — mirrors ActionExecutor’s own `‘execute’ .

ParameterTypeDescription
$viewReflectionClass``<``object``>

Returns list``<``ReflectionMethod``>

public function legacyViewFileFor(ModuleActionEntry $entry, string $canonicalViewToken): string

The file path of the non-class view for a module/view token pair.

Resolved from the module’s quiote.view.path directive. The path is returned whether or not a file exists there; TriadViewResolver::resolveExistingViewFile() is the variant that checks.

ParameterTypeDescription
$entryModuleActionEntry
$canonicalViewTokenstring

Returns string

public function literalReturnViewTokens(ReflectionClass<object> $action): list<string>

Every view token an action’s execute*() methods return as a bare string literal, in declaration order and de-duplicated.

ParameterTypeDescription
$actionReflectionClass``<``object``>

Returns list``<``string``>

public function outputTypeNameFor(ReflectionMethod $method): ?string

The output type name an execute*() method is resolved for, or null for the bare execute() method, which stands in for whichever output type is otherwise in effect (the app’s configured default, absent further context).

ParameterTypeDescription
$methodReflectionMethod

Returns ?``string

public function resolveExistingViewFile(ModuleActionEntry $entry, string $canonicalViewToken, string $namespacePrefix): ?string

Existing view class name, or the legacy view file path if only that exists, or null if neither does.

ParameterTypeDescription
$entryModuleActionEntry
$canonicalViewTokenstring
$namespacePrefixstring

Returns ?``string

public function resolveViewToken(ReflectionClass<object> $reflection): ?string

The view an action declares as its default, for triad/diagnostic purposes — deliberately narrower than “whatever getDefaultViewName() * returns”.

ParameterTypeDescription
$reflectionReflectionClass``<``object``>

Returns ?``string

public function templateExtensionFor(ReflectionMethod $method, ?Controller $controller): string

The template file extension (leading dot included) that a given execute*() method’s output type renders with, resolved from the app’s real, already-initialized output type/renderer configuration when available.

Falls back to the PHP-renderer convention (.php) when no Controller is supplied, or the output type/renderer can’t be resolved (e.g. a name with no configured output type) — the same default this check used before per-output-type extensions existed.

ParameterTypeDescription
$methodReflectionMethod
$controller?Controller

Returns string

public function templateFileFor(ModuleActionEntry $entry, string $canonicalViewToken, string $extension = '.php'): string

The template file path a canonical view token renders from.

Takes the module’s quiote.template.directory directive, strips any trailing slash from it and appends the view token plus $extension (leading dot included; TriadViewResolver::templateExtensionFor() supplies the output-type-specific one). Existence is not checked.

ParameterTypeDescription
$entryModuleActionEntry
$canonicalViewTokenstring
$extensionstring

Returns string

public function viewClassFor(ModuleActionEntry $entry, string $canonicalViewToken, string $namespacePrefix): string

The fully qualified view class name the triad convention expects.

Composes {$namespacePrefix}\Modules\{module}\Views\{token}View, with any / in the canonical token turned into a namespace separator so a nested view token maps onto a sub-namespace. Purely a name computation: the class is not required to exist.

ParameterTypeDescription
$entryModuleActionEntry
$canonicalViewTokenstring
$namespacePrefixstring

Returns string