Skip to content

Static bootloader + Services locator (drop the DI container) - #11

Merged
akshat009 merged 2 commits into
mainfrom
feat/static-bootloader-services
Aug 29, 2026
Merged

Static bootloader + Services locator (drop the DI container)#11
akshat009 merged 2 commits into
mainfrom
feat/static-bootloader-services

Conversation

@akshat009

Copy link
Copy Markdown
Owner

Replaces the DI-container architecture with a lighter static bootloader, per request.

Before / after

Was Now
Plugin create() builds a Container + provider list; boot() loops register() then boot() singleton Plugin::instance()->boot() — news up each module, calls init_hooks(); idempotent
Module class implements Service_Provider [, Conditional], register() + boot() plain class, one init_hooks(): void
Shared services $container->get(X::class) + per-provider factory closures Services::x() — static, memoised, one instance per accessor
Woo conditional load each provider implements Conditional / is_needed() one if ( class_exists( 'WooCommerce' ) ) block in boot()
Deleted Core/Container, Core/Exceptions/Not_Found_Exception, Contracts/Service_Provider, Contracts/Conditional, Container_Test

Activator/Deactivator keep the Activatable/Deactivatable contract but drop the Container argument and ( new X() )->method() directly. Main file calls Plugin::instance()->boot() on plugins_loaded.

Tests

  • Container_Test removed; new Services_Test covers set()/reset().
  • Example_Test / Plugin_Boot_Test now assert the singleton identity + idempotent boot() (no double hook registration).
  • Every module unit test switched from ->boot(new Container()) to ->init_hooks().

Verification

67 generator + 13 engine tests green. Full all-modules scaffold: php -l clean on every PHP file, no leftover Container/Service_Provider references, no stray template tokens. composer lint (wp-org + vip + both) and composer test on the new shape run in CI here.

BREAKING: the generated plugin's architecture changes.

- Plugin is a singleton bootloader: Plugin::instance()->boot() news up
  every selected module and calls its init_hooks(); boot() is idempotent.
  No constructor, no provider list, no register()/boot() two-phase.
- Services is a static locator — Services::cache(), Services::settings_repository(),
  etc. build one memoised instance per accessor, with set()/reset() test seams.
  Only emitted for module sets that need a shared service.
- Every module class loses `implements Service_Provider` / `Conditional` and
  merges register()+boot() into one init_hooks(): void. Dependencies are
  constructor-injected from Services at the bootloader call site.
- WooCommerce modules go inside one `if ( class_exists( 'WooCommerce' ) )`
  guard in boot() instead of each provider implementing Conditional.
- Deleted: Core/Container, Core/Exceptions/Not_Found_Exception,
  Contracts/Service_Provider, Contracts/Conditional, tests/Unit/Container_Test.
  Activatable/Deactivatable keep their contract but lose the Container arg.
- Activator/Deactivator run `( new X() )->method()` directly; the main file
  calls Plugin::instance()->boot() on plugins_loaded.
- index.js: providerRegistrations -> bootLines / wooBootLines / servicesAccessors;
  {{PROVIDER_REGISTRATIONS}} -> {{BOOTLOADER_LINES}} + {{SERVICES_ACCESSORS}}.
- Tests: Container_Test dropped; Example_Test + Plugin_Boot_Test cover the
  singleton + idempotent boot; new Services_Test for the locator seams.

Verified: 67 generator + 13 engine tests; full all-modules scaffold — php -l
clean on every file, no leftover Container/Service_Provider refs, no stray
tokens. composer lint / composer test on the new shape run in CI.
@akshat009
akshat009 merged commit 9d94195 into main Aug 29, 2026
6 checks passed
akshat009 added a commit that referenced this pull request Aug 29, 2026
akshat009 added a commit that referenced this pull request Aug 29, 2026
…repare-dist (#11, #12 revised)

Re-audit #2 retracted "drop the */templates/* exclude" — the WC email/My-Account
overrides genuinely fail three sniffs (PrefixAllGlobals on core WC hook names +
loosely-named locals; EscapeOutput on plain-text bodies that use
wp_strip_all_tags). But the blanket path exclude also silenced EscapeOutput on
the HTML email template, where escaping does matter.

Now: when a woo:email / woo:my-account module ships a templates/ dir,
phpcs.xml adds `<file>./templates</file>` and excludes only:
  - WordPress.NamingConventions.PrefixAllGlobals for */templates/*
  - WordPress.Security.EscapeOutput for */templates/emails/plain/* only
Everything else in templates/ (docblocks, spacing, i18n, the HTML email's
escaping) is linted. Gated on a new has_wc_template_overrides flag; a scaffold
without those modules has no templates/ reference at all.

Also: `composer prepare-dist` = `composer install --no-dev --optimize-autoloader`,
so `npm run plugin-zip` doesn't depend on the user reading the release docs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant