Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 227
0.00% covered (danger)
0.00%
0 / 41
CRAP
0.00% covered (danger)
0.00%
0 / 1
PFTemplateInForm
0.00% covered (danger)
0.00%
0 / 227
0.00% covered (danger)
0.00%
0 / 41
16770
0.00% covered (danger)
0.00%
0 / 1
 create
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 newFromFormTag
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
420
 getTemplateName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHeight
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFields
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEmbedInTemplate
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEmbedInField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLabel
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getIntro
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAddButtonText
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisplay
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEventTitleField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEventDateField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEventStartDateField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEventEndDateField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPlaceholder
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisplayedFieldsWhenMinimized
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 allowsMultiple
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 strictParsing
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMinInstancesAllowed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMaxInstancesAllowed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createMarkup
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
42
 getFullTextInPage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 pageCallsThisTemplate
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasValueFromPageForField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAndRemoveValueFromPageForField
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getValuesFromPage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getInstanceNum
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getGridValues
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 incrementInstanceNum
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 allInstancesPrinted
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addGridValue
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 addField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 changeFieldValues
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 setFieldValuesFromSubmit
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
132
 getValuesFromSubmit
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 removeUnparsedText
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 restoreUnparsedText
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 setFieldValuesFromPage
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 1
1056
 setPageRelatedInfo
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 checkIfAllInstancesPrinted
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2/**
3 * Represents a template in a user-defined form.
4 * @author Yaron Koren
5 * @file
6 * @ingroup PF
7 */
8class PFTemplateInForm {
9    private $mTemplateName;
10    private $mLabel;
11    private $mIntro;
12    private $mAddButtonText;
13    private $mDisplay;
14    private $mEventTitleField;
15    private $mEventDateField;
16    private $mEventStartDateField;
17    private $mEventEndDateField;
18    private $mAllowMultiple;
19    private $mStrictParsing;
20    private $mMinAllowed;
21    private $mMaxAllowed;
22    private $mFields = [];
23    private $mEmbedInTemplate;
24    private $mEmbedInField;
25    private $mPlaceholder;
26    private $mHeight = '200px';
27    /**
28     * Conceptually, it would make more sense to define and store this
29     * parameter per-field, rather than per-template. However, it's a lot
30     * easier to handle it in just one place, rather than in every form
31     * input class. Also, this allows, in theory, to set the order of the
32     * fields being displayed - though that's not being done yet.
33     */
34    private $mDisplayedFieldsWhenMinimized;
35
36    /**
37     * These fields are for a specific usage of a form (or more
38     * specifically, a template in a form) to edit a particular page.
39     * Perhaps they should go in another class.
40     */
41    private $mSearchTemplateStr;
42    private $mPregMatchTemplateStr;
43    private $mFullTextInPage;
44    private $mValuesFromPage = [];
45    private $mValuesFromSubmit = [];
46    private $mNumInstancesFromSubmit = 0;
47    private $mPageCallsThisTemplate = false;
48    private $mInstanceNum = 0;
49    private $mAllInstancesPrinted = false;
50    private $mGridValues = [];
51
52    static function create( $name, $label = null, $allowMultiple = null, $maxAllowed = null, $formFields = null ) {
53        $tif = new PFTemplateInForm();
54        $tif->mTemplateName = str_replace( '_', ' ', $name );
55        if ( $formFields === null ) {
56            $template = PFTemplate::newFromName( $tif->mTemplateName );
57            $fields = $template->getTemplateFields();
58            foreach ( $fields as $field ) {
59                $tif->mFields[] = PFFormField::create( $field );
60            }
61        } else {
62            $tif->mFields = $formFields;
63        }
64        $tif->mLabel = $label;
65        $tif->mAllowMultiple = $allowMultiple;
66        $tif->mMaxAllowed = $maxAllowed;
67        return $tif;
68    }
69
70    public static function newFromFormTag( $tag_components ) {
71        global $wgPageFormsEmbeddedTemplates;
72
73        $parser = PFUtils::getParser();
74
75        $tif = new PFTemplateInForm();
76        $tif->mTemplateName = str_replace( '_', ' ', trim( PFFormPrinter::getParsedValue( $parser, $tag_components[1] ) ) );
77
78        $tif->mAddButtonText = wfMessage( 'pf_formedit_addanother' )->text();
79
80        if ( array_key_exists( $tif->mTemplateName, $wgPageFormsEmbeddedTemplates ) ) {
81            list( $tif->mEmbedInTemplate, $tif->mEmbedInField ) =
82                $wgPageFormsEmbeddedTemplates[$tif->mTemplateName];
83            $tif->mPlaceholder = PFFormPrinter::placeholderFormat( $tif->mEmbedInTemplate, $tif->mEmbedInField );
84        }
85
86        // Cycle through the other components.
87        for ( $i = 2; $i < count( $tag_components ); $i++ ) {
88            $component = $tag_components[$i];
89            if ( $component == 'multiple' ) {
90                $tif->mAllowMultiple = true;
91            } elseif ( $component == 'strict' ) {
92                $tif->mStrictParsing = true;
93            }
94            $sub_components = array_map( 'trim', explode( '=', $component, 2 ) );
95            if ( count( $sub_components ) == 2 ) {
96                if ( $sub_components[0] == 'label' ) {
97                    $tif->mLabel = PFFormPrinter::getParsedValue( $parser, $sub_components[1] );
98                } elseif ( $sub_components[0] == 'intro' ) {
99                    $tif->mIntro = $sub_components[1];
100                } elseif ( $sub_components[0] == 'minimum instances' ) {
101                    $tif->mMinAllowed = $sub_components[1];
102                } elseif ( $sub_components[0] == 'maximum instances' ) {
103                    $tif->mMaxAllowed = $sub_components[1];
104                } elseif ( $sub_components[0] == 'add button text' ) {
105                    $tif->mAddButtonText = PFFormPrinter::getParsedValue( $parser, $sub_components[1] );
106                } elseif ( $sub_components[0] == 'embed in field' ) {
107                    // Placeholder on form template level. Assume that the template form def
108                    // will have a multiple+placeholder parameters, and get the placeholder value.
109                    // We expect something like TemplateName[fieldName], and convert it to the
110                    // TemplateName___fieldName form used internally.
111                    preg_match( '/\s*(.*)\[(.*)\]\s*/', $sub_components[1], $matches );
112                    if ( count( $matches ) > 2 ) {
113                        $tif->mEmbedInTemplate = $matches[1];
114                        $tif->mEmbedInField = $matches[2];
115                        $tif->mPlaceholder = PFFormPrinter::placeholderFormat( $tif->mEmbedInTemplate, $tif->mEmbedInField );
116                    }
117                } elseif ( $sub_components[0] == 'display' ) {
118                    $tif->mDisplay = $sub_components[1];
119                } elseif ( $sub_components[0] == 'height' ) {
120                    $tif->mHeight = $sub_components[1];
121                } elseif ( $sub_components[0] == 'displayed fields when minimized' ) {
122                    $tif->mDisplayedFieldsWhenMinimized = $sub_components[1];
123                } elseif ( $sub_components[0] == 'event title field' ) {
124                    $tif->mEventTitleField = $sub_components[1];
125                } elseif ( $sub_components[0] == 'event date field' ) {
126                    $tif->mEventDateField = $sub_components[1];
127                } elseif ( $sub_components[0] == 'event start date field' ) {
128                    $tif->mEventStartDateField = $sub_components[1];
129                } elseif ( $sub_components[0] == 'event end date field' ) {
130                    $tif->mEventEndDateField = $sub_components[1];
131                }
132            }
133        }
134
135        return $tif;
136    }
137
138    function getTemplateName() {
139        return $this->mTemplateName;
140    }
141
142    function getHeight() {
143        return $this->mHeight;
144    }
145
146    function getFields() {
147        return $this->mFields;
148    }
149
150    function getEmbedInTemplate() {
151        return $this->mEmbedInTemplate;
152    }
153
154    function getEmbedInField() {
155        return $this->mEmbedInField;
156    }
157
158    function getLabel() {
159        return $this->mLabel;
160    }
161
162    function getIntro() {
163        return $this->mIntro;
164    }
165
166    function getAddButtonText() {
167        return $this->mAddButtonText;
168    }
169
170    function getDisplay() {
171        return $this->mDisplay;
172    }
173
174    function getEventTitleField() {
175        return $this->mEventTitleField;
176    }
177
178    function getEventDateField() {
179        return $this->mEventDateField;
180    }
181
182    function getEventStartDateField() {
183        return $this->mEventStartDateField;
184    }
185
186    function getEventEndDateField() {
187        return $this->mEventEndDateField;
188    }
189
190    function getPlaceholder() {
191        return $this->mPlaceholder;
192    }
193
194    function getDisplayedFieldsWhenMinimized() {
195        return $this->mDisplayedFieldsWhenMinimized;
196    }
197
198    function allowsMultiple() {
199        return $this->mAllowMultiple;
200    }
201
202    function strictParsing() {
203        return $this->mStrictParsing;
204    }
205
206    function getMinInstancesAllowed() {
207        return $this->mMinAllowed;
208    }
209
210    function getMaxInstancesAllowed() {
211        return $this->mMaxAllowed;
212    }
213
214    function createMarkup() {
215        $text = "{{{for template|" . $this->mTemplateName;
216        if ( $this->mAllowMultiple ) {
217            $text .= "|multiple";
218        }
219        if ( $this->mLabel != '' ) {
220            $text .= "|label=" . $this->mLabel;
221        }
222        $text .= "}}}\n";
223        // For now, HTML for templates differs for multiple-instance
224        // templates; this may change if handling of form definitions
225        // gets more sophisticated.
226        if ( !$this->mAllowMultiple ) {
227            $text .= "{| class=\"formtable\"\n";
228        }
229        foreach ( $this->mFields as $i => $field ) {
230            $is_last_field = ( $i == count( $this->mFields ) - 1 );
231            $text .= $field->createMarkup( $this->mAllowMultiple, $is_last_field );
232        }
233        if ( !$this->mAllowMultiple ) {
234            $text .= "|}\n";
235        }
236        $text .= "{{{end template}}}\n";
237        return $text;
238    }
239
240    /**
241     * This method, and all methods below it, are intended for an instance
242     * of a template in a specific form, and perhaps should be moved into
243     * another class.
244     *
245     * @return string
246     */
247    function getFullTextInPage() {
248        return $this->mFullTextInPage;
249    }
250
251    function pageCallsThisTemplate() {
252        return $this->mPageCallsThisTemplate;
253    }
254
255    function hasValueFromPageForField( $field_name ) {
256        return array_key_exists( $field_name, $this->mValuesFromPage );
257    }
258
259    function getAndRemoveValueFromPageForField( $field_name ) {
260        $value = $this->mValuesFromPage[$field_name];
261        unset( $this->mValuesFromPage[$field_name] );
262        return $value;
263    }
264
265    function getValuesFromPage() {
266        return $this->mValuesFromPage;
267    }
268
269    function getInstanceNum() {
270        return $this->mInstanceNum;
271    }
272
273    function getGridValues() {
274        return $this->mGridValues;
275    }
276
277    function incrementInstanceNum() {
278        $this->mInstanceNum++;
279    }
280
281    function allInstancesPrinted() {
282        return $this->mAllInstancesPrinted;
283    }
284
285    function addGridValue( $field_name, $cur_value ) {
286        if ( !array_key_exists( $this->mInstanceNum, $this->mGridValues ) ) {
287            $this->mGridValues[$this->mInstanceNum] = [];
288        }
289        $this->mGridValues[$this->mInstanceNum][$field_name] = $cur_value;
290    }
291
292    function addField( $form_field ) {
293        $this->mFields[] = $form_field;
294    }
295
296    /**
297     * This makes it possible for += and -= to modify values based on existing values.
298     *
299     * @param string $field_name
300     * @param string $new_value
301     * @param string|null $modifier
302     */
303    function changeFieldValues( $field_name, $new_value, $modifier = null ) {
304        $this->mValuesFromPage[$field_name] = $new_value;
305        if ( $modifier !== null && array_key_exists( $field_name . $modifier, $this->mValuesFromPage ) ) {
306            // clean up old values with + or - in them from the array
307            unset( $this->mValuesFromPage[$field_name . $modifier] );
308        }
309    }
310
311    function setFieldValuesFromSubmit() {
312        global $wgRequest;
313
314        // Reset values for every new instance, if this is a
315        // multiple-instance template.
316        if ( $this->mInstanceNum > 0 ) {
317            $this->mValuesFromSubmit = [];
318        }
319
320        $query_template_name = str_replace( ' ', '_', $this->mTemplateName );
321        // Also replace periods with underlines, since that's what
322        // POST does to strings anyway.
323        $query_template_name = str_replace( '.', '_', $query_template_name );
324        // ...and escape apostrophes.
325        //  (Or don't.)
326        // $query_template_name = str_replace( "'", "\'", $query_template_name );
327
328        $allValuesFromSubmit = $wgRequest->getArray( $query_template_name );
329        if ( $allValuesFromSubmit === null ) {
330            return;
331        }
332        // If this is a multiple-instance template, get the values for
333        // this instance of the template.
334        if ( $this->mAllowMultiple ) {
335            // If this data came from a spreadsheet, unescape some characters.
336            $spreadsheetTemplates = $wgRequest->getArray( 'spreadsheet_templates' );
337            if ( is_array( $spreadsheetTemplates ) && array_key_exists( $query_template_name, $spreadsheetTemplates ) ) {
338                foreach ( $allValuesFromSubmit as &$rowValues ) {
339                    foreach ( $rowValues as &$curValue ) {
340                        $curValue = str_replace( [ '&lt;', '&gt;' ], [ '<', '>' ], $curValue );
341                    }
342                }
343            }
344            $valuesFromSubmitKeys = [];
345            foreach ( array_keys( $allValuesFromSubmit ) as $key ) {
346                if ( $key != 'num' ) {
347                    $valuesFromSubmitKeys[] = $key;
348                }
349            }
350            $this->mNumInstancesFromSubmit = count( $valuesFromSubmitKeys );
351            if ( $this->mNumInstancesFromSubmit > $this->mInstanceNum ) {
352                $instanceKey = $valuesFromSubmitKeys[$this->mInstanceNum];
353                $this->mValuesFromSubmit = $allValuesFromSubmit[$instanceKey];
354            }
355        } else {
356            $this->mValuesFromSubmit = $allValuesFromSubmit;
357        }
358    }
359
360    function getValuesFromSubmit() {
361        return $this->mValuesFromSubmit;
362    }
363
364    /**
365     * Remove all the bits that should not be parsed - those
366     * contained in <pre> tags, etc. - and place them in an array,
367     * so that they can be added back in later. This will prevent
368     * the brackets, curly braces and pipes within those bits from
369     * interfering with the parsing we need to do.
370     *
371     * @param string $str
372     * @param string[] &$replacements
373     * @return string
374     */
375    static function removeUnparsedText( $str, &$replacements ) {
376        $startAndEndTags = [
377            [ '<pre', 'pre>' ],
378            [ '<syntaxhighlight', 'syntaxhighlight>' ],
379            [ '<source', 'source>' ],
380            [ '<ref', 'ref>' ],
381            [ '<nowiki', 'nowiki>' ]
382        ];
383        foreach ( $startAndEndTags as $tags ) {
384            list( $startTag, $endTag ) = $tags;
385
386            $startTagLoc = -1;
387            while ( ( $startTagLoc + strlen( $startTag ) < strlen( $str ) ) &&
388                ( ( $startTagLoc = strpos( $str, $startTag, $startTagLoc + strlen( $startTag ) ) ) !== false ) ) {
389                // Ignore "singleton" tags, like '<ref name="abc" />'.
390                $possibleSingletonTagEnd = strpos( $str, '/>', $startTagLoc );
391                if ( $possibleSingletonTagEnd !== false && $possibleSingletonTagEnd < strpos( $str, '>', $startTagLoc ) ) {
392                    continue;
393                }
394                $endTagLoc = strpos( $str, $endTag, $startTagLoc + strlen( $startTag ) );
395                // Also ignore unclosed tags.
396                if ( $endTagLoc === false ) {
397                    continue;
398                }
399                $fullTagTextLength = $endTagLoc + strlen( $endTag ) - $startTagLoc;
400                $replacements[] = substr( $str, $startTagLoc, $fullTagTextLength );
401                $replacementNum = count( $replacements ) - 1;
402                $str = substr_replace( $str, "\1" . $replacementNum . "\2", $startTagLoc, $fullTagTextLength );
403            }
404        }
405        return $str;
406    }
407
408    /**
409     * @param string $str
410     * @param string[] $replacements
411     * @return string
412     */
413    static function restoreUnparsedText( $str, $replacements ) {
414        foreach ( $replacements as $i => $fullTagText ) {
415            $str = str_replace( "\1" . $i . "\2", $fullTagText, $str );
416        }
417        return $str;
418    }
419
420    function setFieldValuesFromPage( $existing_page_content ) {
421        $unparsedTextReplacements = [];
422        $existing_page_content = self::removeUnparsedText( $existing_page_content, $unparsedTextReplacements );
423        $matches = [];
424        $search_pattern = '/{{' . $this->mPregMatchTemplateStr . '\s*[\|}]/i';
425        $content_str = str_replace( '_', ' ', $existing_page_content );
426        preg_match( $search_pattern, $content_str, $matches, PREG_OFFSET_CAPTURE );
427        // is this check necessary?
428        if ( array_key_exists( 0, $matches ) && array_key_exists( 1, $matches[0] ) ) {
429            $start_char = $matches[0][1];
430            $fields_start_char = $start_char + 2 + strlen( $this->mSearchTemplateStr );
431            // Skip ahead to the first real character.
432            while ( in_array( $existing_page_content[$fields_start_char], [ ' ', '\n' ] ) ) {
433                $fields_start_char++;
434            }
435            // If the next character is a pipe, skip that too.
436            if ( $existing_page_content[$fields_start_char] == '|' ) {
437                $fields_start_char++;
438            }
439            $this->mValuesFromPage = [ '0' => '' ];
440            // Cycle through template call, splitting it up by pipes ('|'),
441            // except when that pipe is part of a piped link.
442            $field = "";
443            $uncompleted_square_brackets = 0;
444            $uncompleted_curly_brackets = 2;
445            $template_ended = false;
446            for ( $i = $fields_start_char; !$template_ended && ( $i < strlen( $existing_page_content ) ); $i++ ) {
447                $c = $existing_page_content[$i];
448                if ( $i + 1 < strlen( $existing_page_content ) ) {
449                    $nextc = $existing_page_content[$i + 1];
450                } else {
451                    $nextc = null;
452                }
453                if ( $i > 0 ) {
454                    $prevc = $existing_page_content[$i - 1];
455                } else {
456                    $prevc = null;
457                }
458                if ( $c == '[' && ( $nextc == '[' || $prevc == '[' ) ) {
459                    $uncompleted_square_brackets++;
460                } elseif ( $c == ']' && ( $nextc == ']' || $prevc == ']' ) && $uncompleted_square_brackets > 0 ) {
461                    $uncompleted_square_brackets--;
462                } elseif ( $c == '{' && ( $nextc == '{' || $prevc == '{' ) ) {
463                    $uncompleted_curly_brackets++;
464                } elseif ( $c == '}' && ( $nextc == '}' || $prevc == '}' ) && $uncompleted_curly_brackets > 0 ) {
465                    $uncompleted_curly_brackets--;
466                }
467                // handle an end to a field and/or template declaration
468                $template_ended = ( $uncompleted_curly_brackets == 0 && $uncompleted_square_brackets == 0 );
469                $field_ended = ( $c == '|' && $uncompleted_square_brackets == 0 && $uncompleted_curly_brackets <= 2 );
470                if ( $template_ended || $field_ended ) {
471                    // If this was the last character in the template, remove
472                    // the closing curly brackets.
473                    if ( $template_ended ) {
474                        $field = substr( $field, 0, -1 );
475                    }
476                    $field = self::restoreUnparsedText( $field, $unparsedTextReplacements );
477                    // Either there's an equals sign near the beginning or not -
478                    // handling is similar in either way; if there's no equals
479                    // sign, the index of this field becomes the key.
480                    $sub_fields = explode( '=', $field, 2 );
481                    if ( count( $sub_fields ) > 1 ) {
482                        $this->mValuesFromPage[trim( $sub_fields[0] )] = trim( $sub_fields[1] );
483                    } else {
484                        $this->mValuesFromPage[] = trim( $sub_fields[0] );
485                    }
486                    $field = '';
487                } else {
488                    $field .= $c;
489                }
490            }
491
492            // If there are uncompleted opening brackets, the whole form will get messed up -
493            // throw an exception.
494            // (If there are too many *closing* brackets, some template stuff will end up in
495            // the "free text" field - which is bad, but it's harder for the code to detect
496            // the problem - though hopefully, easier for users.)
497            if ( $uncompleted_curly_brackets > 0 || $uncompleted_square_brackets > 0 ) {
498                throw new MWException( "PageFormsMismatchedBrackets" );
499            }
500
501            $fullText = substr( $existing_page_content, $start_char, $i - $start_char );
502            $this->mFullTextInPage = self::restoreUnparsedText( $fullText, $unparsedTextReplacements );
503        }
504    }
505
506    /**
507     * Set some vars based on the current contents of the page being
508     * edited - or at least vars that only need to be set if there's
509     * an existing page.
510     * @param string $existing_page_content
511     */
512    function setPageRelatedInfo( $existing_page_content ) {
513        // Replace underlines with spaces in template name, to allow for
514        // searching on either.
515        $this->mSearchTemplateStr = str_replace( '_', ' ', $this->mTemplateName );
516        $this->mPregMatchTemplateStr = str_replace(
517            [ '/', '(', ')', '^' ],
518            [ '\/', '\(', '\)', '\^' ],
519            $this->mSearchTemplateStr );
520        $this->mPageCallsThisTemplate = preg_match( '/{{' . $this->mPregMatchTemplateStr . '\s*[\|}]/i', str_replace( '_', ' ', $existing_page_content ) );
521    }
522
523    function checkIfAllInstancesPrinted( $form_submitted, $source_is_page ) {
524        // Find additional instances of this template in the page
525        // (if it's an existing page) or the query string (if it's a
526        // new page).
527        // If there's at least one, re-parse this section of the
528        // definition form for the subsequent template instance;
529        // if there's none, don't include fields at all.
530        // @TODO - There has to be a more efficient way to handle
531        // multiple instances of templates, one that doesn't involve
532        // re-parsing the same tags, but I don't know what it is.
533        // (Also add additional, blank instances if there's a minimum
534        // number required in this form, and we haven't reached it yet.)
535        if ( !$this->mAllowMultiple ) {
536            return;
537        }
538        if ( $form_submitted && $this->mInstanceNum < $this->mNumInstancesFromSubmit ) {
539            return;
540        }
541        if ( !$form_submitted && $this->mInstanceNum < $this->mMinAllowed ) {
542            return;
543        }
544        if ( !$form_submitted && $source_is_page && $this->mPageCallsThisTemplate ) {
545            return;
546        }
547        if ( !$form_submitted && !$source_is_page && $this->mValuesFromSubmit != null ) {
548            return;
549        }
550        $this->mAllInstancesPrinted = true;
551    }
552
553}