[6.x] Registries (widget types, field types, ...)#19270
Open
riasvdv wants to merge 19 commits into
Open
Conversation
📚 Storybook previews@craftcms/ui — open Storybook No changed components detected in this Storybook. resources/js — open Storybook No changed components detected in this Storybook. |
# Conflicts: # src/View/TemplateRenderer.php # tests/Unit/View/TemplateRendererTest.php
Contributor
There was a problem hiding this comment.
Pull request overview
This PR migrates multiple Craft CMS extension points from “resolve-time events” to registry-based APIs, making registries the primary source of truth while preserving Yii2-adapter compatibility via explicit legacy-finalization steps.
Changes:
- Introduces a shared
TypeRegistryfoundation and new registries for key extension points (elements, fields, widgets, utilities, filesystem types, image transformers, template roots/cache collectors, GraphQL directives/argument handlers, permissions, system messages). - Refactors core services and plugin concerns to register/resolve via registries instead of dispatching “*Resolving” events.
- Updates Yii2-adapter bridges and adds/updates tests to validate modern+legacy interoperability and registry semantics.
Reviewed changes
Copilot reviewed 122 out of 122 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| CHANGELOG-WIP.md | Updates changelog entries to reference registry APIs instead of resolving events. |
| CHANGELOG.md | Updates changelog entries to reference registry APIs instead of resolving events. |
| src/Component/TypeRegistry.php | Adds a reusable base registry with identity/protection/validation semantics. |
| src/Dashboard/Dashboard.php | Switches widget type resolution to WidgetTypeRegistry. |
| src/Dashboard/Events/WidgetTypesResolving.php | Removes the widget-type resolving event (replaced by registry). |
| src/Dashboard/WidgetTypeRegistry.php | Adds widget-type registry backed by TypeRegistry. |
| src/Element/ElementTypeRegistry.php | Adds element-type registry backed by TypeRegistry. |
| src/Element/Elements.php | Switches element type resolution from events to ElementTypeRegistry. |
| src/Element/Events/ElementTypesResolving.php | Removes the element-types resolving event (replaced by registry). |
| src/Field/Events/FieldTypesResolving.php | Removes the field-types resolving event (replaced by registry). |
| src/Field/Events/LinkTypesResolving.php | Removes the link-types resolving event (replaced by registry). |
| src/Field/FieldTypeRegistry.php | Adds field-type registry backed by TypeRegistry. |
| src/Field/Fields.php | Switches field type resolution from events to FieldTypeRegistry. |
| src/Field/Link.php | Switches link type resolution to LinkTypeRegistry. |
| src/Field/LinkTypeRegistry.php | Adds link-type registry backed by TypeRegistry with protected URL identity. |
| src/Filesystem/Events/FilesystemTypesResolving.php | Removes the filesystem-types resolving event (replaced by registry). |
| src/Filesystem/FilesystemTypeRegistry.php | Adds filesystem-type registry backed by TypeRegistry. |
| src/Filesystem/Filesystems.php | Switches filesystem type resolution from events to FilesystemTypeRegistry. |
| src/Gql/ArgumentManager.php | Switches argument handlers from event resolution to GqlArgumentHandlerRegistry, adds factory support and validation. |
| src/Gql/Events/GqlArgumentHandlersResolving.php | Removes the argument-handlers resolving event (replaced by registry). |
| src/Gql/Events/GqlDirectivesResolving.php | Removes the directives resolving event (replaced by registry). |
| src/Gql/Gql.php | Switches directive loading from events to GqlDirectiveRegistry. |
| src/Gql/GqlArgumentHandlerRegistry.php | Adds argument-handler registry supporting class handlers and factories. |
| src/Gql/GqlDirectiveRegistry.php | Adds directive registry with schema-scope filtering and reserved identity protection. |
| src/Http/Controllers/Gql/SchemasController.php | Updates permission-group construction to include stable handles. |
| src/Image/Events/ImageTransformersResolving.php | Removes the image-transformers resolving event (replaced by registry). |
| src/Image/ImageTransformerRegistry.php | Adds image-transformer registry backed by TypeRegistry. |
| src/Image/ImageTransforms.php | Switches transformer type resolution from events to ImageTransformerRegistry. |
| src/Plugin/Concerns/HasElementTypes.php | Registers plugin element types via ElementTypeRegistry. |
| src/Plugin/Concerns/HasFieldtypes.php | Registers plugin field types via FieldTypeRegistry. |
| src/Plugin/Concerns/HasPermissions.php | Registers plugin permission groups via PermissionGroupRegistry instead of resolving event listeners. |
| src/Plugin/Concerns/HasUtilities.php | Registers plugin utilities via UtilityTypeRegistry. |
| src/Plugin/Concerns/HasViews.php | Registers plugin CP template roots via TemplateRootRegistry. |
| src/Plugin/Concerns/HasWidgets.php | Registers plugin widgets via WidgetTypeRegistry. |
| src/Support/Facades/HtmlSanitizers.php | Updates @see reference to local class name. |
| src/Support/Facades/Template.php | Updates @see reference to local class name. |
| src/SystemMessage/Events/SystemMessagesResolving.php | Removes system-messages resolving event (replaced by registry). |
| src/SystemMessage/SystemMessageRegistry.php | Adds system-message registry with container-invoked factories and validation. |
| src/SystemMessage/SystemMessages.php | Switches default message resolution to SystemMessageRegistry; scopes caching per locale scope. |
| src/User/Data/PermissionGroup.php | Makes permission-group handle an explicit constructor field (stable identity). |
| src/User/Events/UserPermissionsResolving.php | Removes permissions resolving event (replaced by registry). |
| src/User/PermissionGroupRegistry.php | Adds registry for permission-group providers with validation and snapshot behavior. |
| src/User/UserPermissions.php | Applies registry providers to core permission groups and assigns stable handles to core groups. |
| src/Utility/Events/UtilitiesResolving.php | Removes utilities resolving event (replaced by registry). |
| src/Utility/Utilities.php | Switches utility type resolution to UtilityTypeRegistry. |
| src/Utility/UtilityTypeRegistry.php | Adds utility-type registry with config/edition/volume-based filtering and reserved identities. |
| src/View/Events/CpTemplateRootsResolving.php | Removes CP template-roots resolving event (replaced by registry). |
| src/View/Events/SiteTemplateRootsResolving.php | Removes site template-roots resolving event (replaced by registry). |
| src/View/Events/TemplateCacheCollectorsResolving.php | Removes template-cache collector resolving event (replaced by registry). |
| src/View/TemplateCacheCollectorRegistry.php | Adds template-cache collector registry (core collectors + extensibility). |
| src/View/TemplateCaches.php | Switches collector discovery from events to TemplateCacheCollectorRegistry. |
| src/View/TemplateMode.php | Switches templateRoots() to read from TemplateRootRegistry. |
| src/View/TemplateRootRegistry.php | Adds registry for template roots keyed by mode+namespace with ordering and snapshots. |
| src/View/ViewServiceProvider.php | Adjusts template-root integration timing to bootstrap phase (BootProviders). |
| tests/Feature/Dashboard/DashboardTest.php | Updates dashboard tests to register widgets via registry. |
| tests/Feature/Element/ElementTypesTest.php | Updates element type tests to use registry and handle dynamic changes. |
| tests/Feature/Field/FieldsTest.php | Updates field type tests to use registry (including provider-based registration). |
| tests/Feature/Filesystem/FilesystemsTest.php | Updates filesystem type tests to use registry. |
| tests/Feature/Gql/ArgumentManagerTest.php | Updates argument manager tests for registry handlers, factories, and binding behavior. |
| tests/Feature/Gql/GqlTest.php | Updates directive tests to use GqlDirectiveRegistry and verify schema caching behavior. |
| tests/Feature/Http/Controllers/Elements/DeleteElementsControllerTest.php | Updates Elements service test doubles for new constructor dependency (ElementTypeRegistry). |
| tests/Feature/Http/Controllers/Elements/SaveElementControllerTest.php | Updates Elements service test doubles for new constructor dependency (ElementTypeRegistry). |
| tests/Feature/Http/Controllers/Elements/SaveElementIndexElementsControllerTest.php | Updates Elements service test doubles for new constructor dependency (ElementTypeRegistry). |
| tests/Feature/Http/Controllers/Elements/SearchControllerTest.php | Updates Elements service test doubles for new constructor dependency (ElementTypeRegistry). |
| tests/Feature/Http/Controllers/MatrixControllerTest.php | Updates Elements service test double for new constructor dependency (ElementTypeRegistry). |
| tests/Feature/Http/Controllers/SiteRouteControllerTest.php | Updates site template root setup to use TemplateRootRegistry. |
| tests/Feature/Image/ImageTransformsTest.php | Updates transformer tests to use ImageTransformerRegistry. |
| tests/Feature/SystemMessage/SystemMessagesTest.php | Updates system message tests to use SystemMessageRegistry and verify locale scoping. |
| tests/Feature/User/UserPermissionsTest.php | Adds coverage for permission registry register/remove and stable handles. |
| tests/Feature/Utility/UtilitiesTest.php | Updates utility tests to use UtilityTypeRegistry and validate filtering behavior. |
| tests/Unit/Field/LinkTest.php | Adds unit coverage for link types reading from LinkTypeRegistry. |
| tests/Unit/Gql/GqlArgumentHandlerRegistryTest.php | Adds unit coverage for handler registry ordering, updates, and validation. |
| tests/Unit/Plugin/Concerns/HasElementTypesTest.php | Updates plugin element type boot behavior tests to use registry-backed services. |
| tests/Unit/Plugin/Concerns/HasFieldtypesTest.php | Updates plugin field type boot behavior tests to use registry-backed services. |
| tests/Unit/Plugin/Concerns/HasPermissionsTest.php | Updates plugin permissions boot behavior tests to use PermissionGroupRegistry. |
| tests/Unit/Plugin/Concerns/HasUtilitiesTest.php | Updates plugin utilities boot behavior tests to use registry-backed services. |
| tests/Unit/Plugin/Concerns/HasViewsTest.php | Updates plugin view root tests to rely on TemplateMode::templateRoots()/registry. |
| tests/Unit/Plugin/Concerns/HasWidgetsTest.php | Updates plugin widget tests to use registry-backed dashboard service. |
| tests/Unit/SystemMessage/SystemMessageRegistryTest.php | Adds unit coverage for SystemMessageRegistry behavior and validation. |
| tests/Unit/Twig/TemplateResolverTest.php | Updates template resolver tests to register CP roots via TemplateRootRegistry. |
| tests/Unit/User/PermissionGroupRegistryTest.php | Adds unit coverage for permission group provider registry semantics and snapshots. |
| tests/Unit/View/TemplateCachesTest.php | Updates template cache tests to register collectors via registry. |
| tests/Unit/View/TemplateModeTest.php | Removes event-dispatch assertions now that template roots are registry-backed. |
| tests/Unit/View/TemplateRootRegistryTest.php | Adds unit coverage for TemplateRootRegistry behavior across modes and snapshots. |
| tests/Unit/View/TwigEngineTest.php | Updates TwigEngine test to register CP template roots via TemplateRootRegistry. |
| yii2-adapter/constants/Field/Concerns/LegacyFieldConstants.php | Updates legacy link-type bridging to use LinkTypeRegistry and finalize-style registration. |
| yii2-adapter/legacy/events/RegisterComponentTypesEvent.php | Updates deprecation messaging to point to registries. |
| yii2-adapter/legacy/events/RegisterEmailMessagesEvent.php | Updates deprecation messaging to point to SystemMessageRegistry. |
| yii2-adapter/legacy/events/RegisterGqlArgumentHandlersEvent.php | Updates handler typing/docs for closures and points deprecation to registry API. |
| yii2-adapter/legacy/events/RegisterGqlDirectivesEvent.php | Updates deprecation messaging to point to GqlDirectiveRegistry. |
| yii2-adapter/legacy/events/RegisterTemplateRootsEvent.php | Updates deprecation messaging to point to TemplateRootRegistry. |
| yii2-adapter/legacy/events/RegisterUserPermissionsEvent.php | Updates deprecation messaging to point to PermissionGroupRegistry. |
| yii2-adapter/legacy/services/Dashboard.php | Moves legacy widget registration bridging into finalize-style registry reconciliation. |
| yii2-adapter/legacy/services/Elements.php | Moves legacy element type registration bridging into finalize-style registry reconciliation. |
| yii2-adapter/legacy/services/Fields.php | Moves legacy field type registration bridging into finalize-style registry reconciliation. |
| yii2-adapter/legacy/services/Fs.php | Moves legacy filesystem type registration bridging into finalize-style registry reconciliation. |
| yii2-adapter/legacy/services/Gql.php | Moves legacy directive registration bridging into finalize-style registry reconciliation. |
| yii2-adapter/legacy/services/ImageTransforms.php | Moves legacy transformer type registration bridging into finalize-style registry reconciliation. |
| yii2-adapter/legacy/services/SystemMessages.php | Removes legacy system-message resolving bridge in favor of registry-based adapter implementation. |
| yii2-adapter/legacy/services/UserPermissions.php | Bridges legacy permissions via PermissionGroupRegistry provider + resets modern cache. |
| yii2-adapter/legacy/services/Utilities.php | Moves legacy utility registration bridging into finalize-style registry reconciliation. |
| yii2-adapter/legacy/web/View.php | Moves legacy template-root bridging into finalize-style registry reconciliation. |
| yii2-adapter/src/DeprecatedConcepts.php | Registers deprecated-concept-provided types via registries rather than resolving events. |
| yii2-adapter/src/Event/EventCompatibility.php | Switches adapter boot bridges to register into registries and adds explicit finalize step. |
| yii2-adapter/src/Event/LegacyGqlEvents.php | Adds registry-based finalize for legacy GQL argument handlers; removes resolve-time bridge. |
| yii2-adapter/src/LegacyApp.php | Ensures legacy finalize registration events run after boot when installed; resets deprecated support flags. |
| yii2-adapter/src/SystemMessage/LegacySystemMessageRegistry.php | Adds adapter wrapper to expose registry messages to legacy Yii event transforms with locale scoping/caching. |
| yii2-adapter/src/Yii2ServiceProvider.php | Wraps SystemMessageRegistry with legacy adapter and registers base site template root via registry. |
| yii2-adapter/tests-laravel/Fixtures/LegacyPlugin/templates/index.twig | Adds fixture template for legacy plugin template-root tests. |
| yii2-adapter/tests-laravel/Gql/LegacyGqlCompatibilityTest.php | Expands adapter test coverage for directive/argument handler bridging behavior. |
| yii2-adapter/tests-laravel/Http/LegacyActionRoutingTest.php | Updates CP routing test to register template roots via registry. |
| yii2-adapter/tests-laravel/Http/LegacySiteTemplateRoutingTest.php | Removes Once::flush() dependency now that template roots are registry-backed. |
| yii2-adapter/tests-laravel/Legacy/DeprecatedConceptRegistrationCompatibilityTest.php | Adds coverage for deprecated-concept registrations finalized through registries. |
| yii2-adapter/tests-laravel/Legacy/PermissionRegistryCompatibilityTest.php | Adds coverage for permission registry/legacy handle stability and rebuild behavior. |
| yii2-adapter/tests-laravel/Legacy/PluginLifecycleCompatibilityTest.php | Adds coverage ensuring legacy registrations finalize after legacy init + modern boot and propagate to view finder hints. |
| yii2-adapter/tests-laravel/Legacy/RegistrationRegistryCompatibilityTest.php | Adds coverage for system messages, permissions, and template roots bridging via registries. |
| yii2-adapter/tests-laravel/Legacy/TypeRegistryCompatibilityTest.php | Adds coverage for legacy type registration events applying to modern registries and identity rules. |
| yii2-adapter/tests-laravel/View/RegisterTemplateCacheCollectorsTest.php | Updates adapter test to assert collector registration via registry. |
| yii2-adapter/tests/unit/gql/ArgumentHandlerTest.php | Updates unit test to register argument handlers via GqlArgumentHandlerRegistry. |
| yii2-adapter/tests/unit/mail/MailerTest.php | Removes commented event-based system-message registration snippet (obsolete with registries). |
| yii2-adapter/tests/unit/web/ViewTest.php | Updates template root tests to populate TemplateRootRegistry instead of listening for resolving events. |
riasvdv
marked this pull request as ready for review
July 23, 2026 14:09
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.
Description
Instead of relying on events for extensibility, this moves registration and the source of truth for all extension points into registries
Extension Registries
Craft’s Laravel registration events have been replaced with singleton registries. Plugins that listen for any of the removed
*Resolvingevents must register their extensions during theirboot()method instead.Legacy Yii registration events remain supported through
craftcms/yii2-adapter.Type Registries
Most extension types use a shared registry API:
Registries also support replacing and removing types:
Registries validate that registered classes implement the appropriate contract. Types with domain identifiers, such as utility IDs, link type IDs, GraphQL directive names, and element reference handles, must have unique identifiers.
Some core types are protected and cannot be removed or replaced:
urllink typedependenciesandresourcestemplate cache collectorsCollections returned by
types()are snapshots. Modify the registry throughregister(),replace(), orremove()rather than modifying the returned collection.GraphQL Argument Handlers
CraftCms\Cms\Gql\Events\GqlArgumentHandlersResolvinghas been replaced byCraftCms\Cms\Gql\GqlArgumentHandlerRegistry.Handlers may be registered as class names or container-invoked factories:
Handler classes must implement
CraftCms\Cms\Gql\Contracts\ArgumentHandlerInterface. Registering handler instances is no longer supported; use a class name or factory instead.Handlers can be removed by argument name:
System Messages
CraftCms\Cms\SystemMessage\Events\SystemMessagesResolvinghas been replaced byCraftCms\Cms\SystemMessage\SystemMessageRegistry.System messages are registered using lazy, container-invoked factories. The factory must return a
SystemMessagewhose key matches the registered key.Messages can be removed by key:
Factories are resolved in the active site locale.
User Permissions
CraftCms\Cms\User\Events\UserPermissionsResolvinghas been replaced byCraftCms\Cms\User\PermissionGroupRegistry.Permission groups are registered through providers that receive and return a collection:
Provider handles must be unique. Each resolved
PermissionGroupmust also have a unique, stable handle; handles are no longer inferred from group headings.Providers run whenever Craft rebuilds its permission catalog, so they may dynamically append, transform, or replace permission groups.
Template Roots
The following events have been replaced by
CraftCms\Cms\View\TemplateRootRegistry:CraftCms\Cms\View\Events\CpTemplateRootsResolvingCraftCms\Cms\View\Events\SiteTemplateRootsResolvingRegister control panel template roots with
TemplateMode::Cp:Register site template roots with
TemplateMode::Site:Multiple paths may be registered under the same namespace:
Namespaces can be removed independently for each template mode:
Registration Timing
Registration should normally happen during a plugin or service provider’s
boot()method. Unlike resolving events, registries are not redispatched whenever a catalog is read.The following registrations remain lazy:
Register GraphQL directives before schemas are built and template cache collectors before template-cache collection begins.
Legacy Plugins
Plugins using the deprecated Yii registration events do not need to migrate immediately. The Yii2 adapter continues to bridge those events into the new registries after legacy plugins initialize and modern plugins boot.
New Craft 6 plugin code should use the registries directly.