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