MediaWiki master
UserLinkRenderer.php
Go to the documentation of this file.
1<?php
2declare( strict_types=1 );
3
4namespace MediaWiki\Linker;
5
6use HtmlArmor;
17use Wikimedia\IPUtils;
18use Wikimedia\Timestamp\ConvertibleTimestamp;
19
26 private TempUserConfig $tempUserConfig;
27 private SpecialPageFactory $specialPageFactory;
28 private LinkRenderer $linkRenderer;
29 private TempUserDetailsLookup $tempUserDetailsLookup;
30
37 private MapCacheLRU $userLinkCache;
38
39 public function __construct(
40 TempUserConfig $tempUserConfig,
41 SpecialPageFactory $specialPageFactory,
42 LinkRenderer $linkRenderer,
43 TempUserDetailsLookup $tempUserDetailsLookup
44 ) {
45 $this->tempUserConfig = $tempUserConfig;
46 $this->specialPageFactory = $specialPageFactory;
47 $this->linkRenderer = $linkRenderer;
48 $this->tempUserDetailsLookup = $tempUserDetailsLookup;
49
50 / Set a large enough cache size to accommodate long pagers,
51 / such as Special:RecentChanges with a high limit.
52 $this->userLinkCache = new MapCacheLRU( 1_000 );
53 }
54
66 public function userLink(
67 UserIdentity $targetUser,
68 IContextSource $context,
69 ?string $altUserName = null,
70 array $attributes = []
71 ): string {
72 $outputPage = $context->getOutput();
73 $outputPage->addModuleStyles( [ 'mediawiki.interface.helpers.styles' ] );
74 $outputPage->addModules( [ 'mediawiki.interface.helpers' ] );
75
76 / Expired temporary account user links are not cacheable, because they contain a tooltip
77 / that needs to have a unique ID used in an ARIA association with the corresponding link.
78 if ( $this->tempUserDetailsLookup->isExpired( $targetUser ) ) {
79 return $this->renderUserLink( $targetUser, $context, $altUserName, $attributes );
80 }
81
82 return $this->userLinkCache->getWithSetCallback(
83 $this->userLinkCache->makeKey(
84 $targetUser->getName(),
85 $altUserName ?? '',
86 implode( ' ', $attributes )
87 ),
88 fn () => $this->renderUserLink( $targetUser, $context, $altUserName, $attributes )
89 );
90 }
91
103 private function renderUserLink(
104 UserIdentity $targetUser,
105 MessageLocalizer $messageLocalizer,
106 ?string $altUserName = null,
107 array $attributes = []
108 ): string {
109 $userName = $targetUser->getName();
110
111 $classes = [ 'mw-userlink' ];
112
113 $postfix = '';
114
115 if ( $this->tempUserConfig->isTempName( $userName ) ) {
116 $classes[] = 'mw-tempuserlink';
117
118 / Adjust the styling of expired temporary account links (T358469).
119 if ( $this->tempUserDetailsLookup->isExpired( $targetUser ) ) {
120 $classes[] = 'mw-tempuserlink-expired';
121 $tooltipId = sprintf(
122 'mw-tempuserlink-expired-tooltip-%08x',
123 ConvertibleTimestamp::hrtime()
124 );
125
126 $postfix = Html::element(
127 'div',
128 [
129 'id' => $tooltipId,
130 'role' => 'tooltip',
131 'class' => 'cdx-tooltip mw-tempuserlink-expired--tooltip',
132 ],
133 $messageLocalizer->msg( 'tempuser-expired-link-tooltip' )->text()
134 );
135
136 $attributes['aria-describedby'] = $tooltipId;
137
138 / Hide default link title when rendering expired temporary account links
139 / to avoid conflicting with the tooltip.
140 $attributes['title'] = '';
141 }
142
143 $pageName = $this->specialPageFactory->getLocalNameFor( 'Contributions', $userName );
144 $page = new TitleValue( NS_SPECIAL, $pageName );
145 } elseif ( !$targetUser->isRegistered() ) {
146 $page = ExternalUserNames::getUserLinkTitle( $userName );
147
148 if ( ExternalUserNames::isExternal( $userName ) ) {
149 $classes[] = 'mw-extuserlink';
150 } elseif ( $altUserName === null ) {
151 $altUserName = IPUtils::prettifyIP( $userName );
152 }
153 $classes[] = 'mw-anonuserlink'; / Separate link class for anons (T45179)
154 } else {
155 $page = TitleValue::tryNew( NS_USER, strtr( $userName, ' ', '_' ) );
156 }
157
158 / Wrap the output with <bdi> tags for directionality isolation
159 $linkText =
160 '<bdi>' . htmlspecialchars( $altUserName ?? $userName ) . '</bdi>';
161
162 if ( isset( $attributes['class'] ) ) {
163 $classes[] = $attributes['class'];
164 }
165
166 $attributes['class'] = implode( ' ', $classes );
167
168 if ( $page !== null ) {
169 return $this->linkRenderer->makeLink( $page, new HtmlArmor( $linkText ), $attributes ) . $postfix;
170 }
171
172 return Html::rawElement( 'span', $attributes, $linkText ) . $postfix;
173 }
174}
const NS_USER
Definition Defines.php:67
const NS_SPECIAL
Definition Defines.php:54
Marks HTML that shouldn't be escaped.
Definition HtmlArmor.php:30
Store key-value entries in a size-limited in-memory LRU cache.
This class is a collection of static functions that serve two purposes:
Definition Html.php:57
Class that generates HTML for internal links.
Service class that renders HTML for user-related links.
userLink(UserIdentity $targetUser, IContextSource $context, ?string $altUserName=null, array $attributes=[])
Render a user page link (or user contributions for anonymous and temporary users).
__construct(TempUserConfig $tempUserConfig, SpecialPageFactory $specialPageFactory, LinkRenderer $linkRenderer, TempUserDetailsLookup $tempUserDetailsLookup)
Factory for handling the special page list and generating SpecialPage objects.
Represents the target of a wiki link.
Class to parse and build external user names.
Caching lookup service for metadata related to temporary accounts, such as expiration.
Interface for objects which can provide a MediaWiki context on request.
Interface for temporary user creation config and name matching.
Interface for objects representing user identity.
isRegistered()
This must be equivalent to getId() != 0 and is provided for code readability.
Interface for localizing messages in MediaWiki.
msg( $key,... $params)
This is the method for getting translated interface messages.
element(SerializerNode $parent, SerializerNode $node, $contents)

Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant