Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
84.00% |
21 / 25 |
|
20.00% |
1 / 5 |
CRAP | |
0.00% |
0 / 1 |
SlotDiffRenderer | |
84.00% |
21 / 25 |
|
20.00% |
1 / 5 |
18.18 | |
0.00% |
0 / 1 |
getDiff | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
localizeDiff | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getTablePrefix | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
addModules | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getExtraCacheKeys | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
normalizeContents | |
100.00% |
21 / 21 |
|
100.00% |
1 / 1 |
13 |
1 | <?php |
2 | /** |
3 | * Renders a diff for a single slot. |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup DifferenceEngine |
22 | */ |
23 | |
24 | use MediaWiki\Context\IContextSource; |
25 | use MediaWiki\Output\OutputPage; |
26 | use MediaWiki\Title\Title; |
27 | use Wikimedia\Assert\Assert; |
28 | |
29 | /** |
30 | * Renders a diff for a single slot (that is, a diff between two content objects). |
31 | * |
32 | * Callers should obtain instances of this class by invoking ContentHandler::getSlotDiffRenderer |
33 | * on the content handler of the new content object (ie. the one shown on the right side |
34 | * of the diff), or of the old one if the new one does not exist. |
35 | * |
36 | * The default implementation just does a text diff on the native text representation. |
37 | * Content handler extensions can subclass this to provide a more appropriate diff method by |
38 | * overriding ContentHandler::getSlotDiffRendererInternal. Other extensions that want to interfere |
39 | * with diff generation in some way can use the GetSlotDiffRenderer hook. |
40 | * |
41 | * @stable to extend |
42 | * @ingroup DifferenceEngine |
43 | */ |
44 | abstract class SlotDiffRenderer { |
45 | |
46 | /** |
47 | * Get a diff between two content objects. One of them might be null (meaning a slot was |
48 | * created or removed), but both cannot be. $newContent (or if it's null then $oldContent) |
49 | * must have the same content model that was used to obtain this diff renderer. |
50 | * @param Content|null $oldContent |
51 | * @param Content|null $newContent |
52 | * @return string HTML. One or more <tr> tags, or an empty string if the inputs are identical. |
53 | * @throws IncompatibleDiffTypesException |
54 | */ |
55 | abstract public function getDiff( Content $oldContent = null, Content $newContent = null ); |
56 | |
57 | /** |
58 | * Localize language-independent text returned by getDiff(), making it |
59 | * suitable for display. Subclasses overriding this should arrange for |
60 | * injection of a MessageLocalizer. |
61 | * |
62 | * @param string $diff |
63 | * @param array $options Associative array of options: |
64 | * - reducedLineNumbers: If true, remove "line 1" but allow other line numbers |
65 | * @return string |
66 | */ |
67 | public function localizeDiff( string $diff, array $options = [] ) { |
68 | return $diff; |
69 | } |
70 | |
71 | /** |
72 | * Get the content to add above the main diff table. |
73 | * |
74 | * @since 1.41 |
75 | * @param IContextSource $context |
76 | * @param Title $newTitle |
77 | * @return (string|null)[] An array of HTML fragments to assemble into the prefix |
78 | * area. They will be deduplicated and sorted by key. |
79 | */ |
80 | public function getTablePrefix( IContextSource $context, Title $newTitle ): array { |
81 | return []; |
82 | } |
83 | |
84 | /** |
85 | * Add modules needed for correct styling/behavior of the diff. |
86 | * @stable to override |
87 | * @param OutputPage $output |
88 | */ |
89 | public function addModules( OutputPage $output ) { |
90 | } |
91 | |
92 | /** |
93 | * Return any extra keys to split the diff cache by. |
94 | * @stable to override |
95 | * @return string[] |
96 | */ |
97 | public function getExtraCacheKeys() { |
98 | return []; |
99 | } |
100 | |
101 | /** |
102 | * Helper method to normalize the input of getDiff(). |
103 | * Verifies that at least one of $oldContent and $newContent is not null, verifies that |
104 | * they are instances of one of the allowed classes (if provided), and replaces null with |
105 | * empty content. |
106 | * @param Content|null &$oldContent |
107 | * @param Content|null &$newContent |
108 | * @param string|array|null $allowedClasses |
109 | * @throws IncompatibleDiffTypesException |
110 | */ |
111 | protected function normalizeContents( |
112 | Content &$oldContent = null, Content &$newContent = null, $allowedClasses = null |
113 | ) { |
114 | if ( !$oldContent && !$newContent ) { |
115 | throw new InvalidArgumentException( '$oldContent and $newContent cannot both be null' ); |
116 | } |
117 | |
118 | if ( $allowedClasses ) { |
119 | if ( is_string( $allowedClasses ) ) { |
120 | $allowedClasses = explode( '|', $allowedClasses ); |
121 | } |
122 | $allowedClassesOrNull = array_merge( $allowedClasses, [ 'null' ] ); |
123 | |
124 | // The new content (or the old one if the new one is null) must always match the renderer |
125 | // since the ContentHandler of that model should be used to create it |
126 | Assert::parameterType( $allowedClassesOrNull, $newContent, '$newContent' ); |
127 | if ( !$newContent ) { |
128 | Assert::parameterType( $allowedClassesOrNull, $oldContent, '$oldContent' ); |
129 | } |
130 | |
131 | // If there are two content objects, the old one can be arbitrary as it is possible |
132 | // to generate a diff between any two revisions; so an incompatible model should be |
133 | // handled as a user error, not a logic error. |
134 | if ( $oldContent && $newContent ) { |
135 | $allowed = false; |
136 | foreach ( $allowedClasses as $class ) { |
137 | if ( $oldContent instanceof $class ) { |
138 | $allowed = true; |
139 | break; |
140 | } |
141 | } |
142 | if ( !$allowed ) { |
143 | throw new IncompatibleDiffTypesException( $oldContent->getModel(), $newContent->getModel() ); |
144 | } |
145 | } |
146 | } |
147 | |
148 | if ( !$oldContent ) { |
149 | $oldContent = $newContent->getContentHandler()->makeEmptyContent(); |
150 | } elseif ( !$newContent ) { |
151 | $newContent = $oldContent->getContentHandler()->makeEmptyContent(); |
152 | } |
153 | } |
154 | |
155 | } |