Context
Discussion #3323: a user followed the v3 guide Overriding Core Methods, overrode linkTo(), and called superLinkTo() — HTTP 500, because that function never exists in controller/view context.
Root cause
The super<name> convention is implemented asymmetrically:
vendor/wheels/Model.cfc → $integrateFunctions() (~line 598) — when the mixin method name already exists on the target (i.e. the app overrode it), the else branch registers the framework original as super<name>:
if (!(StructKeyExists(variables, local.name) || StructKeyExists(this, local.name))) {
variables[local.name] = local.ref;
this[local.name] = local.ref;
} else {
local.superName = "super" & local.name;
variables[local.superName] = local.ref;
this[local.superName] = local.ref;
}
vendor/wheels/Controller.cfc → $integrateFunctions() (~line 400) — no else branch. super<name> is only registered when a registered plugin/package mixin overrides the name (overrideSet). App-level overrides of controller/view helpers (defined in app/controllers/Controller.cfc or app/views/helpers.cfm) silently get nothing.
vendor/wheels/Mapper.cfc has its own $integrateFunctions() variant (~line 403) — worth checking for the same gap while in there.
Repro (verified live on develop, Lucee)
- In
app/views/helpers.cfm define an override:
public string function linkTo() {
return superLinkTo(argumentCollection = arguments);
}
- Render any view that calls
linkTo() → error, superLinkTo is undefined.
StructKeyExists(variables, "superLinkTo") in the view returns false. The equivalent model-side override does get superFindAll() etc.
Proposed fix
- Add the same
else branch to Controller.cfc::$integrateFunctions() (and Mapper.cfc if applicable) so controller/view overrides get super<name> parity with models. ~5 lines + a spec.
- Docs: the v3 guide presents the convention as general (it is model-only today), and the v4-0-0 guide tree has no "Overriding Core Methods" page at all — port + correct it once the parity fix lands.
Workaround for users today
Capture the original reference manually (late-binding — same trick $integrateFunctions itself uses); posted in #3323:
variables.coreLinkTo = CreateObject("component", "wheels.view.links").linkTo;
Context
Discussion #3323: a user followed the v3 guide Overriding Core Methods, overrode
linkTo(), and calledsuperLinkTo()— HTTP 500, because that function never exists in controller/view context.Root cause
The
super<name>convention is implemented asymmetrically:vendor/wheels/Model.cfc→$integrateFunctions()(~line 598) — when the mixin method name already exists on the target (i.e. the app overrode it), theelsebranch registers the framework original assuper<name>:if (!(StructKeyExists(variables, local.name) || StructKeyExists(this, local.name))) { variables[local.name] = local.ref; this[local.name] = local.ref; } else { local.superName = "super" & local.name; variables[local.superName] = local.ref; this[local.superName] = local.ref; }vendor/wheels/Controller.cfc→$integrateFunctions()(~line 400) — noelsebranch.super<name>is only registered when a registered plugin/package mixin overrides the name (overrideSet). App-level overrides of controller/view helpers (defined inapp/controllers/Controller.cfcorapp/views/helpers.cfm) silently get nothing.vendor/wheels/Mapper.cfchas its own$integrateFunctions()variant (~line 403) — worth checking for the same gap while in there.Repro (verified live on develop, Lucee)
app/views/helpers.cfmdefine an override:public string function linkTo() { return superLinkTo(argumentCollection = arguments); }linkTo()→ error,superLinkTois undefined.StructKeyExists(variables, "superLinkTo")in the view returnsfalse. The equivalent model-side override does getsuperFindAll()etc.Proposed fix
elsebranch toController.cfc::$integrateFunctions()(andMapper.cfcif applicable) so controller/view overrides getsuper<name>parity with models. ~5 lines + a spec.Workaround for users today
Capture the original reference manually (late-binding — same trick
$integrateFunctionsitself uses); posted in #3323:variables.coreLinkTo = CreateObject("component", "wheels.view.links").linkTo;