User:Daniel Kinzler (WMDE)/MCR-SlotRoleHandler

Sketch of the interface for SlotRoleHandler and SlotRoleRegistry:

SlotRoleHandler
Alternative names: SlotRole, SlotHandler.

Note that there may be several different SlotRoleHandlers for the same role (at least for the "main" role). Content model changes

Interface

 * getRoleName (or getRole - or getName, of the class is called SlotRole)
 * getNameMessageKey and getDescriptionMessageKey for representing the role in the UI. We could use a convention for building these keys instead, like we do for API modules. But TranslateWiki likes it if all messages defiend by an extension share a prefix.
 * getContentModel returns the slot's content model.
 * wrapOutput( $output ) returns HTML including any wrapping or tags or headers. $output is a ParserOutput (or a more narrow Rendering interface). This assumes that the actual rendering of the Content should not be the responsibility of the SlotRoleHandler. If rendering should be triggered here internally, any caching logic would also need to be accessible from the SlotRoleHandler. This seems impractical, especially for previews, during editing, etc.
 * getOutputPlacement returns a hint to higher level code (whatever replaces Article::view, or even skin code) how the output should be placed. Could be an integer, so output gets sorted by that key. Could also include a region name (top/center/bottom/infobox/sidebar/footer/etc).
 * alternatively, define placeOutput( $output, $layout ) instead of wrapOutput and getOutputPlacement; $output is a parserOutput (or Rendering interface), $layout is an array of HTML fragments - either a flat list, or an associative array of lists, defining regions.
 * registerOutput( $slotOutput, $combinedOutput ) registers any relevant JS, CSS, cache control headers, or other HTML/HTTP meta-data in $combinedOutput. This may copy information from $slotOutput, or completely ignore $slotOutput and just register a hard coded list of scripts needed for the desired display.
 * registerDataUpdates( $content, $slotOutputProvider, $combinedOutput ) registers the necessary data updates in $combiendOutput; As per T190063, this should blindly copy everything per default. This method is only needed if we want to allow the "track everything" behavior to be overwritten per slot. $slotOutputProvider is an interface that allows lazy but cached access to renderings of individual slots.
 * getDeletionDataUpdates allows overwriting the behavior of Content::getDeletionUpdates. Should be here if registerDataUpdates is here, and should not be here if registerDataUpdates is not needed here.
 * probably getArticleCountMethod, which declares how this slot should help determine whether the page is counted as an "article" in site stats. Example: For the main slot in content namespaces, this would follow $wgArticleCountMethod. For SDC mediainfo slots in file description pages, this would be 'any'. For the documentation slot on template pages, this would be 'none' (well, this isn't really relevant in non-content namespaces anyway).
 * maybe providesRedirects, which declares whether this slot can be used to define redirects. Probably not needed: Currently, only the main slot can do that. Conceptually, it would be much better of redirects were always defined by a special redirect slot, with its own content model.

Interface

 * getRoleHandler( $role, $title ): SlotRoleHandler. Provides a handler for the given role. Note that the same role may have different handlers depending on the page title - this is especially the case for the main slot (maybe only for the main slot). Returns a $title could just be a PageIdentity (to be introduced) instead of a Title. The handler for the main slot will have to depend on the page's concrete content model, which depends on the database state. This is somewhat circular: generally, the SlotRoleHandler determines the content model. But at least for the main slot, it will have to be the other way around. Internally, main slot handlers could be registered using composite keys that use the model as a suffix, e.g. "main-wikitext", "main-javascript", "main-wikibase-item", etc.
 * getSupportedRoles( $title ): returns a list of roles supported for the given title. This informs the UI layer which roles should be offered when creating or editing the page. This does not guarantee that no other slots may exist on the page. If additional slots exist, they must at least be "looped through" all edits, and must be accessible when addressed explicitly.
 * getRequiredRoles( $title ): returns a list of roles required for the given title. This informs the UI which roles to require during user interaction. This does not guarantee that no revisions exist on the page that do not have all of these slots. All operations must still be possible if any of the slots missing (except the main slot).

Implementation
Since SlotRoleHandlers are not pure value objects and may need access to services, they need to be constructed via callbacks. This could be done by making the SlotRoleRevistry a ServiceContainer (or wrap a ServiceContainer). This would also provide a mechanism for extensions to register additional slot handlers. The declaration and instantiation mechanism for SlotRoleHandlers should be considered an extension point, not configuration.

This leaves the question how to decide which SlotRoleHandler to use for the main slot for which titles. This could be done with a configuration variable and a hooks, like $wgContentModels and the ContentHandlerDefaultModelFor, ContentModelCanBeUsedOn, etc. These are used to configure the content model for the main slot based on namespace and possibly other information embedded in the title, like a ".js" suffix. Since these things together effectively determine a "kind of page", it may be more useful to build on the concept of page types, that already exists in the form of WikiFilePage, ImagePage, etc. An initial implementation of SlotRoleRegistry however may just use hard coded information for well known content models, plus a hook for extensions.