Skip to content

Migrate DI container from Dhii to inpsyde/modularity (510)#9

Open
danieldudzic wants to merge 28 commits intodev/mainfrom
dev/IZET-510-migrate-pos-to-inpsyde-modularity
Open

Migrate DI container from Dhii to inpsyde/modularity (510)#9
danieldudzic wants to merge 28 commits intodev/mainfrom
dev/IZET-510-migrate-pos-to-inpsyde-modularity

Conversation

@danieldudzic
Copy link
Contributor

Description

Migrate the plugin architecture from dhii/module-interface + dhii/containers to inpsyde/modularity ^1.7, and scope conflict-prone packages with Mozart.

Container bootstrap — Replaced the manual container chain (ProxyContainer → CachingContainer → DelegatingContainer → CompositeCachingServiceProvider) with Package::new(PluginProperties).

All 18 modules now implement ServiceModule, ExtendingModule, and/or ExecutableModule with ModuleClassNameIdTrait, returning services()/extensions() arrays directly instead of wrapping in ServiceProvider. Boot logic is inlined into run().

Library classes — Migrated QueueLibrary, StateMachineLibrary, WcEventsLibrary, and ZettlePhpSdkLibrary from Dhii container chains to Package::new(LibraryProperties::new(...)).

Interface replacements — Replaced dhii/collections-interface with project-level WritableContainerInterface / ClearableContainerInterface in src/Container/. Replaced dhii/validator with project-level ValidatorInterface in src/Validation/. Replaced dhii/event-dispatcher-interface with PSR-14 (psr/event-dispatcher).

Cleanup — Removed all Dhii packages from root and 18 module composer.json files. Updated test infrastructure and fixed extension argument order in test files.

Mozart namespace scoping — Scoped psr/container and inpsyde/modularity into lib/packages/ under the Syde\Vendor\Zettle\ prefix using Mozart, matching the pattern from PayPal Payments.

Key behavioral change: In Inpsyde Modularity, extension callbacks receive ($previous, $container) instead of Dhii's ($container, $previous). Extensions may receive null as $previous if no factory is registered for the service key.

Steps to Test

  1. Run ddev composer install to verify dependency resolution with no Dhii packages
  2. Run ddev exec vendor/bin/phpunit — expect 31 passed, 3 incomplete, 2 skipped (7 auth errors require API credentials, 1 pre-existing state machine failure)
  3. Activate the plugin in WordPress and verify it boots without errors — even with wc-smooth-generator or other plugins that bundle psr/container 1.x
  4. Navigate to WooCommerce → Settings → PayPal Point of Sale and confirm settings page loads
  5. Verify the onboarding flow still functions (connect/disconnect)
  6. Trigger a product sync and confirm queue processing works end-to-end

@danieldudzic danieldudzic requested a review from AlexP11223 March 20, 2026 23:30
@private-packagist
Copy link

composer.lock

Package changes

Package Operation From To About
inpsyde/modularity add - 1.12.0 view code - changelog - License: GNU General Public License v2.0 or later
psr/event-dispatcher add - 1.0.0 view code - License: MIT License
brain/nonces upgrade 1.0.5 1.0.6 diff - changelog
inpsyde/assets upgrade 2.11.0 2.13 diff - changelog
inpsyde/inpsyde-debug upgrade dev-dev/main 6c6c1dc dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 73db0e3 -
inpsyde/inpsyde-http-client upgrade dev-dev/main 25ed6ee dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 7ba42da -
inpsyde/inpsyde-queue upgrade dev-dev/main e10798d dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity c8ea863 -
inpsyde/inpsyde-state-machine upgrade dev-dev/main ac8ef0e dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity b98f041 -
inpsyde/inpsyde-woocommerce-lifecycle-events upgrade dev-dev/main 0cdd3bd dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity b319848 -
inpsyde/paypal-pos-assets upgrade dev-dev/main 0127135 dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 13c18e8 -
inpsyde/paypal-pos-auth upgrade dev-dev/main 32539dd dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 3372882 -
inpsyde/paypal-pos-logging upgrade dev-dev/main a5a26b6 dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity b19d1f4 -
inpsyde/paypal-pos-notices upgrade dev-dev/main 536ac74 dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 36c8dc5 -
inpsyde/paypal-pos-onboarding upgrade dev-dev/main 6fbc77d dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity aeb2def -
inpsyde/paypal-pos-php-sdk upgrade dev-dev/main 0add701 dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 0641ff7 -
inpsyde/paypal-pos-product-debug upgrade dev-dev/main 02041da dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity fdbd217 -
inpsyde/paypal-pos-product-settings upgrade dev-dev/main 35cfcad dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity f66a398 -
inpsyde/paypal-pos-queue upgrade dev-dev/main 135d056 dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity d7d3bbc -
inpsyde/paypal-pos-settings upgrade dev-dev/main 80c2303 dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity c0cd45f -
inpsyde/paypal-pos-sync upgrade dev-dev/main 4f7acff dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 1988ccc -
inpsyde/paypal-pos-webhooks upgrade dev-dev/main 800ef55 dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 6496b12 -
inpsyde/psr-18-wp-http-client upgrade v0.1.0-alpha4 0.1.0-alpha5 diff - changelog
inpsyde/wc-product-contracts upgrade dev-dev/main 3bea09d dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity 3bea09d -
inpsyde/wc-status-report upgrade dev-dev/main 22bd64c dev-dev/IZET-510-migrate-pos-to-inpsyde-modularity efb4a7d -
php-http/client-common upgrade 2.7.2 2.7.3 diff - changelog
php-http/curl-client upgrade 2.3.3 2.4.0 diff - changelog
psr/container upgrade 1.1.2 2.0.2 diff - changelog
sniccowp/php-scoper-wordpress-excludes upgrade 6.8.1 6.9.1 diff
symfony/options-resolver upgrade v7.3.3 v7.4.0 diff - changelog
container-interop/service-provider remove v0.4.1 - -
dhii/collections-interface remove v0.3.0 - -
dhii/containers remove v0.1.5 - -
dhii/event-dispatcher-interface remove v0.1.0-alpha1 - -
dhii/module-interface remove v0.3.0-alpha2 - -
dhii/validation-interface remove v0.3.0-alpha3 - -
dhii/validator remove v0.1.0-alpha1 - -

Dev Package changes

Package Operation From To About
brain/monkey upgrade 2.6.2 2.7.0 diff - changelog
phpoption/phpoption upgrade 1.9.4 1.9.5 diff - changelog
spatie/array-to-xml upgrade 3.4.0 3.4.4 diff - changelog
symfony/console upgrade v7.3.6 v7.4.7 diff - changelog
symfony/filesystem upgrade v7.3.6 v7.4.6 diff - changelog
symfony/service-contracts upgrade v3.6.0 v3.6.1 diff - changelog
symfony/string upgrade v7.3.4 v7.4.6 diff - changelog

Settings · Docs · Powered by Private Packagist


```bash
ddev composer require --dev coenjacobs/mozart:^0.7.1 -W
ddev exec vendor/bin/mozart compose
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not look into everything else yet, but we probably do not need to use Mozart here. In PCP we used it because PHP-Scoper had some issues at that time. Now we have PHP-Scoper during build, so it should be fine to just use it for everything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexP11223 I looked into removing Mozart, but it breaks local dev.

When testing with a plugin that bundles a PSR container (like wc-smooth-generator bundles psr/container 1.x), its autoloader takes precedence over ours, so the untyped PSR-11 1.x ContainerInterface gets registered. Then inpsyde/modularity (which uses typed PSR-11 2.x signatures) throws a fatal error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, yeah, if we need to use such plugins, then I guess it's the only way.

Though would be great to nudge their developers to update. :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How common is this during development? AFAIK, PoS would be the only project that requires this workaround during development.

Refactoring our entire codebase against scoped symbols is something we decidedly wanted to get away from when committing to php-scoper during build.

For testing compatibility issues, it is very easy to throw the offending plugins and a build from GHA into a quick wp-env setup and debug there.
Since this repo here is public, we could even point wp-env directly to a build branch.

I really would not use mozart here. It's an extremely invasive change, a constant cat & mouse game and hard to integrate with libraries. And we already have php-scoper for free.

How big is the pain with wc-smooth-generator?

Copy link
Contributor

@AlexP11223 AlexP11223 Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe one workaround for this generator plugin could be to simply disable our plugin when generating something, I guess it would not need to be done often.

But, yes, as of right now, I think this plugin would not be super useful. We only work with products, and currently the main things that matter are product type and the inventory number.
Usually we were just using the WooCommerce sample products, which iirc are created automatically in DDEV here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Biont Actually, PayPal Payments already uses exactly this workaround. The composer.json configures Mozart to rewrite both psr/container and inpsyde/modularity into the WooCommerce\PayPalCommerce\Vendor\ namespace:

"mozart": {
    "dep_namespace": "WooCommerce\\PayPalCommerce\\Vendor\\",
    "dep_directory": "/lib/packages/",
    "classmap_directory": "/lib/classes/",
    "classmap_prefix": "PCPP_",
    "packages": [
        "psr/container",
        "inpsyde/modularity"
    ],
    "delete_vendor_directories": true
}

So the production code uses the Mozart-prefixed copy (WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface), and psr/container is only in require-dev — it's not a production dependency.

There's a bunch of plugins that utilize the PSR container these days, and we shouldn't be limited (if possible) by our own setup regarding what we can test locally or have to alter our flows. I fundamentally want the same freedom while developing locally as when testing post-production.

Copy link
Member

@Biont Biont Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danieldudzic Pardon my ignorance then.

However, I would like to hazard a guess that this is most likely an artifact from a time before build & distribute and php-scoper were introduced.

  1. No Composer scripts trigger it — the scripts section only defines ci (phpcs) and unit (phpunit). Mozart's typical hook would be post-install-cmd or post-update-cmd, and
    neither is present.
  2. No allow-plugins entry for Mozart — the config.allow-plugins block doesn't include coenjacobs/mozart, so even if it tried to act as a Composer plugin, it would be blocked.
  3. Our packaging workflows don't execute it

To run it, you'd need to invoke it manually: vendor/bin/mozart compose.

The workaround is only used, because the code is already committed to VCS and now the convention is sticking around. The damage is done and noone went back in and fixed the mess after we introduced php-scoper. The mozart config should be removed and the code unscoped - but that's a different discussion.

Here in PoS we still have the option to prevent bending our source codebase around potential issues with random third-party plugins - issues which will be gone in production because we have full scoping anyway

Copy link
Contributor

@AlexP11223 AlexP11223 Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in PCP it was added as a quick fix when we could not use PHP-Scoper yet for some reason. woocommerce/woocommerce-paypal-payments#972

So, here we have to choose which trade-off we prefer:

  1. A cleaner approach without Mozart, but possible issues with some third-party plugins in the development environment.
  2. The current messier approach, solving these issues.
  3. We can also try to isolate the third-party plugins instead, if there is a simple and reliable way. https://inpsyde.slack.com/archives/C01DTSYJ743/p1774274144957039

One of the issues with that Mozart approach is that it may be confusing which version of the package is actually used and it will not update automatically. So, if we are going to use it, maybe we should at least try to somehow automate it.

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.

3 participants