Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 87 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 1 |
AbstractFormatter | |
0.00% |
0 / 87 |
|
0.00% |
0 / 12 |
1260 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getHistoryType | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
formatTimestamp | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 | |||
formatAnchorsAsPipeList | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
90 | |||
getDiffAnchor | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getDiffPrevAnchor | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getDiffCurAnchor | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getHistAnchor | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
changeSeparator | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDescription | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getDescriptionParams | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
formatDescription | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getTitleLink | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
30 |
1 | <?php |
2 | |
3 | namespace Flow\Formatter; |
4 | |
5 | use Flow\Container; |
6 | use Flow\FlowActions; |
7 | use Flow\Model\Anchor; |
8 | use Flow\Model\PostRevision; |
9 | use Flow\RevisionActionPermissions; |
10 | use MediaWiki\Context\IContextSource; |
11 | use MediaWiki\Html\Html; |
12 | use MediaWiki\MediaWikiServices; |
13 | use MediaWiki\Message\Message; |
14 | |
15 | /** |
16 | * This is a "utility" class that might come in useful to generate |
17 | * some output per Flow entry, e.g. for RecentChanges, Contributions, ... |
18 | * These share a lot of common characteristics (like displaying a date, links to |
19 | * the posts, some description of the action, ...) |
20 | * |
21 | * Just extend from this class to use these common util methods, and make sure |
22 | * to pass the correct parameters to these methods. Basically, you'll need to |
23 | * create a new method that'll accept the objects for your specific |
24 | * implementation (like ChangesList & RecentChange objects for RecentChanges, or |
25 | * ContribsPager and a DB row for Contributions). From those rows, you should be |
26 | * able to derive the objects needed to pass to these utility functions (mainly |
27 | * Workflow, AbstractRevision, Title, User and Language objects) and return the |
28 | * output. |
29 | * |
30 | * For implementation examples, check Flow\RecentChanges\Formatter or |
31 | * Flow\Contributions\Formatter. |
32 | */ |
33 | abstract class AbstractFormatter { |
34 | /** |
35 | * @var RevisionActionPermissions |
36 | */ |
37 | protected $permissions; |
38 | |
39 | /** |
40 | * @var RevisionFormatter |
41 | */ |
42 | protected $serializer; |
43 | |
44 | public function __construct( |
45 | RevisionActionPermissions $permissions, |
46 | RevisionFormatter $serializer |
47 | ) { |
48 | $this->permissions = $permissions; |
49 | $this->serializer = $serializer; |
50 | } |
51 | |
52 | abstract protected function getHistoryType(); |
53 | |
54 | /** |
55 | * @see RevisionFormatter::buildLinks |
56 | * @see RevisionFormatter::getDateFormats |
57 | * |
58 | * @param array $data Expects an array with keys 'dateFormats', 'isModeratedNotLocked' |
59 | * and 'links'. The former should be an array having the key $key being |
60 | * tossed in here; the latter an array of links in the [key => [href, msg]] |
61 | * format, where 'key' corresponds with a $linksKeys value. The central is |
62 | * a boolean. |
63 | * @param string $key Date format to use - any of the keys in the array |
64 | * returned by RevisionFormatter::getDateFormats |
65 | * @param string[] $linkKeys Link key(s) to use as link for the timestamp; |
66 | * the first available key will be used (but accepts an array of multiple |
67 | * keys for when different kinds of data are tossed in, which may not all |
68 | * have the same kind of links available) |
69 | * @return string HTML |
70 | * @return-taint escaped |
71 | */ |
72 | protected function formatTimestamp( |
73 | array $data, |
74 | $key = 'timeAndDate', |
75 | array $linkKeys = [ 'header-revision', 'topic-revision', 'post-revision', 'summary-revision' ] |
76 | ) { |
77 | // Format timestamp: add link |
78 | $formattedTime = $data['dateFormats'][$key]; |
79 | |
80 | // Find the first available link to attach to the timestamp |
81 | $anchor = null; |
82 | foreach ( $linkKeys as $linkKey ) { |
83 | if ( isset( $data['links'][$linkKey] ) ) { |
84 | $anchor = $data['links'][$linkKey]; |
85 | break; |
86 | } |
87 | } |
88 | |
89 | $class = [ 'mw-changeslist-date' ]; |
90 | if ( $data['isModeratedNotLocked'] ) { |
91 | $class[] = 'history-deleted'; |
92 | } |
93 | |
94 | if ( $anchor instanceof Anchor ) { |
95 | return Html::rawElement( |
96 | 'span', |
97 | [ 'class' => $class ], |
98 | $anchor->toHtml( $formattedTime ) |
99 | ); |
100 | } else { |
101 | return Html::element( 'span', [ 'class' => $class ], $formattedTime ); |
102 | } |
103 | } |
104 | |
105 | /** |
106 | * Generate HTML for "(foo | bar | baz)" based on the links provided by |
107 | * RevisionFormatter. |
108 | * |
109 | * @param (Anchor|Message)[] $links |
110 | * @param IContextSource $ctx |
111 | * @param string[]|null $request List of link names to be allowed in result output |
112 | * @return string Html valid for user output |
113 | */ |
114 | protected function formatAnchorsAsPipeList( |
115 | array $links, |
116 | IContextSource $ctx, |
117 | ?array $request = null |
118 | ) { |
119 | if ( $request === null ) { |
120 | $request = array_keys( $links ); |
121 | } elseif ( !$request ) { |
122 | // empty array was passed |
123 | return ''; |
124 | } |
125 | $have = array_combine( $request, $request ); |
126 | |
127 | $formatted = []; |
128 | foreach ( $links as $key => $link ) { |
129 | if ( isset( $have[$key] ) ) { |
130 | if ( $link instanceof Anchor ) { |
131 | $formatted[] = $link->toHtml(); |
132 | } elseif ( $link instanceof Message ) { |
133 | $formatted[] = $link->escaped(); |
134 | } |
135 | } |
136 | } |
137 | |
138 | if ( $formatted ) { |
139 | $content = $ctx->getLanguage()->pipeList( $formatted ); |
140 | if ( $content ) { |
141 | return $ctx->msg( 'parentheses' )->rawParams( $content )->escaped(); |
142 | } |
143 | } |
144 | |
145 | return ''; |
146 | } |
147 | |
148 | /** |
149 | * Gets the "diff" link; linking to the diff against the previous revision, |
150 | * in a format that can be wrapped in an array and passed to |
151 | * formatLinksAsPipeList. |
152 | * |
153 | * @param Anchor[] $input |
154 | * @param IContextSource $ctx |
155 | * @return Anchor|Message |
156 | */ |
157 | protected function getDiffAnchor( array $input, IContextSource $ctx ) { |
158 | if ( !isset( $input['diff'] ) ) { |
159 | // plain text with no link |
160 | return $ctx->msg( 'diff' ); |
161 | } |
162 | |
163 | return $input['diff']; |
164 | } |
165 | |
166 | /** |
167 | * Gets the "prev" link; linking to the diff against the previous revision, |
168 | * in a format that can be wrapped in an array and passed to |
169 | * formatLinksAsPipeList. |
170 | * |
171 | * @param Anchor[] $input |
172 | * @param IContextSource $ctx |
173 | * @return Anchor|Message |
174 | */ |
175 | protected function getDiffPrevAnchor( array $input, IContextSource $ctx ) { |
176 | if ( !isset( $input['diff-prev'] ) ) { |
177 | // plain text with no link |
178 | return $ctx->msg( 'last' ); |
179 | } |
180 | |
181 | return $input['diff-prev']; |
182 | } |
183 | |
184 | /** |
185 | * Gets the "cur" link; linking to the diff against the current revision, |
186 | * in a format that can be wrapped in an array and passed to |
187 | * formatLinksAsPipeList. |
188 | * |
189 | * @param Anchor[] $input |
190 | * @param IContextSource $ctx |
191 | * @return Anchor|Message |
192 | */ |
193 | protected function getDiffCurAnchor( array $input, IContextSource $ctx ) { |
194 | if ( !isset( $input['diff-cur'] ) ) { |
195 | // plain text with no link |
196 | return $ctx->msg( 'cur' ); |
197 | } |
198 | |
199 | return $input['diff-cur']; |
200 | } |
201 | |
202 | /** |
203 | * Gets the "hist" link; linking to the history of a certain element, in a |
204 | * format that can be wrapped in an array and passed to |
205 | * formatLinksAsPipeList. |
206 | * |
207 | * @param Anchor[] $input |
208 | * @param IContextSource $ctx |
209 | * @return Anchor|Message |
210 | */ |
211 | protected function getHistAnchor( array $input, IContextSource $ctx ) { |
212 | $anchor = $input['post-history'] ?? |
213 | $input['topic-history'] ?? |
214 | $input['board-history'] ?? null; |
215 | |
216 | if ( $anchor instanceof Anchor ) { |
217 | $anchor->setMessage( $ctx->msg( 'hist' ) ); |
218 | return $anchor; |
219 | } else { |
220 | // plain text with no link |
221 | return $ctx->msg( 'hist' ); |
222 | } |
223 | } |
224 | |
225 | /** |
226 | * @return string Html valid for user output |
227 | */ |
228 | protected function changeSeparator() { |
229 | return ' <span class="mw-changeslist-separator">. .</span> '; |
230 | } |
231 | |
232 | /** |
233 | * @param array $data |
234 | * @param IContextSource $ctx |
235 | * @return Message |
236 | */ |
237 | protected function getDescription( array $data, IContextSource $ctx ) { |
238 | // Build description message, piggybacking on history i18n |
239 | $changeType = $data['changeType']; |
240 | $actions = $this->permissions->getActions(); |
241 | |
242 | $key = $actions->getValue( $changeType, 'history', 'i18n-message' ); |
243 | // find specialized message for this particular formatter type |
244 | // E.g. the -irc messages. |
245 | $msg = $ctx->msg( $key . '-' . $this->getHistoryType() ); |
246 | if ( !$msg->exists() ) { |
247 | // fallback to default msg |
248 | $msg = $ctx->msg( $key ); |
249 | } |
250 | |
251 | return $msg->params( ...$this->getDescriptionParams( $data, $actions, $changeType ) ); |
252 | } |
253 | |
254 | /** |
255 | * @param array $data |
256 | * @param FlowActions $actions |
257 | * @param string $changeType |
258 | * @return array |
259 | */ |
260 | protected function getDescriptionParams( array $data, FlowActions $actions, $changeType ) { |
261 | $source = $actions->getValue( $changeType, 'history', 'i18n-params' ); |
262 | $params = []; |
263 | foreach ( $source as $param ) { |
264 | if ( isset( $data['properties'][$param] ) ) { |
265 | $params[] = $data['properties'][$param]; |
266 | } else { |
267 | wfDebugLog( 'Flow', __METHOD__ . |
268 | ": Missing expected parameter $param for change type $changeType" ); |
269 | $params[] = ''; |
270 | } |
271 | } |
272 | |
273 | return $params; |
274 | } |
275 | |
276 | /** |
277 | * Generate an HTML revision description. |
278 | * |
279 | * @param array $data |
280 | * @param IContextSource $ctx |
281 | * @return string Html valid for user output |
282 | */ |
283 | protected function formatDescription( array $data, IContextSource $ctx ) { |
284 | $msg = $this->getDescription( $data, $ctx ); |
285 | return '<span class="plainlinks">' . $msg->parse() . '</span>'; |
286 | } |
287 | |
288 | /** |
289 | * Returns HTML links to the page title and (if the action is topic-related) |
290 | * the topic. |
291 | * |
292 | * @param array $data |
293 | * @param FormatterRow $row |
294 | * @param IContextSource $ctx |
295 | * @return string HTML linking to topic & board |
296 | */ |
297 | protected function getTitleLink( array $data, FormatterRow $row, IContextSource $ctx ) { |
298 | $ownerLink = MediaWikiServices::getInstance()->getLinkRenderer()->makeLink( |
299 | $row->workflow->getOwnerTitle(), |
300 | null, |
301 | [ 'class' => 'mw-title' ] |
302 | ); |
303 | |
304 | if ( !isset( $data['links']['topic'] ) || !$row->revision instanceof PostRevision ) { |
305 | return $ownerLink; |
306 | } |
307 | /** @var Anchor $topic */ |
308 | $topic = $data['links']['topic']; |
309 | |
310 | // generated link has generic link text, should be actual topic title |
311 | // @phan-suppress-next-line PhanUndeclaredMethod $row->revision being PostRevision is not inferred |
312 | $root = $row->revision->getRootPost(); |
313 | if ( $root && $this->permissions->isAllowed( $root, 'view' ) ) { |
314 | $topicDisplayText = Container::get( 'templating' ) |
315 | ->getContent( $root, 'topic-title-plaintext' ); |
316 | $topic->setMessage( $topicDisplayText ); |
317 | } |
318 | |
319 | return $ctx->msg( 'flow-rc-topic-of-board' )->rawParams( |
320 | $topic->toHtml(), |
321 | $ownerLink |
322 | )->escaped(); |
323 | } |
324 | } |