Qualify every reference to a FOG core class - #28
Merged
Conversation
Plugins are global-namespace by design (fogproject ADR 0009) and have always
named core classes bare -- `extends Hook`, `Route::listem()`, `new Image()`.
That works only because every file under fogproject's packages/web/src/ ends
in a class_alias() re-exporting itself into the global namespace, and that
alias set is being retired (fogproject ADR 0013 §2, docs/composer-psr4-plan.md).
A bare name resolves to nothing once it goes.
574 references across 163 files now carry their namespace. The plugins stay
global -- only the names they reach into core with have changed.
ADR 0009 requires this to ship BEFORE the core change that deletes the
aliases: downloadplugins() runs before configureHttpd(), so a server is
never serving a core without aliases against plugins that still need them.
bin/qualify-core-references.php does the rewrite. It reads the map from a
fogproject checkout rather than carrying a copy, because which bucket a class
lives in is fogproject's to decide and a stale list here would rewrite names
to somewhere they are not. Tokenised, never regex, so a name in a docblock or
a string is left alone and `$obj->Route` is not mistaken for a class.
Three sources feed that map, and the first cut used only the first:
src/ PSR-4, so the path is the name
lib/ the 46 discovery-named classes, flat FOG namespace -- eight
plugin reports extend FOG\ReportManagement
commons/ Initiator, genuinely global and staying that way; qualifying it
is just a leading backslash
Two rounds of the sweep were wrong before this was right, and the gates
caught both rather than review doing it:
- The tool built its "classes this tree declares" set from the whole tree,
including tests/stubs, which declares doubles NAMED FOGController,
FOGManagerController and Schema. Every reference to those three therefore
looked like a plugin's own class and was skipped -- 313 rewritten, ~90
silently left. The strict stubs failed the suite immediately.
- Initiator and ReportManagement are not under src/ at all, so the src-only
map could not see them. The self-contained test found all 18.
tests/stubs/fog-stubs.php now declares its doubles in the namespaces core
declares them in, and deliberately NOT also under their bare global names.
That is what makes the plugin tests a gate for this: a file still saying
`extends FOGController` fails to load exactly as it would on a real server.
The stub's own `Schema::createTable()` needed qualifying too -- it sits in
FOG\Base and Schema is in FOG\Items.
tests/core-references-are-qualified.test.php is the standing gate, and it
carries no copy of core's class list: the invariant is that a name this tree
does not declare and PHP does not have must be qualified. That needs no
fogproject checkout, which matters because CI has none. Mutation-confirmed --
reverting one `extends \FOG\Base\Hook` names that file and line. It handles
both tokenizer shapes, since PHP 8 folds a qualified name into one
T_NAME_FULLY_QUALIFIED token and 7.4 does not, and CI runs both.
Suite: 10 passed, 0 failed.
Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 3 of fogproject's alias retirement (
docs/composer-psr4-plan.md:815). This must ship before the core change that deletes the aliases — ADR 0009's ordering:downloadplugins()runs beforeconfigureHttpd(), so a server is never serving a core without aliases against plugins that still need them.Why
Plugins are global-namespace by design (ADR 0009) and have always named core classes bare —
extends Hook,Route::listem(),new Image(). That works only because every file under fogproject'spackages/web/src/ends in aclass_alias()re-exporting itself globally. Once those go, a bare name resolves to nothing and the failure is a fatal on the page or hook that uses it.574 references across 163 files now carry their namespace. The plugins stay global — only the names they reach into core with have changed.
The map has three sources, and the first cut used one
src/\FOG\Base\Hooklib/FOGnamespace\FOG\ReportManagement— 8 plugin reports extend itcommons/Initiator, genuinely global and staying that way\Initiator— just a leading backslashTwo rounds were wrong before this was right — and the gates caught both
The tool skipped ~90 references silently. It built its "classes this tree declares" set from the whole tree including
tests/stubs, which declares doubles namedFOGController,FOGManagerControllerandSchema. Every reference to those three therefore looked like a plugin's own class. 313 rewritten, ~90 left behind. The strict stubs failed the suite immediately withClass "FOGController" not found.InitiatorandReportManagementwere invisible to a src-only map. Neither lives undersrc/. The self-contained test found all 18.Neither was caught by reading the diff.
What makes the tests a real gate
tests/stubs/fog-stubs.phpnow declares its doubles in the namespaces core declares them in —FOG\Base\FOGController,FOG\Base\FOGManagerController,FOG\Items\Schema— and deliberately not also under their bare global names. A plugin file still sayingextends FOGControllerresolves nothing and fails to load, exactly as it would on a real server. Adding a global alias back would make the stubs kinder than production and the suite would go green on code that cannot run.The stub's own
Schema::createTable()needed qualifying too — it sits inFOG\BaseandSchemais inFOG\Items, so the bare name resolved toFOG\Base\Schema. Same bug class that white-screened fogproject's UI last week.The standing gate
tests/core-references-are-qualified.test.phpcarries no copy of core's class list. The invariant is self-contained: a name this tree does not declare, and that PHP does not have, must be qualified. That needs no fogproject checkout — which matters, because CI has none.extends \FOG\Base\Hookfails naming that file and line.T_NAME_FULLY_QUALIFIEDtoken, 7.4 emitsT_NS_SEPARATOR+T_STRINGper segment, and CI runs both.574 qualified reference(s), 70 bare one(s) checked— the 70 being the plugins' own classes and PHP built-ins.Verification
Suite: 10 passed, 0 failed (9 existing + the new gate).
Full end-to-end proof — every plugin class loading against a core with the aliases actually deleted — lands with the fogproject PR, because core's own 46
lib/files have the same bare-name problem and are fixed there. Confirmed in a shadow tree: with plugin-referenced aliases stripped, the first failure iscore'slib/hooks/bootitem.hook.php, not a plugin.