Skip to content

Support Class Inventory & Anti-Patterns

Reference for the *Support layer in middag-io/moodle — the static, stateless facade that sits between the boundary and native Moodle APIs, one class per Moodle subsystem.

What a *Support class is

PropertyRule
ScopeOne class per Moodle subsystem (db_support, cache_support, context_support, …)
StateNone — static, stateless methods only
LogicNo business logic — pure interface translation, never a behavior decision
Return typeTyped (?Type), converting Moodle's false/stdClass results
Dependenciesshared/-equivalent code only — the one exception is the router bridge support, which reaches the kernel router for URL generation
Admission threshold2+ real call sites in the framework consuming the same subsystem; a single-call convenience method is accepted only when no type transformation is involved

Legacy inventory — 40 support classes across 8 groups

The moodle-local_middag legacy plugin grouped its 40 support classes as follows; all were @internal, consumed only through a generated facade mirror.

GroupSupport classes
Data/Persistencedb_support, cache_support, config_support, preference_support
Auth/Authorizationauth_support, capability_support, session_support, role_support
Context/Entitiescontext_support, user_support, course_support, category_support, group_support, cohort_support, enrol_support, custom_field_support, competency_support
Content/Filesfile_support, grade_support
Presentation/UIpage_support, output_support, html_writer_support, url_support, lang_support
Communication/Eventsmessage_support, event_support, notification_support, calendar_support
Runtime/Infratask_support, plugin_support, request_support, version_support, time_support, lock_support, check_support, settings_support
Bridgedi_bridge_support, router_bridge_support

Current inventory in this adapter (middag-io/moodle)

The OSS extraction grew the inventory to 45 *Support classes under src/Support/, plus Support/Moodle — a static aggregator that returns fresh *Support instances, rather than a generated per-class facade.

The legacy facade-generation mechanism (build:facades, one mirror class per support) is not part of this OSS adapter — it is a consumer-product concern. MIDDAG product facades are generated by dev-tools inside the consumer plugin ({component}\facade\...), never inside this package. Consequence: importing Support\*Support classes directly from this package is not an anti-pattern the way it was in the legacy plugin — there is no OSS-side facade layer to bypass here. The facade-bypass anti-pattern (below) is scoped to whichever facade convention a consumer project has adopted on top of this package, not to this package's own usage.

Auth/Capability — dual consumption path

AuthSupport/CapabilitySupport-equivalent classes still follow the *Support pattern, but consumption is deliberately split by context:

PathMechanismWhen to use
DI (preferred)Security\Authentication / Security\Authorizer / Security\Capability contracts, in src/Security/Contract/Controllers, services, extensions — anywhere DI is available
Facade / direct call (fallback)Direct *Support static callProcedural contexts only: lib.php, navigation hooks, install/upgrade

Anti-patterns

Anti-patternWhy it's wrong
Direct import of a support-equivalent class from a consumer extension, bypassing that consumer's own facade conventionDefeats the indirection the consumer's facade layer exists to provide
A support class carrying business logicShould be a pure adapter — logic belongs in a service or domain layer
Calling a Moodle API ($DB, $PAGE, …) outside a *Support classBypasses the boundary whitelist entirely
Creating a support class with only 1 call siteBelow the 2+ real call-site admission threshold
Using the auth/capability facade fallback inside a controller instead of DIControllers always have DI available — no reason to fall back
A support class depending on domain/, service/, or kernel/-equivalent layersOnly shared/-equivalent code is allowed (router bridge support is the sole documented exception)

Decision record: MDL-003 — Support Layer Pattern.

MIDDAG © 2015-2026