Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 503
0.00% covered (danger)
0.00%
0 / 28
CRAP
0.00% covered (danger)
0.00%
0 / 1
PFPageSchemas
0.00% covered (danger)
0.00%
0 / 503
0.00% covered (danger)
0.00%
0 / 28
34410
0.00% covered (danger)
0.00%
0 / 1
 createPageSchemasObject
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
462
 createSchemaXMLFromForm
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
272
 createTemplateXMLFromForm
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
42
 createFieldXMLFromForm
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
156
 createPageSectionXMLFromForm
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 createFormInputXMLFromForm
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 getDisplayColor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSchemaDisplayString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSchemaEditingHTML
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
56
 getTemplateEditingHTML
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
12
 getFieldEditingHTML
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
210
 getPageSectionEditingHTML
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
56
 getFormName
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getMainFormInfo
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 getFormFieldInfo
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
90
 getPageSection
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 getPagesToGenerate
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getFieldsFromTemplateSchema
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
72
 generateForm
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
56
 generatePages
0.00% covered (danger)
0.00%
0 / 83
0.00% covered (danger)
0.00%
0 / 1
420
 getSchemaDisplayValues
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 getTemplateValues
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 getTemplateDisplayString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTemplateDisplayValues
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
 getFieldDisplayString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPageSectionDisplayString
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFieldDisplayValues
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
30
 getPageSectionDisplayValues
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3use MediaWiki\MediaWikiServices;
4
5/**
6 * Static functions for Page Forms, for use by the Page Schemas
7 * extension.
8 *
9 * @author Yaron Koren
10 * @author Ankit Garg
11 * @file
12 * @ingroup PF
13 */
14
15class PFPageSchemas extends PSExtensionHandler {
16
17    /**
18     * Creates an object to hold form-wide information, based on an XML
19     * object from the Page Schemas extension.
20     * @param string $tagName
21     * @param SimpleXMLElement $xml
22     * @return string[]|null
23     */
24    public static function createPageSchemasObject( $tagName, $xml ) {
25        $pfarray = [];
26
27        if ( $tagName == "standardInputs" ) {
28            foreach ( $xml->children() as $_ => $child ) {
29                foreach ( $child->children() as $tag => $formelem ) {
30                    if ( $tag == $tagName ) {
31                        foreach ( $formelem->attributes() as $attr => $name ) {
32                            $pfarray[$attr] = (string)$formelem->attributes()->$attr;
33                        }
34                    }
35                }
36                return $pfarray;
37            }
38        }
39
40        if ( $tagName == "pageforms_Form" ) {
41            foreach ( $xml->children() as $tag => $child ) {
42                if ( $tag == $tagName ) {
43                    $formName = (string)$child->attributes()->name;
44                    $pfarray['name'] = $formName;
45                    foreach ( $child->children() as $childTag => $formelem ) {
46                        $pfarray[$childTag] = (string)$formelem;
47                    }
48                    return $pfarray;
49                }
50            }
51        }
52        if ( $tagName == "pageforms_TemplateDetails" ) {
53            foreach ( $xml->children() as $tag => $child ) {
54                if ( $tag == $tagName ) {
55                    foreach ( $child->children() as $childTag => $formelem ) {
56                        $pfarray[$childTag] = (string)$formelem;
57                    }
58                    return $pfarray;
59                }
60            }
61        }
62        if ( $tagName == "pageforms_FormInput" || $tagName == "pageforms_PageSection" ) {
63            foreach ( $xml->children() as $tag => $child ) {
64                if ( $tag == $tagName ) {
65                    foreach ( $child->children() as $prop ) {
66                        if ( $prop->getName() == 'InputType' ) {
67                            $pfarray[$prop->getName()] = (string)$prop;
68                        } else {
69                            if ( (string)$prop->attributes()->name == '' ) {
70                                $pfarray[$prop->getName()] = (string)$prop;
71                            } else {
72                                $pfarray[(string)$prop->attributes()->name] = (string)$prop;
73                            }
74                        }
75                    }
76                    return $pfarray;
77                }
78            }
79        }
80        return null;
81    }
82
83    /**
84     * Creates Page Schemas XML for form-wide information.
85     * @return string
86     */
87    public static function createSchemaXMLFromForm() {
88        global $wgRequest;
89
90        // Quick check: if the "form name" field hasn't been sent,
91        // it means the main "Form" checkbox wasn't selected; don't
92        // create any XML if so.
93        if ( !$wgRequest->getCheck( 'pf_form_name' ) ) {
94            return '';
95        }
96
97        $formName = null;
98        $xml = '';
99        $includeFreeText = false;
100        foreach ( $wgRequest->getValues() as $var => $val ) {
101            $val = str_replace( [ '<', '>' ], [ '&lt;', '&gt;' ], $val );
102            if ( $var == 'pf_form_name' ) {
103                $formName = $val;
104            } elseif ( $var == 'pf_page_name_formula' ) {
105                if ( !empty( $val ) ) {
106                    $val = Xml::escapeTagsOnly( $val );
107                    $xml .= '<PageNameFormula>' . $val . '</PageNameFormula>';
108                }
109            } elseif ( $var == 'pf_create_title' ) {
110                if ( !empty( $val ) ) {
111                    $xml .= '<CreateTitle>' . $val . '</CreateTitle>';
112                }
113            } elseif ( $var == 'pf_edit_title' ) {
114                if ( !empty( $val ) ) {
115                    $xml .= '<EditTitle>' . $val . '</EditTitle>';
116                }
117            } elseif ( $var == 'pf_fi_free_text' && !empty( $val ) ) {
118                $includeFreeText = true;
119                $xml .= '<standardInputs inputFreeText="1" ';
120            } elseif ( $includeFreeText && $var == 'pf_fi_free_text_label' ) {
121                if ( !empty( $val ) ) {
122                    $xml .= 'freeTextLabel="' . Xml::escapeTagsOnly( $val ) . '" ';
123                }
124            }
125        }
126        if ( $includeFreeText ) {
127            $xml .= ' />';
128        }
129        $xml = '<pageforms_Form name="' . $formName . '" >' . $xml;
130        $xml .= '</pageforms_Form>';
131        return $xml;
132    }
133
134    /**
135     * Creates Page Schemas XML from form information on templates.
136     * @return string[]
137     */
138    public static function createTemplateXMLFromForm() {
139        global $wgRequest;
140
141        $xmlPerTemplate = [];
142        $templateNum = -1;
143        $xml = '';
144        foreach ( $wgRequest->getValues() as $var => $val ) {
145            $val = str_replace( [ '<', '>' ], [ '&lt;', '&gt;' ], $val );
146            if ( substr( $var, 0, 18 ) === 'pf_template_label_' ) {
147                $templateNum = substr( $var, 18 );
148                $xml = '<pageforms_TemplateDetails>';
149                if ( !empty( $val ) ) {
150                    $xml .= "<Label>$val</Label>";
151                }
152            } elseif ( substr( $var, 0, 23 ) === 'pf_template_addanother_' ) {
153                if ( !empty( $val ) ) {
154                    $xml .= "<AddAnotherText>$val</AddAnotherText>";
155                }
156                $xml .= '</pageforms_TemplateDetails>';
157                $xmlPerTemplate[$templateNum] = $xml;
158            }
159        }
160        return $xmlPerTemplate;
161    }
162
163    /**
164     * Creates Page Schemas XML for form fields.
165     * @return string[]
166     */
167    public static function createFieldXMLFromForm() {
168        global $wgRequest;
169
170        $xmlPerField = [];
171        $fieldNum = -1;
172        $xml = '';
173        foreach ( $wgRequest->getValues() as $var => $val ) {
174            $val = str_replace( [ '<', '>' ], [ '&lt;', '&gt;' ], $val );
175            if ( substr( $var, 0, 14 ) === 'pf_input_type_' ) {
176                $fieldNum = substr( $var, 14 );
177                $xml = '<pageforms_FormInput>';
178                if ( !empty( $val ) ) {
179                    $xml .= '<InputType>' . $val . '</InputType>';
180                }
181            } elseif ( substr( $var, 0, 14 ) === 'pf_key_values_' ) {
182                $xml .= self::createFormInputXMLFromForm( $val );
183            } elseif ( substr( $var, 0, 14 ) === 'pf_input_befo_' ) {
184                if ( $val !== '' ) {
185                    $xml .= '<TextBeforeField>' . $val . '</TextBeforeField>';
186                }
187            } elseif ( substr( $var, 0, 14 ) === 'pf_input_desc_' ) {
188                if ( $val !== '' ) {
189                    $xml .= '<Description>' . $val . '</Description>';
190                }
191            } elseif ( substr( $var, 0, 18 ) === 'pf_input_desctool_' ) {
192                if ( $val !== '' ) {
193                    $xml .= '<DescriptionTooltipMode>' . $val . '</DescriptionTooltipMode>';
194                }
195            } elseif ( substr( $var, 0, 16 ) === 'pf_input_finish_' ) {
196                // This is a hack.
197                $xml .= '</pageforms_FormInput>';
198                $xmlPerField[$fieldNum] = $xml;
199            }
200        }
201        return $xmlPerField;
202    }
203
204    /**
205     * Creates Page Schemas XML for page sections
206     * @return string[]
207     */
208    public static function createPageSectionXMLFromForm() {
209        global $wgRequest;
210        $xmlPerPageSection = [];
211        $pageSectionNum = -1;
212
213        foreach ( $wgRequest->getValues() as $var => $val ) {
214            $val = str_replace( [ '<', '>' ], [ '&lt;', '&gt;' ], $val );
215            if ( substr( $var, 0, 26 ) == 'pf_pagesection_key_values_' ) {
216                $pageSectionNum = substr( $var, 26 );
217                $xml = "";
218                if ( $val != '' ) {
219                    $xml = '<pageforms_PageSection>';
220                    $xml .= self::createFormInputXMLFromForm( $val );
221                    $xml .= '</pageforms_PageSection>';
222                }
223                $xmlPerPageSection[$pageSectionNum] = $xml;
224            }
225        }
226        return $xmlPerPageSection;
227    }
228
229    static function createFormInputXMLFromForm( $valueFromForm ) {
230        $xml = '';
231        if ( $valueFromForm !== '' ) {
232            // replace the comma substitution character that has no chance of
233            // being included in the values list - namely, the ASCII beep
234            $listSeparator = ',';
235            $key_values_str = str_replace( "\\$listSeparator", "\a", $valueFromForm );
236            $key_values_array = explode( $listSeparator, $key_values_str );
237            foreach ( $key_values_array as $value ) {
238            // replace beep back with comma, trim
239                $value = str_replace( "\a", $listSeparator, trim( $value ) );
240                $param_value = explode( "=", $value, 2 );
241                if ( count( $param_value ) == 2 && $param_value[1] != null ) {
242                    // Handles <Parameter name="size">20</Parameter>
243                    $xml .= '<Parameter name="' . $param_value[0] . '">' . $param_value[1] . '</Parameter>';
244                } else {
245                    // Handles <Parameter name="mandatory" />
246                    $xml .= '<Parameter name="' . $param_value[0] . '"/>';
247                }
248            }
249        }
250        return $xml;
251    }
252
253    public static function getDisplayColor() {
254        return '#CF9';
255    }
256
257    public static function getSchemaDisplayString() {
258        return wfMessage( 'pf-pageschemas-header' )->escaped();
259    }
260
261    public static function getSchemaEditingHTML( $pageSchemaObj ) {
262        $form_array = [];
263        $hasExistingValues = false;
264        if ( $pageSchemaObj !== null ) {
265            $form_array = $pageSchemaObj->getObject( 'pageforms_Form' );
266            if ( $form_array !== null ) {
267                $hasExistingValues = true;
268            }
269        }
270
271        // Get all the values from the page schema.
272        $formName = PageSchemas::getValueFromObject( $form_array, 'name' );
273        $pageNameFormula = PageSchemas::getValueFromObject( $form_array, 'PageNameFormula' );
274        $createTitle = PageSchemas::getValueFromObject( $form_array, 'CreateTitle' );
275        $editTitle = PageSchemas::getValueFromObject( $form_array, 'EditTitle' );
276
277        // Inputs
278        if ( $pageSchemaObj !== null ) {
279            $standardInputs = $pageSchemaObj->getObject( 'standardInputs' );
280            $includeFreeText = isset( $standardInputs['inputFreeText'] ) ? $standardInputs['inputFreeText'] : false;
281        } else {
282            $includeFreeText = true;
283        }
284
285        $freeTextLabel = html_entity_decode( PageSchemas::getValueFromObject( $form_array, 'freeTextLabel' ) );
286
287        $text = "\t<p>" . wfMessage( 'ps-namelabel' )->escaped() . ' ' . Html::input( 'pf_form_name', $formName, 'text', [ 'size' => 15 ] ) . "</p>\n";
288        // The checkbox isn't actually a field in the page schema -
289        // we set it based on whether or not a page formula has been
290        // specified.
291        $twoStepProcessAttrs = [ 'id' => 'pf-two-step-process' ];
292        if ( $pageNameFormula === null ) {
293            $twoStepProcessAttrs['checked'] = true;
294        }
295        $text .= '<p>' . Html::input( 'pf_two_step_process', null, 'checkbox', $twoStepProcessAttrs );
296        $text .= ' Users must enter the page name before getting to the form (default)';
297        $text .= "</p>\n";
298        $text .= '<div class="editSchemaMinorFields">';
299        $text .= "\t<p id=\"pf-page-name-formula\">" . wfMessage( 'pf-pageschemas-pagenameformula' )->escaped() . ' ' .
300            Html::input( 'pf_page_name_formula', $pageNameFormula, 'text', [ 'size' => 30 ] ) . "</p>\n";
301        $text .= "\t<p>" . wfMessage( 'pf-pageschemas-createtitle' )->escaped() . ' ' .
302            Html::input( 'pf_create_title', $createTitle, 'text', [ 'size' => 25 ] ) . "</p>\n";
303        $text .= "\t<p id=\"pf-edit-title\">" . wfMessage( 'pf-pageschemas-edittitle' )->escaped() . ' ' .
304            Html::input( 'pf_edit_title', $editTitle, 'text', [ 'size' => 25 ] ) . "</p>\n";
305
306        // This checkbox went from a default of false to true in PF 5.2.
307        $text .= '<p>';
308        $text .= Html::input( 'pf_fi_free_text', '1', 'checkbox', [ 'id' => 'pf_fi_free_text', 'checked' => $includeFreeText ] ) . ' ';
309        $text .= Html::rawElement( 'label', [ 'for' => 'pf_fi_free_text' ], wfMessage( 'pf-pageschemas-includefreetextinput' )->escaped() );
310        $text .= "</p>";
311
312        if ( empty( $freeTextLabel ) ) {
313            $freeTextLabel = wfMessage( 'pf_form_freetextlabel' )->inContentLanguage()->text();
314        }
315        $text .= '<p>' . wfMessage( 'pf-pageschemas-freetextlabel' )->escaped() . ' ' .
316            Html::input( 'pf_fi_free_text_label', $freeTextLabel, 'text' ) . "</p>";
317
318        $text .= "</div>\n";
319
320        global $wgOut;
321        // Separately, add Javascript for getting the checkbox to
322        // hide certain fields.
323        $wgOut->addModules( [ 'ext.pageforms.PF_PageSchemas' ] );
324
325        return [ $text, $hasExistingValues ];
326    }
327
328    public static function getTemplateEditingHTML( $psTemplate ) {
329        $hasExistingValues = false;
330        $templateLabel = null;
331        $addAnotherText = null;
332        if ( $psTemplate !== null ) {
333            $form_array = $psTemplate->getObject( 'pageforms_TemplateDetails' );
334            if ( $form_array !== null ) {
335                $hasExistingValues = true;
336                $templateLabel = PageSchemas::getValueFromObject( $form_array, 'Label' );
337                $addAnotherText = PageSchemas::getValueFromObject( $form_array, 'AddAnotherText' );
338            }
339        }
340
341        $text = "\t<p>" . wfMessage( 'pf-pageschemas-templatedetailslabel' )->escaped() . "</p>\n";
342        $text .= "\t<p>" . wfMessage( 'exif-label' )->escaped() . ': ' .
343            Html::input( 'pf_template_label_num', $templateLabel, 'text', [ 'size' => 15 ] ) . "</p>\n";
344        $text .= "\t<p>" . 'Text of button to add another instance (default is "Add another"):' . ' ' .
345            Html::input( 'pf_template_addanother_num', $addAnotherText, 'text', [ 'size' => 25 ] ) . "</p>\n";
346
347        return [ $text, $hasExistingValues ];
348    }
349
350    /**
351     * Returns the HTML for inputs to define a single form field,
352     * within the Page Schemas 'edit schema' page.
353     * @param PSTemplateField $psField
354     * @return array
355     */
356    public static function getFieldEditingHTML( $psField ) {
357        $fieldValues = [];
358        $hasExistingValues = false;
359        $inputType = null;
360        $inputDesc = null;
361        $inputDescTooltipMode = null;
362        $inputBeforeText = null;
363        if ( $psField !== null ) {
364            $fieldValues = $psField->getObject( 'pageforms_FormInput' );
365            if ( $fieldValues !== null ) {
366                $hasExistingValues = true;
367                $inputType = PageSchemas::getValueFromObject( $fieldValues, 'InputType' );
368                $inputDesc = PageSchemas::getValueFromObject( $fieldValues, 'Description' );
369                $inputDescTooltipMode = PageSchemas::getValueFromObject( $fieldValues, 'DescriptionTooltipMode' );
370                $inputBeforeText = PageSchemas::getValueFromObject( $fieldValues, 'TextBeforeField' );
371            } else {
372                $fieldValues = [];
373            }
374        }
375
376        global $wgPageFormsFormPrinter;
377        $possibleInputTypes = $wgPageFormsFormPrinter->getAllInputTypes();
378        $inputTypeDropdownHTML = Html::element( 'option', null, null );
379        foreach ( $possibleInputTypes as $possibleInputType ) {
380            $inputTypeOptionAttrs = [];
381            if ( $possibleInputType == $inputType ) {
382                $inputTypeOptionAttrs['selected'] = true;
383            }
384            $inputTypeDropdownHTML .= Html::element( 'option', $inputTypeOptionAttrs, $possibleInputType ) . "\n";
385        }
386        $inputTypeDropdown = Html::rawElement( 'select', [ 'name' => 'pf_input_type_num' ], $inputTypeDropdownHTML );
387        $text = '<p>' . wfMessage( 'pf-pageschemas-inputtype' )->escaped() . ' ' . $inputTypeDropdown . '</p>';
388
389        $text .= "\t" . '<p>' . wfMessage( 'pf-pageschemas-otherparams', 'size=20, mandatory' )->escaped() . '</p>' . "\n";
390        $paramValues = [];
391        foreach ( $fieldValues as $param => $value ) {
392            if ( !empty( $param ) && $param != 'InputType' && $param != 'Description' && $param != 'DescriptionTooltipMode' && $param != 'TextBeforeField' ) {
393                if ( !empty( $value ) ) {
394                    $paramValues[] = $param . '=' . $value;
395                } else {
396                    $paramValues[] = $param;
397                }
398            }
399        }
400        foreach ( $paramValues as $i => $paramAndVal ) {
401            $paramValues[$i] = str_replace( ',', '\,', $paramAndVal );
402        }
403        $param_value_str = implode( ', ', $paramValues );
404        $inputParamsAttrs = [ 'size' => 80 ];
405        $inputParamsInput = Html::input( 'pf_key_values_num', $param_value_str, 'text', $inputParamsAttrs );
406        $text .= "\t<p>$inputParamsInput</p>\n";
407
408        $text .= '<div class="editSchemaMinorFields">' . "\n";
409        $inputBeforeTextPrint = Html::input( 'pf_input_befo_num', $inputBeforeText, 'text', [ 'size' => 80 ] );
410        $text .= "\t<p>Text that will be printed before the field: $inputBeforeTextPrint</p>\n";
411
412        $inputDescriptionLabel = wfMessage( 'pf-pageschemas-inputdescription' )->parse();
413        $inputDescription = Html::input( 'pf_input_desc_num', $inputDesc, 'text', [ 'size' => 80 ] );
414        $inputDescriptionTooltipMode = Html::input( 'pf_input_desctool_num', $inputDescTooltipMode, 'checkbox', [ 'checked' => ( $inputDescTooltipMode ) ? 'checked' : null ] );
415        $useTooltipLabel = wfMessage( 'pf-pageschemas-usetooltip' )->escaped();
416        $text .= "\t<p>$inputDescriptionLabel $inputDescription<br>$inputDescriptionTooltipMode $useTooltipLabel</p>\n";
417
418        // @HACK to make input parsing easier.
419        $text .= Html::hidden( 'pf_input_finish_num', 1 );
420
421        $text .= "</div>\n";
422
423        return [ $text, $hasExistingValues ];
424    }
425
426    public static function getPageSectionEditingHTML( $psPageSection ) {
427        $otherParams = [];
428
429        if ( $psPageSection !== null ) {
430            $otherParams = $psPageSection->getObject( 'pageforms_PageSection' );
431        }
432        $paramValues = [];
433        if ( $otherParams !== null ) {
434            foreach ( $otherParams as $param => $value ) {
435                if ( !empty( $param ) ) {
436                    if ( !empty( $value ) ) {
437                        $paramValues[] = $param . '=' . $value;
438                    } else {
439                        $paramValues[] = $param;
440                    }
441                }
442            }
443        }
444
445        foreach ( $paramValues as $i => $paramAndVal ) {
446            $paramValues[$i] = str_replace( ',', '\,', $paramAndVal );
447        }
448        $param_value_str = implode( ', ', $paramValues );
449        $text = "\t" . '<p>' . wfMessage( 'pf-pageschemas-otherparams', 'rows=10, mandatory' )->escaped() . '</p>' . "\n";
450        $inputParamsInput = Html::input( 'pf_pagesection_key_values_num', $param_value_str, 'text', [ 'size' => 80 ] );
451        $text .= "\t<p>$inputParamsInput</p>\n";
452
453        return $text;
454    }
455
456    public static function getFormName( $pageSchemaObj ) {
457        $mainFormInfo = self::getMainFormInfo( $pageSchemaObj );
458        if ( $mainFormInfo === null || !array_key_exists( 'name', $mainFormInfo ) ) {
459            return null;
460        }
461        return $mainFormInfo['name'];
462    }
463
464    public static function getMainFormInfo( $pageSchemaObj ) {
465        // return $pageSchemaObj->getObject( 'pageforms_Form' );
466        // We don't just call getObject() here, because sometimes, for
467        // some reason, this gets called before PF registers itself
468        // with Page Schemas, which means that getObject() would return
469        // null. Instead, we directly call the code that would have
470        // been called.
471        $xml = $pageSchemaObj->getXML();
472        foreach ( $xml->children() as $tag => $child ) {
473            if ( $tag == "pageforms_Form" ) {
474                $pfarray = [];
475                $formName = (string)$child->attributes()->name;
476                $pfarray['name'] = $formName;
477                foreach ( $child->children() as $childTag => $formelem ) {
478                    if ( $childTag == "standardInputs" ) {
479                        foreach ( $formelem->attributes() as $attr => $value ) {
480                            $pfarray[$attr] = (string)$formelem->attributes()->$attr;
481                        }
482                    } else {
483                        $pfarray[$childTag] = (string)$formelem;
484                    }
485                }
486                return $pfarray;
487            }
488        }
489        return [];
490    }
491
492    public static function getFormFieldInfo( $psTemplate, $template_fields ) {
493        $form_fields = [];
494        $fieldsInfo = $psTemplate->getFields();
495        foreach ( $fieldsInfo as $i => $psField ) {
496            $fieldFormArray = $psField->getObject( 'pageforms_FormInput' );
497            if ( $fieldFormArray === null ) {
498                continue;
499            }
500            $formField = PFFormField::create( $template_fields[$i] );
501            foreach ( $fieldFormArray as $var => $val ) {
502                if ( $var == 'InputType' ) {
503                    $formField->setInputType( $val );
504                } elseif ( $var == 'mandatory' ) {
505                    $formField->setIsMandatory( true );
506                } elseif ( $var == 'hidden' ) {
507                    $formField->setIsHidden( true );
508                } elseif ( $var == 'restricted' ) {
509                    $formField->setIsRestricted( true );
510                } elseif ( in_array( $var, [ 'Description', 'DescriptionTooltipMode', 'TextBeforeField' ] ) ) {
511                    $formField->setDescriptionArg( $var, $val );
512                } else {
513                    $formField->setFieldArg( $var, $val );
514                }
515            }
516            $form_fields[] = $formField;
517        }
518        return $form_fields;
519    }
520
521    public static function getPageSection( $psPageSection ) {
522        $pageSection = PFPageSection::create( $psPageSection->getSectionName() );
523        $pageSectionArray = $psPageSection->getObject( 'pageforms_PageSection' );
524        if ( $pageSectionArray == null ) {
525            return null;
526        }
527
528        foreach ( $pageSectionArray as $var => $val ) {
529            if ( $var == 'mandatory' ) {
530                $pageSection->setIsMandatory( true );
531            } elseif ( $var == 'hidden' ) {
532                $pageSection->setIsHidden( true );
533            } elseif ( $var == 'restricted' ) {
534                $pageSection->setIsRestricted( true );
535            } else {
536                $pageSection->setSectionArgs( $var, $val );
537            }
538        }
539
540        return $pageSection;
541    }
542
543    /**
544     * Return the list of pages that Page Forms could generate from
545     * the current Page Schemas schema.
546     * @param PFPageSchemas $pageSchemaObj
547     * @return Title[]
548     */
549    public static function getPagesToGenerate( $pageSchemaObj ) {
550        $genPageList = [];
551        $psTemplates = $pageSchemaObj->getTemplates();
552        foreach ( $psTemplates as $psTemplate ) {
553            $title = Title::makeTitleSafe( NS_TEMPLATE, $psTemplate->getName() );
554            $genPageList[] = $title;
555        }
556        $form_name = self::getFormName( $pageSchemaObj );
557        if ( $form_name != null ) {
558            $title = Title::makeTitleSafe( PF_NS_FORM, $form_name );
559            $genPageList[] = $title;
560        }
561
562        return $genPageList;
563    }
564
565    /**
566     * Returns an array of PFTemplateField objects, representing the fields
567     * of a template, based on the contents of a <PageSchema> tag.
568     * @param PFTemplate $psTemplate
569     * @return PFTemplateField[]
570     */
571    public static function getFieldsFromTemplateSchema( $psTemplate ) {
572        $psFields = $psTemplate->getFields();
573        $templateFields = [];
574        foreach ( $psFields as $psField ) {
575            if ( defined( 'SMW_VERSION' ) ) {
576                $prop_array = $psField->getObject( 'semanticmediawiki_Property' );
577                $propertyName = PageSchemas::getValueFromObject( $prop_array, 'name' );
578                if ( $prop_array !== null && empty( $propertyName ) ) {
579                    $propertyName = $psField->getName();
580                }
581            } else {
582                $propertyName = null;
583            }
584
585            if ( $psField->getLabel() === '' ) {
586                $fieldLabel = $psField->getName();
587            } else {
588                $fieldLabel = $psField->getLabel();
589            }
590            $templateField = PFTemplateField::create(
591                $psField->getName(),
592                $fieldLabel,
593                $propertyName,
594                $psField->isList(),
595                $psField->getDelimiter(),
596                $psField->getDisplay()
597            );
598            $templateField->setNSText( $psField->getNamespace() );
599            if ( defined( 'CARGO_VERSION' ) ) {
600                $cargoFieldArray = $psField->getObject( 'cargo_Field' );
601                $fieldType = PageSchemas::getValueFromObject( $cargoFieldArray, 'Type' );
602                $allowedValues = PageSchemas::getValueFromObject( $cargoFieldArray, 'AllowedValues' );
603                if ( $fieldType != '' ) {
604                    $templateField->setFieldType( $fieldType );
605                    $templateField->setPossibleValues( $allowedValues );
606                }
607            }
608
609            $templateFields[] = $templateField;
610        }
611        return $templateFields;
612    }
613
614    /**
615     * Creates a form page, when called from the 'generatepages' page
616     * of Page Schemas.
617     * @param string $formName
618     * @param Title $formTitle
619     * @param array $formItems
620     * @param array $formDataFromSchema
621     * @param string $categoryName
622     */
623    public static function generateForm( $formName, $formTitle,
624        $formItems, $formDataFromSchema, $categoryName ) {
625        $includeFreeText = array_key_exists( 'inputFreeText', $formDataFromSchema );
626        $freeTextLabel = null;
627        if ( $includeFreeText && array_key_exists( 'freeTextLabel', $formDataFromSchema ) ) {
628            $freeTextLabel = $formDataFromSchema['freeTextLabel'];
629        }
630
631        $form = PFForm::create( $formName, $formItems );
632        $form->setAssociatedCategory( $categoryName );
633        if ( array_key_exists( 'PageNameFormula', $formDataFromSchema ) ) {
634            $form->setPageNameFormula( $formDataFromSchema['PageNameFormula'] );
635        }
636        if ( array_key_exists( 'CreateTitle', $formDataFromSchema ) ) {
637            $form->setCreateTitle( $formDataFromSchema['CreateTitle'] );
638        }
639        if ( array_key_exists( 'EditTitle', $formDataFromSchema ) ) {
640            $form->setEditTitle( $formDataFromSchema['EditTitle'] );
641        }
642
643        $user = RequestContext::getMain()->getUser();
644
645        $formContents = $form->createMarkup( $includeFreeText, $freeTextLabel );
646        $params = [];
647        $params['user_id'] = $user->getId();
648        $params['page_text'] = $formContents;
649        $job = new PSCreatePageJob( $formTitle, $params );
650
651        $jobs = [ $job ];
652        if ( method_exists( MediaWikiServices::class, 'getJobQueueGroup' ) ) {
653            // MW 1.37+
654            MediaWikiServices::getInstance()->getJobQueueGroup()->push( $jobs );
655        } else {
656            JobQueueGroup::singleton()->push( $jobs );
657        }
658    }
659
660    /**
661     * Generate pages (form and templates) specified in the list.
662     * @param PageSchemas $pageSchemaObj
663     * @param array $selectedPages
664     */
665    public static function generatePages( $pageSchemaObj, $selectedPages ) {
666        if ( $selectedPages == null ) {
667            return;
668        }
669
670        $user = RequestContext::getMain()->getUser();
671
672        $psFormItems = $pageSchemaObj->getFormItemsList();
673        $form_items = [];
674        $jobs = [];
675        $templateHackUsed = false;
676        $isCategoryNameSet = false;
677
678        // Generate every specified template
679        foreach ( $psFormItems as $psFormItem ) {
680            if ( $psFormItem['type'] == 'Template' ) {
681                $psTemplate = $psFormItem['item'];
682                $templateName = $psTemplate->getName();
683                $templateTitle = Title::makeTitleSafe( NS_TEMPLATE, $templateName );
684                $fullTemplateName = $templateTitle->getPrefixedText();
685                $template_fields = self::getFieldsFromTemplateSchema( $psTemplate );
686                // Get property for use in either #set_internal
687                // or #subobject, defined by either SIO's or
688                // SMW's Page Schemas portion. We don't need
689                // to record which one it came from, because
690                // PF's code to generate the template runs its
691                // own, similar check.
692                // @TODO - $internalObjProperty should probably
693                // have a more generic name.
694                if ( class_exists( 'SIOPageSchemas' ) ) {
695                    $internalObjProperty = SIOPageSchemas::getInternalObjectPropertyName( $psTemplate );
696                } elseif ( method_exists( 'SMWPageSchemas', 'getConnectingPropertyName' ) ) {
697                    $internalObjProperty = SMWPageSchemas::getConnectingPropertyName( $psTemplate );
698                } else {
699                    $internalObjProperty = null;
700                }
701                // TODO - actually, the category-setting should be
702                // smarter than this: if there's more than one
703                // template in the schema, it should probably be only
704                // the first non-multiple template that includes the
705                // category tag.
706                if ( $psTemplate->isMultiple() ) {
707                    $categoryName = null;
708                } else {
709                    if ( $isCategoryNameSet == false ) {
710                        $categoryName = $pageSchemaObj->getCategoryName();
711                        $isCategoryNameSet = true;
712                    } else {
713                        $categoryName = null;
714                    }
715
716                }
717                if ( method_exists( $psTemplate, 'getFormat' ) ) {
718                    $templateFormat = $psTemplate->getFormat();
719                } else {
720                    $templateFormat = null;
721                }
722
723                $pfTemplate = new PFTemplate( $templateName, $template_fields );
724                $pfTemplate->setConnectingProperty( $internalObjProperty );
725                $pfTemplate->setCategoryName( $categoryName );
726                $pfTemplate->setFormat( $templateFormat );
727
728                // Set Cargo table, if one was set in the schema.
729                $cargoArray = $psTemplate->getObject( 'cargo_TemplateDetails' );
730                if ( $cargoArray !== null ) {
731                    $cargoTable = PageSchemas::getValueFromObject( $cargoArray, 'Table' );
732                    $pfTemplate->setCargoTable( $cargoTable );
733                }
734
735                $templateText = $pfTemplate->createText();
736
737                if ( in_array( $fullTemplateName, $selectedPages ) ) {
738                    $params = [];
739                    $params['user_id'] = $user->getId();
740                    $params['page_text'] = $templateText;
741                    $jobs[] = new PSCreatePageJob( $templateTitle, $params );
742                    if ( strpos( $templateText, '{{!}}' ) > 0 ) {
743                        $templateHackUsed = true;
744                    }
745                }
746
747                $templateValues = self::getTemplateValues( $psTemplate );
748                if ( array_key_exists( 'Label', $templateValues ) ) {
749                    $templateLabel = $templateValues['Label'];
750                } else {
751                    $templateLabel = null;
752                }
753                $form_fields = self::getFormFieldInfo( $psTemplate, $template_fields );
754                // Create template info for form, for use in generating
755                // the form (if it will be generated).
756                $form_template = PFTemplateInForm::create(
757                    $templateName,
758                    $templateLabel,
759                    $psTemplate->isMultiple(),
760                    null,
761                    $form_fields
762                );
763                $form_items[] = [ 'type' => 'template', 'name' => $form_template->getTemplateName(), 'item' => $form_template ];
764            } elseif ( $psFormItem['type'] == 'Section' ) {
765                $psPageSection = $psFormItem['item'];
766                $form_section = self::getPageSection( $psPageSection );
767                if ( $form_section !== null ) {
768                    $form_section->setSectionLevel( $psPageSection->getSectionLevel() );
769                    $form_items[] = [ 'type' => 'section', 'name' => $form_section->getSectionName(), 'item' => $form_section ];
770                }
771            }
772
773        }
774
775        // Create the "!" hack template, if it's necessary
776        if ( $templateHackUsed ) {
777            $templateTitle = Title::makeTitleSafe( NS_TEMPLATE, '!' );
778            if ( !$templateTitle->exists() ) {
779                $params = [];
780                $params['user_id'] = $user->getId();
781                $params['page_text'] = '|';
782                $jobs[] = new PSCreatePageJob( $templateTitle, $params );
783            }
784        }
785
786        if ( method_exists( MediaWikiServices::class, 'getJobQueueGroup' ) ) {
787            // MW 1.37+
788            MediaWikiServices::getInstance()->getJobQueueGroup()->push( $jobs );
789        } else {
790            JobQueueGroup::singleton()->push( $jobs );
791        }
792
793        // Create form, if it's specified.
794        $formName = self::getFormName( $pageSchemaObj );
795        $categoryName = $pageSchemaObj->getCategoryName();
796        if ( !empty( $formName ) ) {
797            $formInfo = self::getMainFormInfo( $pageSchemaObj );
798            $formTitle = Title::makeTitleSafe( PF_NS_FORM, $formName );
799            $fullFormName = $formTitle->getPrefixedText();
800            if ( in_array( $fullFormName, $selectedPages ) ) {
801                self::generateForm( $formName, $formTitle,
802                    $form_items, $formInfo, $categoryName );
803            }
804        }
805    }
806
807    public static function getSchemaDisplayValues( $schemaXML ) {
808        foreach ( $schemaXML->children() as $tag => $child ) {
809            if ( $tag == "pageforms_Form" ) {
810                $formName = $child->attributes()->name;
811                $values = [];
812                foreach ( $child->children() as $tagName => $prop ) {
813                    $values[$tagName] = (string)$prop;
814                }
815                return [ $formName, $values ];
816            }
817        }
818        return null;
819    }
820
821    public static function getTemplateValues( $psTemplate ) {
822        // TODO - fix this.
823        $values = [];
824        if ( $psTemplate instanceof PSTemplate ) {
825            $psTemplate = $psTemplate->getXML();
826        }
827        // @phan-suppress-next-line PhanNonClassMethodCall
828        foreach ( $psTemplate->children() as $tag => $child ) {
829            if ( $tag == "pageforms_TemplateDetails" ) {
830                foreach ( $child->children() as $prop ) {
831                    $values[$prop->getName()] = (string)$prop;
832                }
833            }
834        }
835        return $values;
836    }
837
838    public static function getTemplateDisplayString() {
839        return wfMessage( 'pf-pageschemas-templatedetails' )->escaped();
840    }
841
842    /**
843     * Displays form details for one template in the Page Schemas XML.
844     * @param string $templateXML
845     * @return null|array
846     */
847    public static function getTemplateDisplayValues( $templateXML ) {
848        $templateValues = self::getTemplateValues( $templateXML );
849        if ( count( $templateValues ) == 0 ) {
850            return null;
851        }
852
853        $displayValues = [];
854        foreach ( $templateValues as $key => $value ) {
855            if ( $key == 'Label' ) {
856                $propName = wfMessage( 'exif-label' )->escaped();
857            } elseif ( $key == 'AddAnotherText' ) {
858                $propName = "'Add another' button";
859            }
860            $displayValues[$propName] = $value;
861        }
862        return [ null, $displayValues ];
863    }
864
865    public static function getFieldDisplayString() {
866        return wfMessage( 'pf-pageschemas-forminput' )->parse();
867    }
868
869    public static function getPageSectionDisplayString() {
870        return wfMessage( 'ps-otherparams' )->text();
871    }
872
873    /**
874     * Displays data on a single form input in the Page Schemas XML.
875     * @param Node $fieldXML
876     * @return array|null
877     * @suppress PhanUndeclaredTypeParameter
878     */
879    public static function getFieldDisplayValues( $fieldXML ) {
880        foreach ( $fieldXML->children() as $tag => $child ) {
881            if ( $tag == "pageforms_FormInput" ) {
882                $inputName = $child->attributes()->name;
883                $values = [];
884                foreach ( $child->children() as $prop ) {
885                    if ( $prop->getName() == 'InputType' ) {
886                        $propName = 'Input type';
887                    } else {
888                        $propName = (string)$prop->attributes()->name;
889                    }
890                    $values[$propName] = (string)$prop;
891                }
892                return [ $inputName, $values ];
893            }
894        }
895        return null;
896    }
897
898    public static function getPageSectionDisplayValues( $pageSectionXML ) {
899        foreach ( $pageSectionXML->children() as $tag => $child ) {
900            if ( $tag == "pageforms_PageSection" ) {
901                $inputName = $child->attributes()->name;
902                $values = [];
903                foreach ( $child->children() as $prop ) {
904                    $propName = (string)$prop->attributes()->name;
905                    $values[$propName] = (string)$prop;
906                }
907                return [ $inputName, $values ];
908            }
909        }
910        return null;
911    }
912}