Problem
The LinkRenderer service currently violates the best practice that a service must only depend on the wiki and its site-wide configuration. Specifically, it must not logically vary by information from the current web request.
Proposal
If there is use for a generic default that is e.g. based on the default user preferences for CLI use or something like that, then we could keep it. But if not, I suggest we deprecate and remove it in favour of the LinkRendererFactory service which exists already.
Impact
From a quick look in our code (Code search), it seems LinkRenderer is mainly used in code that is user-facing, which makes sense. The majority of its calls are in classes that have a direct connection to RequestContext:
- Action and subclasses.
- SpecialPage and subclasses.
- Utility classes solely used by the above (e..g ProtectionForm).
For example:
public function makeTemplatesOnThisPageList( array $templates ) { $templateListFormatter = new TemplatesOnThisPageFormatter( $this->context, MediaWikiServices::getInstance()->getLinkRenderer() );
The EditPage is a user-facing that requires a WebRequest and session context etc. It already has a req context object handy and could use getLinkRendererFactory()->forUser( $context->getUser() ) instead.
$linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer(); return $linkRenderer->makeLink( $title, null, [], $query );
Idem. OutputPage already has getUser() and knows how to deal with it. Trivial to replace.
And then there are a few odd-ball cases like the below:
// link to the group description page, if it exists $linkTitle = self::getGroupPage( $group ); $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer(); `
This is tricky because the class is generic (not specific to skinned output), and the caller isn't inside a method that takes a "current user" parameter. The thing is, though, this code is effectively using legacy wgUser. Which is known-bad. Except this is worse because it's white-washed behind a modern service, evoking the illusion that the only code smell is lack of dependency injection for the future use case of being able to invoke the code for other wikis. When really it's much worse.
I could only find one or two cases like this, and I would suggest we convert them to what they are by calling RequestContext::getMain()->getUser() (formerly known as $wgUser) explicitly inline, which is what the service wiring currently does. On a case-by-case basis we may be able to figure out if it really needs to depend on the current user and maybe make it use a generic instance instead, or we may find that there is a nearby LinkRenderer, context or User object we can use already.