Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
95.13% |
215 / 226 |
|
81.82% |
9 / 11 |
CRAP | |
0.00% |
0 / 1 |
| LinkHolderArray | |
95.56% |
215 / 225 |
|
81.82% |
9 / 11 |
64 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| __destruct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
| merge | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
| isBig | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| clear | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| makeHolder | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
2 | |||
| replace | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| replaceInternal | |
98.77% |
80 / 81 |
|
0.00% |
0 / 1 |
19 | |||
| replaceInterwiki | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
3 | |||
| doVariants | |
89.66% |
78 / 87 |
|
0.00% |
0 / 1 |
29.93 | |||
| replaceText | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Holder of replacement pairs for wiki links |
| 4 | * |
| 5 | * @license GPL-2.0-or-later |
| 6 | * @file |
| 7 | * @ingroup Parser |
| 8 | */ |
| 9 | |
| 10 | namespace MediaWiki\Parser; |
| 11 | |
| 12 | use MediaWiki\HookContainer\HookContainer; |
| 13 | use MediaWiki\HookContainer\HookRunner; |
| 14 | use MediaWiki\Language\ILanguageConverter; |
| 15 | use MediaWiki\Linker\Linker; |
| 16 | use MediaWiki\MainConfigNames; |
| 17 | use MediaWiki\MediaWikiServices; |
| 18 | use MediaWiki\Page\LinkCache; |
| 19 | use MediaWiki\Title\Title; |
| 20 | use Wikimedia\HtmlArmor\HtmlArmor; |
| 21 | |
| 22 | /** |
| 23 | * @internal for using in Parser only. |
| 24 | * |
| 25 | * @ingroup Parser |
| 26 | */ |
| 27 | class LinkHolderArray { |
| 28 | /** @var array<int,array<int,array>> Indexed by numeric namespace and link ids, {@see Parser::nextLinkID} */ |
| 29 | private $internals = []; |
| 30 | /** @var array<int,array> Indexed by numeric link id */ |
| 31 | private $interwikis = []; |
| 32 | /** @var int */ |
| 33 | private $size = 0; |
| 34 | private HookRunner $hookRunner; |
| 35 | |
| 36 | public function __construct( |
| 37 | private Parser $parent, |
| 38 | private ILanguageConverter $languageConverter, |
| 39 | HookContainer $hookContainer, |
| 40 | ) { |
| 41 | $this->hookRunner = new HookRunner( $hookContainer ); |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * Reduce memory usage to reduce the impact of circular references |
| 46 | */ |
| 47 | public function __destruct() { |
| 48 | // @phan-suppress-next-line PhanTypeSuspiciousNonTraversableForeach |
| 49 | foreach ( $this as $name => $_ ) { |
| 50 | unset( $this->$name ); |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Merge another LinkHolderArray into this one |
| 56 | * @param LinkHolderArray $other |
| 57 | */ |
| 58 | public function merge( $other ) { |
| 59 | foreach ( $other->internals as $ns => $entries ) { |
| 60 | $this->size += count( $entries ); |
| 61 | if ( !isset( $this->internals[$ns] ) ) { |
| 62 | $this->internals[$ns] = $entries; |
| 63 | } else { |
| 64 | $this->internals[$ns] += $entries; |
| 65 | } |
| 66 | } |
| 67 | $this->interwikis += $other->interwikis; |
| 68 | } |
| 69 | |
| 70 | /** |
| 71 | * Returns true if the memory requirements of this object are getting large |
| 72 | * @return bool |
| 73 | */ |
| 74 | public function isBig() { |
| 75 | $linkHolderBatchSize = MediaWikiServices::getInstance()->getMainConfig() |
| 76 | ->get( MainConfigNames::LinkHolderBatchSize ); |
| 77 | return $this->size > $linkHolderBatchSize; |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * Clear all stored link holders. |
| 82 | * Make sure you don't have any text left using these link holders, before you call this |
| 83 | */ |
| 84 | public function clear() { |
| 85 | $this->internals = []; |
| 86 | $this->interwikis = []; |
| 87 | $this->size = 0; |
| 88 | } |
| 89 | |
| 90 | /** |
| 91 | * Make a link placeholder. The text returned can be later resolved to a real link with |
| 92 | * replaceLinkHolders(). This is done for two reasons: firstly to avoid further |
| 93 | * parsing of interwiki links, and secondly to allow all existence checks and |
| 94 | * article length checks (for stub links) to be bundled into a single query. |
| 95 | * |
| 96 | * @param Title $nt |
| 97 | * @param string $text |
| 98 | * @param string $trail [optional] |
| 99 | * @param string $prefix [optional] |
| 100 | * @return string |
| 101 | */ |
| 102 | public function makeHolder( Title $nt, $text = '', $trail = '', $prefix = '' ) { |
| 103 | # Separate the link trail from the rest of the link |
| 104 | [ $inside, $trail ] = Linker::splitTrail( $trail ); |
| 105 | |
| 106 | $key = $this->parent->nextLinkID(); |
| 107 | $entry = [ |
| 108 | 'title' => $nt, |
| 109 | 'text' => $prefix . $text . $inside, |
| 110 | 'pdbk' => $nt->getPrefixedDBkey(), |
| 111 | ]; |
| 112 | |
| 113 | $this->size++; |
| 114 | if ( $nt->isExternal() ) { |
| 115 | // Use a globally unique ID to keep the objects mergeable |
| 116 | $this->interwikis[$key] = $entry; |
| 117 | return "<!--IWLINK'\" $key-->{$trail}"; |
| 118 | } else { |
| 119 | $ns = $nt->getNamespace(); |
| 120 | $this->internals[$ns][$key] = $entry; |
| 121 | return "<!--LINK'\" $ns:$key-->{$trail}"; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /** |
| 126 | * Replace <!--LINK--> link placeholders with actual links, in the buffer |
| 127 | * |
| 128 | * @param string &$text |
| 129 | */ |
| 130 | public function replace( &$text ) { |
| 131 | $this->replaceInternal( $text ); |
| 132 | $this->replaceInterwiki( $text ); |
| 133 | } |
| 134 | |
| 135 | /** |
| 136 | * Replace internal links |
| 137 | * @param string &$text |
| 138 | */ |
| 139 | protected function replaceInternal( &$text ) { |
| 140 | if ( !$this->internals ) { |
| 141 | return; |
| 142 | } |
| 143 | |
| 144 | $classes = []; |
| 145 | $services = MediaWikiServices::getInstance(); |
| 146 | $linkCache = $services->getLinkCache(); |
| 147 | $output = $this->parent->getOutput(); |
| 148 | $linkRenderer = $this->parent->getLinkRenderer(); |
| 149 | |
| 150 | $dbr = $services->getConnectionProvider()->getReplicaDatabase(); |
| 151 | |
| 152 | # Sort by namespace |