Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 66 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
Logic | |
0.00% |
0 / 66 |
|
0.00% |
0 / 3 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
setupForParse | |
0.00% |
0 / 42 |
|
0.00% |
0 / 1 |
182 | |||
addSubpageHandlerToOutput | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
56 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\TemplateSandbox; |
4 | |
5 | use Content; |
6 | use InvalidArgumentException; |
7 | use MediaWiki\Linker\LinkTarget; |
8 | use MediaWiki\MediaWikiServices; |
9 | use MediaWiki\Output\OutputPage; |
10 | use MediaWiki\Page\PageReference; |
11 | use MediaWiki\Revision\MutableRevisionRecord; |
12 | use MediaWiki\Revision\SlotRecord; |
13 | use MediaWiki\Title\Title; |
14 | use ParserOptions; |
15 | use RequestContext; |
16 | use Wikimedia\ScopedCallback; |
17 | |
18 | /** |
19 | * Business logic class for TemplateSandbox |
20 | */ |
21 | class Logic { |
22 | private static $counter = 0; |
23 | |
24 | /** Prefixes to search for sandbox templates */ |
25 | private $prefixes = []; |
26 | |
27 | /** Title to replace with $content */ |
28 | private $title = null; |
29 | |
30 | /** Content to replace $title */ |
31 | private $content = null; |
32 | |
33 | /** |
34 | * @param string[] $prefixes Title prefixes to search for sandbox templates |
35 | * @param Title|null $title Title to replace with 'content' |
36 | * @param Content|null $content Content to use to replace 'title' |
37 | */ |
38 | public function __construct( $prefixes, $title, $content ) { |
39 | if ( ( $title === null ) !== ( $content === null ) ) { |
40 | throw new InvalidArgumentException( '$title and $content must both be given or both be null' ); |
41 | } |
42 | |
43 | $this->prefixes = $prefixes; |
44 | $this->title = $title; |
45 | $this->content = $content; |
46 | } |
47 | |
48 | /** |
49 | * Set up a ParserOptions for TemplateSandbox operation. |
50 | * @param ParserOptions $popt |
51 | * @return ScopedCallback to uninstall |
52 | */ |
53 | public function setupForParse( ParserOptions $popt ) { |
54 | $hookContainer = MediaWikiServices::getInstance()->getHookContainer(); |
55 | |
56 | $inHook = false; |
57 | $hookReset = $hookContainer->scopedRegister( 'TitleExists', function ( $title, &$exists ) use ( &$inHook ) { |
58 | if ( $exists || $inHook ) { |
59 | return; |
60 | } |
61 | $inHook = true; |
62 | $titleText = $title->getPrefixedText(); |
63 | try { |
64 | if ( $this->title && $this->title->equals( $title ) ) { |
65 | $exists = true; |
66 | return; |
67 | } |
68 | |
69 | foreach ( $this->prefixes as $prefix ) { |
70 | $newtitle = Title::newFromText( $prefix . '/' . $titleText ); |
71 | if ( $newtitle instanceof Title && $newtitle->exists() ) { |
72 | $exists = true; |
73 | return; |
74 | } |
75 | } |
76 | } finally { |
77 | $inHook = false; |
78 | } |
79 | } ); |
80 | |
81 | $oldCurrentRevisionRecordCallback = $popt->setCurrentRevisionRecordCallback( |
82 | function ( $title, $parser = false ) use ( &$oldCurrentRevisionRecordCallback ) { |
83 | if ( $this->title && $this->title->equals( $title ) ) { |
84 | $user = RequestContext::getMain()->getUser(); |
85 | $revRecord = new MutableRevisionRecord( $title ); |
86 | $revRecord->setUser( $user ); |
87 | $revRecord->setContent( |
88 | SlotRecord::MAIN, |
89 | $this->content |
90 | ); |
91 | $revRecord->setParentId( $title->getLatestRevID() ); |
92 | return $revRecord; |
93 | } |
94 | |
95 | foreach ( $this->prefixes as $prefix ) { |
96 | $newtitle = Title::newFromText( $prefix . '/' . $title->getPrefixedText() ); |
97 | if ( $newtitle instanceof Title && $newtitle->exists() ) { |
98 | $title = $newtitle; |
99 | break; |
100 | } |
101 | } |
102 | return call_user_func( $oldCurrentRevisionRecordCallback, $title, $parser ); |
103 | } |
104 | ); |
105 | |
106 | MediaWikiServices::getInstance()->getLinkCache()->clear(); |
107 | |
108 | return new ScopedCallback( static function () use ( $hookReset ) { |
109 | ScopedCallback::consume( $hookReset ); |
110 | MediaWikiServices::getInstance()->getLinkCache()->clear(); |
111 | } ); |
112 | } |
113 | |
114 | /** |
115 | * Add a handler for sandbox subpages to the OutputPage |
116 | * @param array $prefixes |
117 | * @param OutputPage $output |
118 | */ |
119 | public static function addSubpageHandlerToOutput( array $prefixes, OutputPage $output ) { |
120 | $cache = []; |
121 | $output->addContentOverrideCallback( static function ( $title ) use ( $prefixes, &$cache ) { |
122 | /** @var PageReference|LinkTarget $title */ |
123 | $formatter = MediaWikiServices::getInstance()->getTitleFormatter(); |
124 | $titleText = $formatter->getPrefixedText( $title ); |
125 | if ( array_key_exists( $titleText, $cache ) ) { |
126 | return $cache[$titleText]; |
127 | } |
128 | foreach ( $prefixes as $prefix ) { |
129 | $newtitle = Title::newFromText( $prefix . '/' . $titleText ); |
130 | if ( $newtitle instanceof Title && $newtitle->exists() ) { |
131 | $rev = MediaWikiServices::getInstance() |
132 | ->getRevisionLookup() |
133 | ->getRevisionByTitle( $newtitle ); |
134 | $content = $rev ? $rev->getContent( SlotRecord::MAIN ) : null; |
135 | if ( $content ) { |
136 | $cache[$titleText] = $content; |
137 | return $content; |
138 | } |
139 | } |
140 | } |
141 | $cache[$titleText] = null; |
142 | return null; |
143 | } ); |
144 | } |
145 | |
146 | } |