Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
6.90% |
6 / 87 |
|
20.00% |
1 / 5 |
CRAP | |
0.00% |
0 / 1 |
PFFormLinker | |
6.90% |
6 / 87 |
|
20.00% |
1 / 5 |
707.72 | |
0.00% |
0 / 1 |
getDefaultForm | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
createPageWithForm | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
20 | |||
setBrokenLink | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
42 | |||
getDefaultFormsForPage | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
182 | |||
getDefaultFormForNamespace | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | use MediaWiki\Linker\LinkRenderer; |
4 | use MediaWiki\MediaWikiServices; |
5 | |
6 | /** |
7 | * Gets the form(s) used to edit a page, both for existing pages and for |
8 | * not-yet-created, red-linked pages. |
9 | * |
10 | * @author Yaron Koren |
11 | * @file |
12 | * @ingroup PF |
13 | */ |
14 | |
15 | class PFFormLinker { |
16 | |
17 | private static $formPerNamespace = []; |
18 | |
19 | static function getDefaultForm( ?Title $title ): ?string { |
20 | // The title passed in can be null in at least one |
21 | // situation: if the "namespace page" is being checked, and |
22 | // the project namespace alias contains any non-ASCII |
23 | // characters. There may be other cases too. |
24 | // If that happens, just exit. |
25 | if ( $title === null ) { |
26 | return null; |
27 | } |
28 | |
29 | $props = MediaWikiServices::getInstance()->getPageProps() |
30 | ->getProperties( $title, [ 'PFDefaultForm', 'SFDefaultForm' ] ); |
31 | $pageID = $title->getArticleID(); |
32 | |
33 | // Keep backward compatibility with the page property name for Semantic Forms. |
34 | return $props[$pageID]['PFDefaultForm'] ?? $props[$pageID]['SFDefaultForm'] ?? null; |
35 | } |
36 | |
37 | public static function createPageWithForm( $title, $formName, $inQueryArr ) { |
38 | /** @var PFFormPrinter $wgPageFormsFormPrinter */ |
39 | global $wgPageFormsFormPrinter, $wgOut; |
40 | |
41 | $wgOut->enableOOUI(); |
42 | |
43 | $formTitle = Title::makeTitleSafe( PF_NS_FORM, $formName ); |
44 | $formDefinition = PFUtils::getPageText( $formTitle ); |
45 | $preloadContent = null; |
46 | |
47 | // Allow outside code to set/change the preloaded text. |
48 | MediaWikiServices::getInstance()->getHookContainer()->run( 'PageForms::EditFormPreloadText', [ &$preloadContent, $title, $formTitle ] ); |
49 | |
50 | list( $formText, $pageText, $formPageTitle, $generatedPageName ) = |
51 | $wgPageFormsFormPrinter->formHTML( |
52 | $formDefinition, false, false, null, $preloadContent, |
53 | 'Some very long page name that will hopefully never get created ABCDEF123', |
54 | null, PFFormPrinter::CONTEXT_AUTOCREATE, $inQueryArr |
55 | ); |
56 | $params = []; |
57 | |
58 | // Get user "responsible" for all auto-generated |
59 | // pages from red links. |
60 | $userID = 1; |
61 | global $wgPageFormsAutoCreateUser; |
62 | if ( $wgPageFormsAutoCreateUser !== null ) { |
63 | $user = User::newFromName( $wgPageFormsAutoCreateUser ); |
64 | if ( $user !== null ) { |
65 | $userID = $user->getId(); |
66 | } |
67 | } |
68 | $params['user_id'] = $userID; |
69 | $params['page_text'] = $pageText; |
70 | $job = new PFCreatePageJob( $title, $params ); |
71 | |
72 | $jobs = [ $job ]; |
73 | if ( method_exists( MediaWikiServices::class, 'getJobQueueGroup' ) ) { |
74 | // MW 1.37+ |
75 | MediaWikiServices::getInstance()->getJobQueueGroup()->push( $jobs ); |
76 | } else { |
77 | JobQueueGroup::singleton()->push( $jobs ); |
78 | } |
79 | } |
80 | |
81 | /** |
82 | * Called by the HtmlPageLinkRendererEnd hook. |
83 | * The $target argument is listed in the documentation as being of type |
84 | * LinkTarget, but in practice it seems to sometimes be of type Title |
85 | * and sometimes of type TitleValue. So we just leave out a type |
86 | * declaration for that argument in the header. |
87 | * |
88 | * @param LinkRenderer $linkRenderer |
89 | * @param Title $target |
90 | * @param bool $isKnown |
91 | * @param string &$text |
92 | * @param array &$attribs |
93 | * @param bool &$ret |
94 | * @return true |
95 | */ |
96 | static function setBrokenLink( LinkRenderer $linkRenderer, $target, $isKnown, &$text, &$attribs, &$ret ) { |
97 | global $wgContentNamespaces; |
98 | global $wgPageFormsLinkAllRedLinksToForms; |
99 | |
100 | // If it's not a broken (red) link, exit. |
101 | if ( $isKnown ) { |
102 | return true; |
103 | } |
104 | |
105 | $namespace = $target->getNamespace(); |
106 | |
107 | // Quick check. |
108 | if ( $namespace == NS_SPECIAL ) { |
109 | return true; |
110 | } |
111 | |
112 | if ( self::getDefaultFormForNamespace( $namespace ) !== null ) { |
113 | $title = Title::newFromLinkTarget( $target ); |
114 | $attribs['href'] = $title->getLinkURL( [ 'action' => 'formedit', 'redlink' => '1' ] ); |
115 | return true; |
116 | } |
117 | |
118 | // If there's no default form, keep going only if we're |
119 | // modifying "all" red links, and this is a link to a |
120 | // content namespace. |
121 | if ( !$wgPageFormsLinkAllRedLinksToForms || |
122 | !in_array( $namespace, $wgContentNamespaces ) ) { |
123 | return true; |
124 | } |
125 | |
126 | // We're still here - change the link. |
127 | // The class of $target can be either Title or |
128 | // TitleValue. |
129 | $title = Title::newFromLinkTarget( $target ); |
130 | $attribs['href'] = $title->getLinkURL( [ 'action' => 'formedit', 'redlink' => '1' ] ); |
131 | |
132 | return true; |
133 | } |
134 | |
135 | /** |
136 | * Get the form(s) used to edit this page - either: |
137 | * - the default form(s) for the page itself, if there are any; or |
138 | * - the default form(s) for a category that this article belongs to, |
139 | * if there are any; or |
140 | * - the default form(s) for the article's namespace, if there are any. |
141 | * @param Title $title |
142 | * @return array |
143 | */ |
144 | static function getDefaultFormsForPage( $title ) { |
145 | // See if the page itself has a default form (or forms), and |
146 | // return it/them if so. |
147 | // (Disregard category pages for this check.) |
148 | if ( $title->getNamespace() != NS_CATEGORY ) { |
149 | $default_form = self::getDefaultForm( $title ); |
150 | if ( $default_form === '' ) { |
151 | // A call to "{{#default_form:}}" (i.e., no form |
152 | // specified) should cancel any inherited forms. |
153 | return []; |
154 | } elseif ( $default_form !== null ) { |
155 | return [ $default_form ]; |
156 | } |
157 | } |
158 | |
159 | // If this is not a category page, look for a default form |
160 | // for its parent category or categories. |
161 | $namespace = $title->getNamespace(); |
162 | if ( NS_CATEGORY !== $namespace ) { |
163 | $default_forms = []; |
164 | $categories = PFValuesUtils::getCategoriesForPage( $title ); |
165 | foreach ( $categories as $category ) { |
166 | if ( class_exists( 'PSSchema' ) ) { |
167 | // Check the Page Schema, if one exists. |
168 | $psSchema = new PSSchema( $category ); |
169 | if ( $psSchema->isPSDefined() ) { |
170 | $formName = PFPageSchemas::getFormName( $psSchema ); |
171 | if ( $formName !== null ) { |
172 | $default_forms[] = $formName; |
173 | } |
174 | } |
175 | } |
176 | $categoryPage = Title::makeTitleSafe( NS_CATEGORY, $category ); |
177 | $defaultFormForCategory = self::getDefaultForm( $categoryPage ); |
178 | if ( $defaultFormForCategory != '' ) { |
179 | $default_forms[] = $defaultFormForCategory; |
180 | } |
181 | } |
182 | if ( count( $default_forms ) > 0 ) { |
183 | // It is possible for two categories to have the same default form, so purge any |
184 | // duplicates from the array to avoid a "more than one default form" warning. |
185 | return array_unique( $default_forms ); |
186 | } |
187 | } |
188 | |
189 | // All that's left is checking for the namespace. If this is |
190 | // a subpage, exit out - default forms for namespaces don't |
191 | // apply to subpages. |
192 | if ( $title->isSubpage() ) { |
193 | return []; |
194 | } |
195 | |
196 | $default_form = self::getDefaultFormForNamespace( $namespace ); |
197 | if ( $default_form != '' ) { |
198 | return [ $default_form ]; |
199 | } |
200 | |
201 | return []; |
202 | } |
203 | |
204 | public static function getDefaultFormForNamespace( $namespace ) { |
205 | if ( array_key_exists( $namespace, self::$formPerNamespace ) ) { |
206 | return self::$formPerNamespace[$namespace]; |
207 | } |
208 | |
209 | if ( NS_MAIN === $namespace ) { |
210 | // If it's in the main (blank) namespace, check for the |
211 | // file named with the word for "Main" in this language. |
212 | $namespace_label = wfMessage( 'pf_blank_namespace' )->inContentLanguage()->text(); |
213 | } else { |
214 | $namespace_labels = PFUtils::getContLang()->getNamespaces(); |
215 | if ( !array_key_exists( $namespace, $namespace_labels ) ) { |
216 | // This can happen if it's a custom namespace that |
217 | // was not entirely correctly declared. |
218 | self::$formPerNamespace[$namespace] = null; |
219 | return null; |
220 | } |
221 | $namespace_label = $namespace_labels[$namespace]; |
222 | } |
223 | |
224 | $namespacePage = Title::makeTitleSafe( NS_PROJECT, $namespace_label ); |
225 | $defaultForm = self::getDefaultForm( $namespacePage ); |
226 | self::$formPerNamespace[$namespace] = $defaultForm; |
227 | return $defaultForm; |
228 | } |
229 | } |