Esempio n. 1
0
 function setTypeAndPossibleValues()
 {
     $proptitle = Title::makeTitleSafe(SMW_NS_PROPERTY, $this->mSemanticProperty);
     if ($proptitle === null) {
         return;
     }
     $store = smwfGetStore();
     // this returns an array of objects
     $allowed_values = SFUtils::getSMWPropertyValues($store, $proptitle, "Allows value");
     $label_formats = SFUtils::getSMWPropertyValues($store, $proptitle, "Has field label format");
     if (class_exists('SMWDIProperty')) {
         // SMW 1.6+
         $propValue = SMWDIProperty::newFromUserLabel($this->mSemanticProperty);
         $this->mPropertyType = $propValue->findPropertyTypeID();
     } else {
         $propValue = SMWPropertyValue::makeUserProperty($this->mSemanticProperty);
         $this->mPropertyType = $propValue->getPropertyTypeID();
     }
     foreach ($allowed_values as $allowed_value) {
         // HTML-unencode each value
         $this->mPossibleValues[] = html_entity_decode($allowed_value);
         if (count($label_formats) > 0) {
             $label_format = $label_formats[0];
             $prop_instance = SMWDataValueFactory::findTypeID($this->mPropertyType);
             $label_value = SMWDataValueFactory::newTypeIDValue($prop_instance, $wiki_value);
             $label_value->setOutputFormat($label_format);
             $this->mValueLabels[$wiki_value] = html_entity_decode($label_value->getWikiValue());
         }
     }
     // HACK - if there were any possible values, set the property
     // type to be 'enumeration', regardless of what the actual type is
     if (count($this->mPossibleValues) > 0) {
         $this->mPropertyType = 'enumeration';
     }
 }
 /**
  * Read and interpret the given parameters.
  *
  * @since 1.8
  * @param string $query from the web request as given by MW
  */
 protected function processParameters($query)
 {
     global $wgRequest;
     // get the GET parameters
     $params = SMWInfolink::decodeParameters($query, false);
     reset($params);
     $inputPropertyString = $wgRequest->getText('property', current($params));
     $inputValueString = $wgRequest->getText('value', next($params));
     $inputValueString = str_replace(' ', ' ', $inputValueString);
     $inputValueString = str_replace(' ', ' ', $inputValueString);
     $this->property = SMWPropertyValue::makeUserProperty($inputPropertyString);
     if (!$this->property->isValid()) {
         $this->propertystring = $inputPropertyString;
         $this->value = null;
         $this->valuestring = $inputValueString;
     } else {
         $this->propertystring = $this->property->getWikiValue();
         $this->value = SMWDataValueFactory::newPropertyObjectValue($this->property->getDataItem(), $inputValueString);
         $this->valuestring = $this->value->isValid() ? $this->value->getWikiValue() : $inputValueString;
     }
     $limitString = $wgRequest->getVal('limit');
     if (is_numeric($limitString)) {
         $this->limit = intval($limitString);
     } else {
         $this->limit = 20;
     }
     $offsetString = $wgRequest->getVal('offset');
     if (is_numeric($offsetString)) {
         $this->offset = intval($offsetString);
     } else {
         $this->offset = 0;
     }
 }
 /**
  * @since 2.1
  *
  * @param PPFrame $frame
  * @param array $args
  */
 public function parse(PPFrame $frame, array $args)
 {
     // @todo Save as metadata
     if (!$frame->isTemplate()) {
         return '';
     }
     $this->subject = $this->parserData->getSemanticData()->getSubject();
     foreach ($args as $arg) {
         if (trim($arg) !== '') {
             $expanded = trim($frame->expand($arg));
             $parts = explode('=', $expanded, 2);
             if (count($parts) == 1) {
                 $propertystring = $expanded;
                 $argumentname = $expanded;
             } else {
                 $propertystring = $parts[0];
                 $argumentname = $parts[1];
             }
             $propertyValue = PropertyValue::makeUserProperty($propertystring);
             $argument = $frame->getArgument($argumentname);
             $valuestring = $frame->expand($argument);
             if ($propertyValue->isValid()) {
                 $this->matchValueArgument($propertyValue, $propertystring, $valuestring);
             }
         }
     }
     $this->parserData->pushSemanticDataToParserOutput();
     return '';
 }
Esempio n. 4
0
 protected static function addPropertyValueToSemanticData($propertyName, $valueString, $semanticData)
 {
     $propertyDv = SMWPropertyValue::makeUserProperty($propertyName);
     $propertyDi = $propertyDv->getDataItem();
     self::addPropertyDiValueToSemanticData($propertyDi, $valueString, $semanticData);
     return $propertyDi;
 }
	public static function printoutFromString( $printout ) {
		return new SMWPrintRequest(
			SMWPrintRequest::PRINT_PROP,
			$printout,
			SMWPropertyValue::makeUserProperty( $printout )
		);
	}
Esempio n. 6
0
 function testCheckIfPropertyRenamed()
 {
     // do some checks
     $page = Title::newFromText("5 cylinder", NS_MAIN);
     $prop = SMWPropertyValue::makeUserProperty("Torsional moment");
     $values = smwfGetStore()->getPropertyValues($page, $prop);
     $this->assertTrue(count($values) > 0);
 }
	public function setXMLAttribute( $key, $value ) {
		if ( $value == '' ) throw new MWException( __METHOD__ . ": value cannot be empty" );

		if ( $key == 'name' ) {
			$property = SMWPropertyValue::makeUserProperty( $value );
		} else {
			throw new MWException( __METHOD__ . ": invalid key/value pair: name=property_name" );
		}
	}
Esempio n. 8
0
 /**
  * Method for handling the declare parser function.
  * 
  * @since 1.5.3
  * 
  * @param Parser $parser
  * @param PPFrame $frame
  * @param array $args
  */
 public static function render(Parser &$parser, PPFrame $frame, array $args)
 {
     if ($frame->isTemplate()) {
         foreach ($args as $arg) {
             if (trim($arg) !== '') {
                 $expanded = trim($frame->expand($arg));
                 $parts = explode('=', $expanded, 2);
                 if (count($parts) == 1) {
                     $propertystring = $expanded;
                     $argumentname = $expanded;
                 } else {
                     $propertystring = $parts[0];
                     $argumentname = $parts[1];
                 }
                 $property = SMWPropertyValue::makeUserProperty($propertystring);
                 $argument = $frame->getArgument($argumentname);
                 $valuestring = $frame->expand($argument);
                 if ($property->isValid()) {
                     $type = $property->getPropertyTypeID();
                     if ($type == '_wpg') {
                         $matches = array();
                         preg_match_all('/\\[\\[([^\\[\\]]*)\\]\\]/u', $valuestring, $matches);
                         $objects = $matches[1];
                         if (count($objects) == 0) {
                             if (trim($valuestring) !== '') {
                                 SMWParseData::addProperty($propertystring, $valuestring, false, $parser, true);
                             }
                         } else {
                             foreach ($objects as $object) {
                                 SMWParseData::addProperty($propertystring, $object, false, $parser, true);
                             }
                         }
                     } elseif (trim($valuestring) !== '') {
                         SMWParseData::addProperty($propertystring, $valuestring, false, $parser, true);
                     }
                     // $value = SMWDataValueFactory::newPropertyObjectValue( $property->getDataItem(), $valuestring );
                     // if (!$value->isValid()) continue;
                 }
             }
         }
     } else {
         // @todo Save as metadata
     }
     global $wgTitle;
     if (!is_null($wgTitle) && $wgTitle->isSpecialPage()) {
         global $wgOut;
         SMWOutputs::commitToOutputPage($wgOut);
     } else {
         SMWOutputs::commitToParser($parser);
     }
     return '';
 }
	public function addPropertyAndValue( $propName, $value ) {
		// SMW 1.6+
		if ( class_exists( 'SMWDIProperty' ) ) {
			$property = SMWDIProperty::newFromUserLabel( $propName );
		} else {
			$property = SMWPropertyValue::makeUserProperty( $propName );
		}
		$dataValue = SMWDataValueFactory::newPropertyObjectValue( $property, $value );

		if ( $dataValue->isValid() ) {
			$this->mPropertyValuePairs[] = array( $property, $dataValue );
		} // else - show an error message?
	}
Esempio n. 10
0
 /**
  * Must be called from derived class to initialize the member variables.
  */
 protected function SMWSemanticStore(Title $domainRangeHintRelation, Title $minCard, Title $maxCard, Title $transitiveCat, Title $symetricalCat, Title $inverseOf)
 {
     $this->domainRangeHintRelation = $domainRangeHintRelation;
     $this->maxCard = $maxCard;
     $this->minCard = $minCard;
     $this->transitiveCat = $transitiveCat;
     $this->symetricalCat = $symetricalCat;
     $this->inverseOf = $inverseOf;
     $this->domainRangeHintProp = SMWPropertyValue::makeUserProperty($this->domainRangeHintRelation->getDBkey());
     $this->minCardProp = SMWPropertyValue::makeUserProperty($this->minCard->getDBkey());
     $this->maxCardProp = SMWPropertyValue::makeUserProperty($this->maxCard->getDBkey());
     $this->inverseOfProp = SMWPropertyValue::makeUserProperty($this->inverseOf->getDBkey());
 }
Esempio n. 11
0
 protected static function addPropertyValueToSemanticData($propertyName, $valueString, $semanticData)
 {
     $propertyDv = SMWPropertyValue::makeUserProperty($propertyName);
     $propertyDi = $propertyDv->getDataItem();
     if (!$propertyDi->isInverse()) {
         $valueDv = SMWDataValueFactory::newPropertyObjectValue($propertyDi, $valueString, false, $semanticData->getSubject());
         $semanticData->addPropertyObjectValue($propertyDi, $valueDv->getDataItem());
         // Take note of the error for storage (do this here and not in storage, thus avoiding duplicates).
         if (!$valueDv->isValid()) {
             $semanticData->addPropertyObjectValue(new SMWDIProperty('_ERRP'), $propertyDi->getDiWikiPage());
             self::$m_errors = array_merge(self::$m_errors, $valueDv->getErrors());
         }
     } else {
         self::$m_errors[] = wfMsgForContent('smw_noinvannot');
     }
 }
	/**
	 * Main entry point for Special Pages. Gets all required parameters.
	 *
	 * @param[in] $query string  Given by MediaWiki
	 */
	public function execute( $query ) {
		global $wgRequest, $wgOut;
		$this->setHeaders();

		// get the GET parameters
		$this->propertystring = $wgRequest->getText( 'property' );
		$this->valuestring = $wgRequest->getText( 'value' );

		$params = SMWInfolink::decodeParameters( $query, false );
		reset( $params );

		// no GET parameters? Then try the URL
		if ( $this->propertystring === '' ) $this->propertystring = current( $params );
		if ( $this->valuestring === '' ) $this->valuestring = next( $params );

		$this->valuestring = str_replace( ' ', ' ', $this->valuestring );
		$this->valuestring = str_replace( ' ', ' ', $this->valuestring );

		$this->property = SMWPropertyValue::makeUserProperty( $this->propertystring );
		if ( !$this->property->isValid() ) {
			$this->propertystring = '';
		} else {
			$this->propertystring = $this->property->getWikiValue();
			$this->value = SMWDataValueFactory::newPropertyObjectValue( $this->property->getDataItem(), $this->valuestring );

			if ( $this->value->isValid() ) {
				$this->valuestring = $this->value->getWikiValue();
			} else {
				$this->value = null;
			}
		}

		$limitstring = $wgRequest->getVal( 'limit' );
		if ( is_numeric( $limitstring ) ) {
			$this->limit =  intval( $limitstring );
		}

		$offsetstring = $wgRequest->getVal( 'offset' );
		if ( is_numeric( $offsetstring ) ) {
			$this->offset = intval( $offsetstring );
		}

		$wgOut->addHTML( $this->displaySearchByProperty() );
		$wgOut->addHTML( $this->queryForm() );

		SMWOutputs::commitToOutputPage( $wgOut ); // make sure locally collected output data is pushed to the output!
	}
 /**
  * @since 2.1
  */
 public function initialize()
 {
     $params = explode('/', $this->queryString);
     reset($params);
     // Remove empty elements
     $params = array_filter($params, 'strlen');
     $property = isset($this->requestOptions['property']) ? $this->requestOptions['property'] : current($params);
     $value = isset($this->requestOptions['value']) ? $this->requestOptions['value'] : next($params);
     $property = $this->urlEncoder->decode($property);
     $value = str_replace(array('-25'), array('%'), $value);
     $this->property = PropertyValue::makeUserProperty($property);
     if (!$this->property->isValid()) {
         $this->propertyString = $property;
         $this->value = null;
         $this->valueString = $value;
     } else {
         $this->propertyString = $this->property->getWikiValue();
         $this->value = DataValueFactory::getInstance()->newPropertyObjectValue($this->property->getDataItem(), $this->urlEncoder->decode($value));
         $this->valueString = $this->value->isValid() ? $this->value->getWikiValue() : $value;
     }
     $this->setLimit();
     $this->setOffset();
     $this->setNearbySearch();
 }
Esempio n. 14
0
 /**
  * Function for handling the {{\#missingvalues }} parser function.
  */
 public static function doMissingValues($parser, $querystring, $propertyname, $values)
 {
     $all_values = explode(',', $values);
     $all_values_clean = array();
     foreach ($all_values as $cur_value) {
         // remove whitespaces
         $cur_value = trim($cur_value);
         // ignore a value if it's null
         if ('' != $cur_value) {
             $all_values_clean[] = $cur_value;
         }
     }
     $params = array();
     $params['format'] = 'list';
     $params['link'] = 'none';
     $params['mainlabel'] = '-';
     $extraprintouts = array();
     $printmode = SMWPrintRequest::PRINT_PROP;
     $data = SMWPropertyValue::makeUserProperty(trim($propertyname));
     $label = '';
     $printout = new SMWPrintRequest($printmode, $label, $data);
     $extraprintouts[] = $printout;
     $outputmode = SMW_OUTPUT_WIKI;
     $result = SMWQueryProcessor::getResultFromQueryString($querystring, $params, $extraprintouts, $outputmode);
     $found_values = explode(', ', $result);
     $missing_values = array_diff($all_values_clean, $found_values);
     return join(', ', $missing_values);
 }
Esempio n. 15
0
function getAnnotations($annotatedImage)
{
    global $wgExtensionCredits;
    $new = false;
    foreach ($wgExtensionCredits['semantic'] as $elem) {
        if ($elem['name'] == 'Semantic MediaWiki') {
            $vers = $elem['version'];
            $new = version_compare($vers, '1.7', '>=');
        }
    }
    $returnString = '{"shapes":[';
    $queryString = '[[SIAannotatedImage::' . $annotatedImage . ']]';
    $params = array();
    $params['link'] = 'none';
    $params['mainlabel'] = 'result';
    #$params = ['order'];
    #$params = ['sort'];
    if ($new) {
        $params['order'] = array('asc');
        $params['sort'] = array('SIAannotatedImage');
    } else {
        $params['order'] = 'asc';
        $params['sort'] = 'SIAannotatedImage';
    }
    //Generate all the extra printouts, eg all properties to retrieve:
    $printmode = SMWPrintRequest::PRINT_PROP;
    $customPrintouts = array('coordinates' => 'SIArectangleCoordinates', 'text' => 'ImageAnnotationText');
    $extraprintouts = array();
    foreach ($customPrintouts as $label => $property) {
        $extraprintouts[] = new SMWPrintRequest($printmode, $label, SMWPropertyValue::makeUserProperty($property));
    }
    $format = 'table';
    $context = SMWQueryProcessor::INLINE_QUERY;
    $query = SMWQueryProcessor::createQuery($queryString, $params, $context, $format, $extraprintouts);
    $store = smwfGetStore();
    // default store
    $res = $store->getQueryResult($query);
    $shapeCounter = 0;
    while (($resArrayArray = $res->getNext()) != false) {
        //Array of SMWResultArray Objects, eg. all retrieved Pages
        $shapeCounter++;
        if ($shapeCounter > 1) {
            $returnString .= ',';
        }
        $returnString .= '{';
        foreach ($resArrayArray as $resArray) {
            //SMWResultArray-Object, column of resulttable (pagename or propertyvalue)
            $currentPrintRequestLabel = $resArray->getPrintRequest()->getLabel();
            //The label as defined in the above array
            if ($currentPrintRequestLabel == 'coordinates') {
                $currentResultPage = $resArray->getResultSubject();
                $currentID = $currentResultPage->getTitle()->getFullText();
                $currentCoords = $resArray->getNextDataItem()->getSerialization();
                $returnString .= '"coords":"' . $currentCoords . '","id":"' . $currentID . '"';
            }
        }
        $returnString .= '}';
    }
    $returnString .= ']}';
    return $returnString;
}
Esempio n. 16
0
 public function execute($query)
 {
     global $wgRequest, $wgOut;
     $linker = smwfGetLinker();
     $this->setHeaders();
     // Get parameters
     $pagename = $wgRequest->getVal('from');
     $propname = $wgRequest->getVal('type');
     $limit = $wgRequest->getVal('limit');
     $offset = $wgRequest->getVal('offset');
     if ($limit === '') {
         $limit = 20;
     }
     if ($offset === '') {
         $offset = 0;
     }
     if ($propname === '') {
         // No GET parameters? Try the URL:
         $queryparts = explode('::', $query);
         $propname = $query;
         if (count($queryparts) > 1) {
             $pagename = $queryparts[0];
             $propname = implode('::', array_slice($queryparts, 1));
         }
     }
     $subject = SMWDataValueFactory::newTypeIDValue('_wpg', $pagename);
     $pagename = $subject->isValid() ? $subject->getPrefixedText() : '';
     $property = SMWPropertyValue::makeUserProperty($propname);
     $propname = $property->isValid() ? $property->getWikiValue() : '';
     // Produce output
     $html = '';
     if ($propname === '') {
         // no property given, show a message
         $html .= wfMsg('smw_pp_docu') . "\n";
     } else {
         // property given, find and display results
         // FIXME: very ugly, needs i18n
         $wgOut->setPagetitle(($pagename !== '' ? $pagename . ' ' : '') . $property->getWikiValue());
         // get results (get one more, to see if we have to add a link to more)
         $options = new SMWRequestOptions();
         $options->limit = $limit + 1;
         $options->offset = $offset;
         $options->sort = true;
         $results = smwfGetStore()->getPropertyValues($pagename !== '' ? $subject->getDataItem() : null, $property->getDataItem(), $options);
         // prepare navigation bar if needed
         if ($offset > 0 || count($results) > $limit) {
             if ($offset > 0) {
                 $navigation = Html::element('a', array('href' => $this->getTitle()->getLocalURL(array('offset' => max(0, $offset - $limit), 'limit' => $limit, 'type' => $propname, 'from' => $pagename))), wfMsg('smw_result_prev'));
             } else {
                 $navigation = wfMsg('smw_result_prev');
             }
             $navigation .= '&#160;&#160;&#160;&#160; <b>' . wfMsg('smw_result_results') . ' ' . ($offset + 1) . '– ' . ($offset + min(count($results), $limit)) . '</b>&#160;&#160;&#160;&#160;';
             if (count($results) == $limit + 1) {
                 $navigation = Html::element('a', array('href' => $this->getTitle()->getLocalURL(array('offset' => $offset + $limit, 'limit' => $limit, 'type' => $propname, 'from' => $pagename))), wfMsg('smw_result_next'));
             } else {
                 $navigation .= wfMsg('smw_result_next');
             }
         } else {
             $navigation = '';
         }
         // display results
         $html .= '<br />' . $navigation;
         if (count($results) == 0) {
             $html .= wfMsg('smw_result_noresults');
         } else {
             $html .= "<ul>\n";
             $count = $limit + 1;
             foreach ($results as $di) {
                 $count--;
                 if ($count < 1) {
                     continue;
                 }
                 $dv = SMWDataValueFactory::newDataItemValue($di, $property->getDataItem());
                 $html .= '<li>' . $dv->getLongHTMLText($linker);
                 // do not show infolinks, the magnifier "+" is ambiguous with the browsing '+' for '_wpg' (see below)
                 if ($property->getDataItem()->findPropertyTypeID() == '_wpg') {
                     $browselink = SMWInfolink::newBrowsingLink('+', $dv->getLongWikiText());
                     $html .= ' &#160;' . $browselink->getHTML($linker);
                 }
                 $html .= "</li> \n";
             }
             $html .= "</ul>\n";
         }
         $html .= $navigation;
     }
     // Display query form
     $spectitle = $this->getTitle();
     $html .= '<p>&#160;</p>';
     $html .= '<form name="pageproperty" action="' . htmlspecialchars($spectitle->getLocalURL()) . '" method="get">' . "\n" . '<input type="hidden" name="title" value="' . $spectitle->getPrefixedText() . '"/>';
     $html .= wfMsg('smw_pp_from') . ' <input type="text" name="from" value="' . htmlspecialchars($pagename) . '" />' . "&#160;&#160;&#160;\n";
     $html .= wfMsg('smw_pp_type') . ' <input type="text" name="type" value="' . htmlspecialchars($propname) . '" />' . "\n";
     $html .= '<input type="submit" value="' . wfMsg('smw_pp_submit') . "\"/>\n</form>\n";
     $wgOut->addHTML($html);
     SMWOutputs::commitToOutputPage($wgOut);
     // make sure locally collected output data is pushed to the output!
 }
	/**
	 * Figures out the label of the property to be used. For outgoing ones it is just
	 * the text, for incoming ones we try to figure out the inverse one if needed,
	 * either by looking for an explicitly stated one or by creating a default one.
	 *
	 * @param[in] $property SMWPropertyValue  The property of interest
	 * @param[in] $incoming bool  If it is an incoming property
	 *
	 * @return string  The label of the property
	 */
	private function getPropertyLabel( SMWPropertyValue $property, $incoming = false ) {
		global $smwgBrowseShowInverse;

		if ( $incoming && $smwgBrowseShowInverse ) {
			$oppositeprop = SMWPropertyValue::makeUserProperty( wfMsg( 'smw_inverse_label_property' ) );
			$labelarray = &smwfGetStore()->getPropertyValues( $property->getDataItem()->getDiWikiPage(), $oppositeprop->getDataItem() );
			$rv = ( count( $labelarray ) > 0 ) ? $labelarray[0]->getLongWikiText():
			       wfMsg( 'smw_inverse_label_default', $property->getWikiValue() );
		} else {
			$rv = $property->getWikiValue();
		}

		return $this->unbreak( $rv );
	}
Esempio n. 18
0
 /**
  * Get derived properties.
  * @param SMWSemanticData $semData
  * 		Annotated facts of an article
  * @return SMWSemanticData
  * 		Derived facts of the article
  */
 public static function getDerivedProperties(SMWSemanticData $semData)
 {
     global $smwgIP, $smwgHaloIP, $smwgTripleStoreGraph;
     require_once $smwgIP . '/includes/SMW_QueryProcessor.php';
     require_once $smwgHaloIP . '/includes/storage/SMW_TripleStore.php';
     $derivedProperties = new SMWSemanticData($semData->getSubject());
     $subject = $semData->getSubject()->getDBkey();
     global $wgContLang;
     $subject = $semData->getSubject();
     $ns = strtolower($wgContLang->getNSText($subject->getNamespace()));
     if (empty($ns)) {
         $ns = 'a';
     }
     $localName = $subject->getDBkey();
     $inst = $smwgTripleStoreGraph . TSNamespaces::$INST_NS_SUFFIX;
     // $queryText = "PREFIX a:<$inst> SELECT ?pred ?obj WHERE { a:$subject ?pred ?obj . }";
     // $queryText = "SELECT ?pred ?obj WHERE { a:$subject ?pred ?obj . }";
     $queryText = "SELECT ?pred ?obj WHERE { <" . $smwgTripleStoreGraph . "/{$ns}#{$localName}> ?pred ?obj . }";
     // echo $queryText;
     wfRunHooks('BeforeDerivedPropertyQuery', array(&$queryText));
     // Ask for all properties of the subject (derived and ground facts)
     $q = SMWSPARQLQueryProcessor::createQuery($queryText, array());
     $res = smwfGetStore()->getQueryResult($q);
     // SMWQueryResult
     wfRunHooks('AfterDerivedPropertyQuery', array());
     wfRunHooks('FilterQueryResults', array(&$res, array('pred')));
     $propVal = array();
     while ($row = $res->getNext()) {
         //$row: SMWResultArray[]
         $i = 0;
         $valuesForProperty = array();
         $key = false;
         if (count($row) == 2) {
             $properties = array();
             $values = array();
             // There may be several properties with the same values
             $p = $row[0];
             while (($object = $p->getNextObject()) !== false) {
                 if ($object instanceof SMWURIValue) {
                     $keys = $object->getDBkeys();
                     $properties[] = $keys[0];
                 } else {
                     $properties[] = $object->getDBkey();
                 }
             }
             // Retrieve the values of the properties
             $v = $row[1];
             while (($object = $v->getNextObject()) !== false) {
                 $values[] = $object;
             }
         }
         foreach ($properties as $p) {
             if (array_key_exists($p, $propVal)) {
                 // The same property may appear several times
                 $propVal[$p] = array_merge($values, $propVal[$p]);
             } else {
                 $propVal[$p] = $values;
             }
         }
     }
     // Check is a property is derived or directly annotated
     foreach ($propVal as $propName => $derivedValues) {
         // does the property already exist?
         $prop = SMWPropertyValue::makeUserProperty($propName);
         $values = $semData->getPropertyValues($prop);
         foreach ($derivedValues as $dv) {
             $isDerived = true;
             $val = null;
             foreach ($values as $v) {
                 if ($dv->getTypeID() == '_wpg' && $v->getTypeID() == '_wpg') {
                     $vt1 = $dv->getTitle();
                     $vt2 = $v->getTitle();
                     if (isset($vt1) && isset($vt2) && $vt1->getText() == $vt2->getText()) {
                         $isDerived = false;
                         break;
                     }
                 } else {
                     if ($dv->getTypeID() == '_wpg' && $v->getTypeID() != '_wpg') {
                         // how can this happen?
                         $isDerived = false;
                         break;
                     } else {
                         if ($dv->isNumeric()) {
                             if ($dv->getWikiValue() == $v->getWikiValue()) {
                                 $isDerived = false;
                                 break;
                             }
                         } else {
                             if (array_shift($dv->getDBkeys()) == array_shift($v->getDBkeys())) {
                                 $isDerived = false;
                                 break;
                             }
                         }
                     }
                 }
             }
             if ($isDerived) {
                 $property = SMWPropertyValue::makeUserProperty($propName);
                 $derivedProperties->addPropertyObjectValue($property, $dv);
             }
         }
     }
     return $derivedProperties;
 }
	protected function getPropertyDescription( $propertyname, &$setNS, &$label, &$relatedArticles ) {
		global $smwgSMWBetaCompatible; // support for old * printouts of beta
		wfLoadExtensionMessages( 'SemanticMediaWiki' );
		$this->readChunk(); // consume separator ":=" or "::"
		// first process property chain syntax (e.g. "property1.property2::value"):
		if ( $propertyname { 0 } == ' ' ) { // escape
			$propertynames = array( $propertyname );
		} else {
			$propertynames = explode( '.', $propertyname );
		}
		$properties = array();
		$typeid = '_wpg';
		foreach ( $propertynames as $name ) {
			if ( $typeid != '_wpg' ) { // non-final property in chain was no wikipage: not allowed
				$this->m_errors[] = wfMsgForContent( 'smw_valuesubquery', $prevname );
				return NULL; // /TODO: read some more chunks and try to finish [[ ]]
			}
			$property = SMWPropertyValue::makeUserProperty( $name );
			if ( !$property->isValid() ) { // illegal property identifier
				$this->m_errors = array_merge( $this->m_errors, $property->getErrors() );
				return NULL; // /TODO: read some more chunks and try to finish [[ ]]
			}
			$typeid = $property->getTypeID();
			$prevname = $name;
			$properties[] = $property;

			// added by ning
			$relatedArticles[] = array(
				'namespace' => SMW_NS_PROPERTY,
				'title' => $property->getDBkey() );

		} // /NOTE: after iteration, $property and $typeid correspond to last value

		$innerdesc = NULL;
		$continue = true;
		while ( $continue ) {
			$chunk = $this->readChunk();
			switch ( $chunk ) {
				case '+': // wildcard, add namespaces for page-type properties
					if ( ( $this->m_defaultns !== NULL ) && ( $typeid == '_wpg' ) ) {
						$innerdesc = $this->addDescription( $innerdesc, $this->m_defaultns, false );
					} else {
						$innerdesc = $this->addDescription( $innerdesc, new SMWThingDescription(), false );
					}
					$chunk = $this->readChunk();
					break;
				case '<q>': // subquery, set default namespaces
					if ( $typeid == '_wpg' ) {
						$this->pushDelimiter( '</q>' );
						$setsubNS = true;
						$sublabel = '';
						$innerdesc = $this->addDescription( $innerdesc, $this->getSubqueryDescription( $setsubNS, $sublabel ), false );
					} else { // no subqueries allowed for non-pages
						$this->m_errors[] = wfMsgForContent( 'smw_valuesubquery', end( $propertynames ) );
						$innerdesc = $this->addDescription( $innerdesc, new SMWThingDescription(), false );
					}
					$chunk = $this->readChunk();
					break;
				default: // normal object value or print statement
					// read value(s), possibly with inner [[...]]
					$open = 1;
					$value = $chunk;
					$continue2 = true;
					// read value with inner [[, ]], ||
					while ( ( $open > 0 ) && ( $continue2 ) ) {
						$chunk = $this->readChunk( '\[\[|\]\]|\|\||\|' );
						switch ( $chunk ) {
							case '[[': // open new [[ ]]
								$open++;
								break;
							case ']]': // close [[ ]]
								$open--;
								break;
							case '|': case '||': // terminates only outermost [[ ]]
								if ( $open == 1 ) {
									$open = 0;
								}
								break;
							case '': // /TODO: report error; this is not good right now
							$continue2 = false;
							break;
						}
						if ( $open != 0 ) {
							$value .= $chunk;
						}
					} // /NOTE: at this point, we normally already read one more chunk behind the value

					if ( $typeid == '__nry' ) { // nary value
						$dv = SMWDataValueFactory::newPropertyObjectValue( $property );
						$dv->acceptQuerySyntax();
						$dv->setUserValue( $value );
						$vl = $dv->getValueList();
						$pm = $dv->getPrintModifier();
						if ( $vl !== NULL ) { // prefer conditions over print statements (only one possible right now)
							$innerdesc = $this->addDescription( $innerdesc, $vl, false );
						} elseif ( $pm !== false ) {
							if ( $chunk == '|' ) {
								$printlabel = $this->readChunk( '\]\]' );
								if ( $printlabel != ']]' ) {
									$chunk = $this->readChunk( '\]\]' );
								} else {
									$printlabel = '';
									$chunk = ']]';
								}
							} else {
								$printlabel = $property->getWikiValue();
							}
							if ( $chunk == ']]' ) {
								return new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, $printlabel, $property, $pm );
							} else {
								$this->m_errors[] = wfMsgForContent( 'smw_badprintout' );
								return NULL;
							}
						}
					} else { // unary value
						$comparator = SMW_CMP_EQ;
						$printmodifier = '';
						SMWNotifyParser::prepareValue( $value, $comparator, $printmodifier );
						if ( ( $value == '*' ) && $smwgSMWBetaCompatible ) {
							if ( $chunk == '|' ) {
								$printlabel = $this->readChunk( '\]\]' );
								if ( $printlabel != ']]' ) {
									$chunk = $this->readChunk( '\]\]' );
								} else {
									$printlabel = '';
									$chunk = ']]';
								}
							} else {
								$printlabel = $property->getWikiValue();
							}
							if ( $chunk == ']]' ) {
								return new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, $printlabel, $property, $printmodifier );
							} else {
								$this->m_errors[] = wfMsgForContent( 'smw_badprintout' );
								return NULL;
							}
						} else {
							$dv = SMWDataValueFactory::newPropertyObjectValue( $property, $value );
							if ( !$dv->isValid() ) {
								$this->m_errors = $this->m_errors + $dv->getErrors();
								$vd = new SMWThingDescription();
							} else {
								$vd = new SMWValueDescription( $dv, $comparator );
							}
							$innerdesc = $this->addDescription( $innerdesc, $vd, false );
						}
					}
			}
			$continue = ( $chunk == '||' );
		}

		if ( $innerdesc === NULL ) { // make a wildcard search
			if ( ( $this->m_defaultns !== NULL ) && ( $typeid == '_wpg' ) ) {
				$innerdesc = $this->addDescription( $innerdesc, $this->m_defaultns, false );
			} else {
				$innerdesc = $this->addDescription( $innerdesc, new SMWThingDescription(), false );
			}
			$this->m_errors[] = wfMsgForContent( 'smw_propvalueproblem', $property->getWikiValue() );
		}
		$properties = array_reverse( $properties );
		foreach ( $properties as $property ) {
			$innerdesc = new SMWSomeProperty( $property, $innerdesc );
		}
		$result = $innerdesc;
		return $this->finishLinkDescription( $chunk, false, $result, $setNS, $label );
	}
Esempio n. 20
0
 /**
  * This function modifies the given query object at $qid to account for all ordering conditions
  * in the SMWQuery $query. It is always required that $qid is the id of a query that joins with
  * SMW IDs table so that the field alias.smw_title is $available for default sorting.
  *
  * @param integer $qid
  */
 protected function applyOrderConditions($qid)
 {
     $qobj = $this->m_queries[$qid];
     // (1) collect required extra property descriptions:
     $extraproperties = array();
     foreach ($this->m_sortkeys as $propkey => $order) {
         if (!array_key_exists($propkey, $qobj->sortfields)) {
             // Find missing property to sort by.
             if ($propkey === '') {
                 // Sort by first result column (page titles).
                 $qobj->sortfields[$propkey] = "{$qobj->alias}.smw_sortkey";
             } else {
                 // Try to extend query.
                 $sortprop = SMWPropertyValue::makeUserProperty($propkey);
                 if ($sortprop->isValid()) {
                     $extraproperties[] = new SMWSomeProperty($sortprop->getDataItem(), new SMWThingDescription());
                 }
             }
         }
     }
     // (2) compile according conditions and hack them into $qobj:
     if (count($extraproperties) > 0) {
         $desc = new SMWConjunction($extraproperties);
         $newqid = $this->compileQueries($desc);
         $newqobj = $this->m_queries[$newqid];
         // This is always an SMWSQLStore3Query::Q_CONJUNCTION ...
         foreach ($newqobj->components as $cid => $field) {
             // ... so just re-wire its dependencies
             $qobj->components[$cid] = $qobj->joinfield;
             $qobj->sortfields = array_merge($qobj->sortfields, $this->m_queries[$cid]->sortfields);
         }
         $this->m_queries[$qid] = $qobj;
     }
 }
 /**
  * Figures out the label of the property to be used. For outgoing ones it is just
  * the text, for incoming ones we try to figure out the inverse one if needed,
  * either by looking for an explicitly stated one or by creating a default one.
  *
  * @param[in] $property SMWPropertyValue  The property of interest
  * @param[in] $incoming bool  If it is an incoming property
  *
  * @return string  The label of the property
  */
 private function getPropertyLabel(\SMWPropertyValue $property, $incoming = false)
 {
     if ($incoming && $this->getOption('showInverse')) {
         $oppositeprop = \SMWPropertyValue::makeUserProperty(wfMessage('smw_inverse_label_property')->text());
         $labelarray = $this->store->getPropertyValues($property->getDataItem()->getDiWikiPage(), $oppositeprop->getDataItem());
         $rv = count($labelarray) > 0 ? $labelarray[0]->getLongWikiText() : wfMessage('smw_inverse_label_default', $property->getWikiValue())->text();
     } else {
         $rv = $property->getWikiValue();
     }
     return $this->unbreak($rv);
 }
 private function initPropertyChain($value)
 {
     $chain = explode('.', $value);
     // Get the last which represents the final output
     // Foo.Bar.Foobar.Baz
     $last = array_pop($chain);
     $this->lastPropertyChainValue = PropertyValue::makeUserProperty($last);
     if (!$this->lastPropertyChainValue->isValid()) {
         return $this->addError($this->lastPropertyChainValue->getErrors());
     }
     $this->lastPropertyChainValue->setOptions($this->getOptions());
     // Generate a forward list from the remaining property labels
     // Foo.Bar.Foobar
     foreach ($chain as $value) {
         $propertyValue = PropertyValue::makeUserProperty($value);
         if (!$propertyValue->isValid()) {
             continue;
         }
         $propertyValue->setOptions($this->getOptions());
         $this->propertyValues[] = $propertyValue;
     }
 }
 /**
  * This function returns to results of a certain query
  * This functions is part of the extension Semantic Tasks by Steren Giannini & Ryan Lane
  * released under GNU GPLv2 (or later)
  * http://www.mediawiki.org/wiki/Extension:Semantic_Tasks
  * @param $query_string String : the query
  * @param $properties_to_display array(String): array of property names to display
  * @param $display_title Boolean : add the page title in the result
  * @return TODO
  */
 static function getQueryResults($query_string, $properties_to_display, $display_title)
 {
     // We use the Semantic MediaWiki Processor
     // $smwgIP is defined by Semantic MediaWiki, and we don't allow
     // this file to be sourced unless Semantic MediaWiki is included.
     global $smwgIP;
     include_once $smwgIP . "/includes/query/SMW_QueryProcessor.php";
     $params = array();
     $inline = true;
     $printlabel = "";
     $printouts = array();
     // add the page name to the printouts
     if ($display_title) {
         if (version_compare(SMW_VERSION, '1.7', '>')) {
             SMWQueryProcessor::addThisPrintout($printouts, $params);
         } else {
             $to_push = new SMWPrintRequest(SMWPrintRequest::PRINT_THIS, $printlabel);
             array_push($printouts, $to_push);
         }
     }
     // Push the properties to display in the printout array.
     foreach ($properties_to_display as $property) {
         if (class_exists('SMWPropertyValue')) {
             // SMW 1.4
             $to_push = new SMWPrintRequest(SMWPrintRequest::PRINT_PROP, $property, SMWPropertyValue::makeUserProperty($property));
         } else {
             $to_push = new SMWPrintRequest(SMWPrintRequest::PRINT_PROP, $property, Title::newFromText($property, SMW_NS_PROPERTY));
         }
         array_push($printouts, $to_push);
     }
     if (version_compare(SMW_VERSION, '1.6.1', '>')) {
         $params = SMWQueryProcessor::getProcessedParams($params, $printouts);
         $format = null;
     } else {
         $format = 'auto';
     }
     $query = SMWQueryProcessor::createQuery($query_string, $params, $inline, $format, $printouts);
     $results = smwfGetStore()->getQueryResult($query);
     return $results;
 }
Esempio n. 24
0
 /**
  * This method adds a new property with the given value to the storage. It is
  * intended to be used on user input, and property and value are sepcified by
  * strings as they might be found in a wiki. The function returns a datavalue
  * object that contains the result of the operation.
  *
  * @param string $propertyName
  * @param string $value
  * @param mixed $caption string or false
  * @param Parser $parser
  * @param boolean $storeAnnotation
  *
  * @return SMWDataValue
  */
 public static function addProperty($propertyName, $value, $caption, Parser $parser, $storeAnnotation = true)
 {
     wfProfileIn('SMWParseData::addProperty (SMW)');
     // See if this property is a special one, such as e.g. "has type".
     $propertyDv = SMWPropertyValue::makeUserProperty($propertyName);
     if (!$propertyDv->isValid()) {
         wfProfileOut('SMWParseData::addProperty (SMW)');
         return $propertyDv;
     }
     $propertyDi = $propertyDv->getDataItem();
     // FIXME: this solves the issue of bug 29438, but is probably not what we want to do.
     if ($propertyDi instanceof SMWDIError) {
         wfProfileOut('SMWParseData::addProperty (SMW)');
         return $propertyDv;
     }
     $semandticData = self::getSMWData($parser);
     $result = SMWDataValueFactory::newPropertyObjectValue($propertyDi, $value, $caption, $semandticData->getSubject());
     if ($propertyDi->isInverse()) {
         $result->addError(wfMsgForContent('smw_noinvannot'));
     } elseif ($storeAnnotation && !is_null(self::getSMWData($parser))) {
         $semandticData->addPropertyObjectValue($propertyDi, $result->getDataItem());
         // Take note of the error for storage (do this here and not in storage, thus avoiding duplicates).
         if (!$result->isValid()) {
             $semandticData->addPropertyObjectValue(new SMWDIProperty('_ERRP'), $propertyDi->getDiWikiPage());
         }
     }
     wfProfileOut('SMWParseData::addProperty (SMW)');
     return $result;
 }
 private static function getAllValuesForProperty($property_name, $substring, $basePropertyName = null, $baseValue = null)
 {
     global $sfgMaxAutocompleteValues, $sfgCacheAutocompleteValues, $sfgAutocompleteCacheTimeout;
     global $smwgDefaultStore;
     $values = array();
     $db = wfGetDB(DB_SLAVE);
     $sqlOptions = array();
     $sqlOptions['LIMIT'] = $sfgMaxAutocompleteValues;
     $property = SMWPropertyValue::makeUserProperty($property_name);
     $propertyHasTypePage = $property->getPropertyTypeID() == '_wpg';
     $property_name = str_replace(' ', '_', $property_name);
     $conditions = array('p_ids.smw_title' => $property_name);
     // Use cache if allowed
     if ($sfgCacheAutocompleteValues) {
         $cache = SFFormUtils::getFormCache();
         // Remove trailing whitespace to avoid unnecessary database selects
         $cacheKeyString = $property_name . '::' . rtrim($substring);
         if (!is_null($basePropertyName)) {
             $cacheKeyString .= ',' . $basePropertyName . ',' . $baseValue;
         }
         $cacheKey = wfMemcKey('sf-autocomplete', md5($cacheKeyString));
         $values = $cache->get($cacheKey);
         if (!empty($values)) {
             // Return with results immediately
             return $values;
         }
     }
     if ($propertyHasTypePage) {
         $valueField = 'o_ids.smw_title';
         if ($smwgDefaultStore === 'SMWSQLStore3') {
             $idsTable = $db->tableName('smw_object_ids');
             $propsTable = $db->tableName('smw_di_wikipage');
         } else {
             $idsTable = $db->tableName('smw_ids');
             $propsTable = $db->tableName('smw_rels2');
         }
         $fromClause = "{$propsTable} p JOIN {$idsTable} p_ids ON p.p_id = p_ids.smw_id JOIN {$idsTable} o_ids ON p.o_id = o_ids.smw_id";
     } else {
         if ($smwgDefaultStore === 'SMWSQLStore3') {
             $valueField = 'p.o_hash';
             $idsTable = $db->tableName('smw_object_ids');
             $propsTable = $db->tableName('smw_di_blob');
         } else {
             $valueField = 'p.value_xsd';
             $idsTable = $db->tableName('smw_ids');
             $propsTable = $db->tableName('smw_atts2');
         }
         $fromClause = "{$propsTable} p JOIN {$idsTable} p_ids ON p.p_id = p_ids.smw_id";
     }
     if (!is_null($basePropertyName)) {
         $baseProperty = SMWPropertyValue::makeUserProperty($basePropertyName);
         $basePropertyHasTypePage = $baseProperty->getPropertyTypeID() == '_wpg';
         $basePropertyName = str_replace(' ', '_', $basePropertyName);
         $conditions['base_p_ids.smw_title'] = $basePropertyName;
         if ($basePropertyHasTypePage) {
             if ($smwgDefaultStore === 'SMWSQLStore3') {
                 $idsTable = $db->tableName('smw_object_ids');
                 $propsTable = $db->tableName('smw_di_wikipage');
             } else {
                 $idsTable = $db->tableName('smw_ids');
                 $propsTable = $db->tableName('smw_rels2');
             }
             $fromClause .= " JOIN {$propsTable} p_base ON p.s_id = p_base.s_id";
             $fromClause .= " JOIN {$idsTable} base_p_ids ON p_base.p_id = base_p_ids.smw_id JOIN {$idsTable} base_o_ids ON p_base.o_id = base_o_ids.smw_id";
             $baseValue = str_replace(' ', '_', $baseValue);
             $conditions['base_o_ids.smw_title'] = $baseValue;
         } else {
             if ($smwgDefaultStore === 'SMWSQLStore3') {
                 $baseValueField = 'p_base.o_hash';
                 $idsTable = $db->tableName('smw_object_ids');
                 $propsTable = $db->tableName('smw_di_blob');
             } else {
                 $baseValueField = 'p_base.value_xsd';
                 $idsTable = $db->tableName('smw_ids');
                 $propsTable = $db->tableName('smw_atts2');
             }
             $fromClause .= " JOIN {$propsTable} p_base ON p.s_id = p_base.s_id";
             $fromClause .= " JOIN {$idsTable} base_p_ids ON p_base.p_id = base_p_ids.smw_id";
             $conditions[$baseValueField] = $baseValue;
         }
     }
     if (!is_null($substring)) {
         // "Page" type property valeus are stored differently
         // in the DB, i.e. underlines instead of spaces.
         $conditions[] = SFUtils::getSQLConditionForAutocompleteInColumn($valueField, $substring, $propertyHasTypePage);
     }
     $sqlOptions['ORDER BY'] = $valueField;
     $res = $db->select($fromClause, "DISTINCT {$valueField}", $conditions, __METHOD__, $sqlOptions);
     while ($row = $db->fetchRow($res)) {
         $values[] = str_replace('_', ' ', $row[0]);
     }
     $db->freeResult($res);
     if ($sfgCacheAutocompleteValues) {
         // Save to cache.
         $cache->set($cacheKey, $values, $sfgAutocompleteCacheTimeout);
     }
     return $values;
 }
Esempio n. 26
0
 private function collectedRequiredExtraPropertyDescriptions($qobj)
 {
     $extraProperties = array();
     foreach ($this->sortKeys as $propkey => $order) {
         if (!is_string($propkey)) {
             throw new RuntimeException("Expected a string value as sortkey");
         }
         if (!array_key_exists($propkey, $qobj->sortfields)) {
             // Find missing property to sort by.
             if ($propkey === '') {
                 // Sort by first result column (page titles).
                 $qobj->sortfields[$propkey] = "{$qobj->alias}.smw_sortkey";
             } else {
                 // Try to extend query.
                 $sortprop = PropertyValue::makeUserProperty($propkey);
                 if ($sortprop->isValid()) {
                     $extraProperties[] = new SomeProperty($sortprop->getDataItem(), new ThingDescription());
                 }
             }
         }
     }
     return $extraProperties;
 }
Esempio n. 27
0
 /**
  * Parse a property description (the part of an inline query that
  * is in between "[[Some property::" and the closing "]]" and create a
  * suitable description. The "::" is the first chunk on the current
  * string.
  */
 private function getPropertyDescription($propertyName, &$setNS)
 {
     $this->readChunk();
     // consume separator ":=" or "::"
     // first process property chain syntax (e.g. "property1.property2::value"), escaped by initial " ":
     $propertynames = $propertyName[0] == ' ' ? array($propertyName) : explode('.', $propertyName);
     $properties = array();
     $typeid = '_wpg';
     $inverse = false;
     foreach ($propertynames as $name) {
         if (!$this->isPagePropertyType($typeid)) {
             // non-final property in chain was no wikipage: not allowed
             $this->errorMessages[] = wfMessage('smw_valuesubquery', $name)->inContentLanguage()->text();
             return null;
             ///TODO: read some more chunks and try to finish [[ ]]
         }
         $property = SMWPropertyValue::makeUserProperty($name);
         if (!$property->isValid()) {
             // illegal property identifier
             $this->errorMessages = array_merge($this->errorMessages, $property->getErrors());
             return null;
             ///TODO: read some more chunks and try to finish [[ ]]
         }
         $typeid = $property->getDataItem()->findPropertyTypeID();
         $inverse = $property->isInverse();
         $properties[] = $property;
     }
     ///NOTE: after iteration, $property and $typeid correspond to last value
     $innerdesc = null;
     $continue = true;
     while ($continue) {
         $chunk = $this->readChunk();
         switch ($chunk) {
             case '+':
                 // wildcard, add namespaces for page-type properties
                 if (!is_null($this->defaultNamespace) && ($this->isPagePropertyType($typeid) || $inverse)) {
                     $innerdesc = $this->addDescription($innerdesc, $this->defaultNamespace, false);
                 } else {
                     $innerdesc = $this->addDescription($innerdesc, new ThingDescription(), false);
                 }
                 $chunk = $this->readChunk();
                 break;
             case '<q>':
                 // subquery, set default namespaces
                 if ($this->isPagePropertyType($typeid) || $inverse) {
                     $this->pushDelimiter('</q>');
                     $setsubNS = true;
                     $innerdesc = $this->addDescription($innerdesc, $this->getSubqueryDescription($setsubNS), false);
                 } else {
                     // no subqueries allowed for non-pages
                     $this->errorMessages[] = wfMessage('smw_valuesubquery', end($propertynames))->inContentLanguage()->text();
                     $innerdesc = $this->addDescription($innerdesc, new ThingDescription(), false);
                 }
                 $chunk = $this->readChunk();
                 break;
             default:
                 // normal object value
                 // read value(s), possibly with inner [[...]]
                 $open = 1;
                 $value = $chunk;
                 $continue2 = true;
                 // read value with inner [[, ]], ||
                 while ($open > 0 && $continue2) {
                     $chunk = $this->readChunk('\\[\\[|\\]\\]|\\|\\||\\|');
                     switch ($chunk) {
                         case '[[':
                             // open new [[ ]]
                             $open++;
                             break;
                         case ']]':
                             // close [[ ]]
                             $open--;
                             break;
                         case '|':
                         case '||':
                             // terminates only outermost [[ ]]
                             if ($open == 1) {
                                 $open = 0;
                             }
                             break;
                         case '':
                             ///TODO: report error; this is not good right now
                             $continue2 = false;
                             break;
                     }
                     if ($open != 0) {
                         $value .= $chunk;
                     }
                 }
                 ///NOTE: at this point, we normally already read one more chunk behind the value
                 $dv = \SMW\DataValueFactory::getInstance()->newPropertyObjectValue($property->getDataItem());
                 $dv->setQueryConditionUsage(true);
                 $vd = $dv->getQueryDescription($value);
                 $innerdesc = $this->addDescription($innerdesc, $vd, false);
                 $this->errorMessages = $this->errorMessages + $dv->getErrors();
         }
         $continue = $chunk == '||';
     }
     if (is_null($innerdesc)) {
         // make a wildcard search
         $innerdesc = !is_null($this->defaultNamespace) && $this->isPagePropertyType($typeid) ? $this->addDescription($innerdesc, $this->defaultNamespace, false) : $this->addDescription($innerdesc, new ThingDescription(), false);
         $this->errorMessages[] = wfMessage('smw_propvalueproblem', $property->getWikiValue())->inContentLanguage()->text();
     }
     $properties = array_reverse($properties);
     foreach ($properties as $property) {
         $innerdesc = new SomeProperty($property->getDataItem(), $innerdesc);
     }
     $result = $innerdesc;
     return $this->finishLinkDescription($chunk, false, $result, $setNS);
 }
 public function setIsSPQRQLQuery($isSPARQL)
 {
     $propertyValue = SMWPropertyValue::makeUserProperty(QRC_ISQ_LABEL);
     $dataValue = SMWDataValueFactory::newPropertyObjectValue($propertyValue, $isSPARQL);
     $this->m_data->addPropertyObjectValue($propertyValue, $dataValue);
 }
 /**
 * Create an SMWPrintRequest object from a string description as one
 * would normally use in #ask and related inputs. The string must start
 * with a "?" and may contain label and formatting parameters after "="
 * or "#", respectively. However, further parameters, given in #ask by
 * "|+param=value" are not allowed here; they must be added
 * individually.
 *
 * @param string $printRequestString
 * @param boolean $showMode
 *
 *@return PrintRequest||null
 * @since 1.8
 */
 protected static function getSMWPrintRequestFromString($printRequestString, $showMode)
 {
     global $wgContLang;
     $parts = explode('=', $printRequestString, 2);
     $propparts = explode('#', $parts[0], 2);
     $data = null;
     if (trim($propparts[0]) === '') {
         // print "this"
         $printmode = PrintRequest::PRINT_THIS;
         $label = '';
         // default
     } elseif ($wgContLang->getNsText(NS_CATEGORY) == ucfirst(trim($propparts[0]))) {
         // print categories
         $printmode = PrintRequest::PRINT_CATS;
         $label = $showMode ? '' : $wgContLang->getNSText(NS_CATEGORY);
         // default
     } else {
         // print property or check category
         $title = Title::newFromText(trim($propparts[0]), SMW_NS_PROPERTY);
         // trim needed for \n
         if (is_null($title)) {
             // not a legal property/category name; give up
             return null;
         }
         if ($title->getNamespace() == NS_CATEGORY) {
             $printmode = PrintRequest::PRINT_CCAT;
             $data = $title;
             $label = $showMode ? '' : $title->getText();
             // default
         } else {
             // enforce interpretation as property (even if it starts with something that looks like another namespace)
             $printmode = PrintRequest::PRINT_PROP;
             $data = SMWPropertyValue::makeUserProperty(trim($propparts[0]));
             if (!$data->isValid()) {
                 // not a property; give up
                 return null;
             }
             $label = $showMode ? '' : $data->getWikiValue();
             // default
         }
     }
     if (count($propparts) == 1) {
         // no outputformat found, leave empty
         $propparts[] = false;
     } elseif (trim($propparts[1]) === '') {
         // "plain printout", avoid empty string to avoid confusions with "false"
         $propparts[1] = '-';
     }
     if (count($parts) > 1) {
         // label found, use this instead of default
         $label = trim($parts[1]);
     }
     try {
         return new PrintRequest($printmode, $label, $data, trim($propparts[1]));
     } catch (InvalidArgumentException $e) {
         // something still went wrong; give up
         return null;
     }
 }
	/**
	 * This function is the real heart of the entire Semantic Forms
	 * extension. It handles two main actions: (1) displaying a form on the
	 * screen, given a form definition and possibly page contents (if an
	 * existing page is being edited); and (2) creating actual page
	 * contents, if the form was already submitted by the user.
	 *
	 * It also does some related tasks, like figuring out the page name (if
	 * only a page formula exists).
	 */
	function formHTML( $form_def, $form_submitted, $source_is_page, $form_id = null, $existing_page_content = null, $page_name = null, $page_name_formula = null, $is_query = false, $is_embedded = false ) {
		global $wgRequest, $wgUser, $wgParser;
		global $sfgTabIndex; // used to represent the current tab index in the form
		global $sfgFieldNum; // used for setting various HTML IDs

		wfProfileIn( __METHOD__ );

		// initialize some variables
		$sfgTabIndex = 1;
		$sfgFieldNum = 1;
		$source_page_matches_this_form = false;
		$form_page_title = null;
		$generated_page_name = $page_name_formula;
		// $form_is_partial is true if:
		// (a) 'partial' == 1 in the arguments
		// (b) 'partial form' is found in the form definition
		// in the latter case, it may remain false until close to the end of
		// the parsing, so we have to assume that it will become a possibility
		$form_is_partial = false;
		$new_text = "";
		// flag for placing "<onlyinclude>" tags in form output
		$onlyinclude_free_text = false;

		// If we have existing content and we're not in an active replacement
		// situation, preserve the original content. We do this because we want
		// to pass the original content on IF this is a partial form.
		// TODO: A better approach here would be to pass the revision ID of the
		// existing page content through the replace value, which would
		// minimize the html traffic and would allow us to do a concurrent
		// update check. For now, we pass it through a hidden text field.

		if ( ! $wgRequest->getCheck( 'partial' ) ) {
			$original_page_content = $existing_page_content;
		} else {
			$original_page_content = null;
			if ( $wgRequest->getCheck( 'free_text' ) ) {
				$existing_page_content = $wgRequest->getVal( 'free_text' );
				$form_is_partial = true;
			}
		}

		// Disable all form elements if user doesn't have edit
		// permission - two different checks are needed, because
		// editing permissions can be set in different ways.
		// HACK - sometimes we don't know the page name in advance, but
		// we still need to set a title here for testing permissions.
		if ( $is_embedded ) {
			// If this is an embedded form (probably a 'RunQuery'),
			// just use the name of the actual page we're on.
			global $wgTitle;
			$this->mPageTitle = $wgTitle;
		} elseif ( $is_query ) {
			$this->mPageTitle = Title::newFromText( 'RunQuery dummy title' );
		} elseif ( $page_name === '' ) {
			$this->mPageTitle = Title::newFromText(
				$wgRequest->getVal( 'namespace' ) . ":Semantic Forms permissions test" );
		} else {
			$this->mPageTitle = Title::newFromText( $page_name );
		}

		global $wgOut;
		// show previous set of deletions for this page, if it's been deleted before
		if ( ! $form_submitted && ( $this->mPageTitle && !$this->mPageTitle->exists() ) ) {
			$this->showDeletionLog( $wgOut );
		}
		// Unfortunately, we can't just call userCan() here because, as of MW 1.16,
		// it has a bug in which it ignores a setting of
		// "$wgEmailConfirmToEdit = true;". Instead, we'll just get the
		// permission errors from the start, and use those to determine whether
		// the page is editable.
		if ( !$is_query ) {
			// $userCanEditPage = ( $wgUser->isAllowed( 'edit' ) && $this->mPageTitle->userCan( 'edit' ) );
			$permissionErrors = $this->mPageTitle->getUserPermissionsErrors( 'edit', $wgUser );
			$userCanEditPage = count( $permissionErrors ) == 0;
			wfRunHooks( 'sfUserCanEditPage', array( $this->mPageTitle, &$userCanEditPage ) );
		}
		$form_text = "";
		if ( $is_query || $userCanEditPage ) {
			$form_is_disabled = false;
			// Show "Your IP address will be recorded" warning if
			// user is anonymous, and it's not a query -
			// wiki-text for bolding has to be replaced with HTML.
			if ( $wgUser->isAnon() && ! $is_query ) {
				$anon_edit_warning = preg_replace( "/'''(.*)'''/", "<strong>$1</strong>", wfMsg( 'anoneditwarning' ) );
				$form_text .= "<p>$anon_edit_warning</p>\n";
			}
		} else {
			$form_is_disabled = true;
			$wgOut->setPageTitle( wfMsg( 'badaccess' ) );
			$wgOut->addWikiText( $wgOut->formatPermissionsErrorMessage( $permissionErrors, 'edit' ) );
			$wgOut->addHTML( "\n<hr />\n" );
		}

		$oldParser = $wgParser;

		$wgParser = unserialize( serialize( $oldParser ) ); // deep clone of parser
		$wgParser->Options( ParserOptions::newFromUser( $wgUser ) );
		$wgParser->Title( $this->mPageTitle );
		$wgParser->clearState();

		$form_def = SFFormUtils::getFormDefinition( $wgParser, $form_def, $form_id );

		// Turn form definition file into an array of sections, one for each
		// template definition (plus the first section)
		$form_def_sections = array();
		$start_position = 0;
		$section_start = 0;
		$free_text_was_included = false;
		$free_text_preload_page = null;
		$free_text_components = array();
		$all_values_for_template = array();
		// Unencode any HTML-encoded representations of curly brackets and
		// pipes - this is a hack to allow for forms to include templates
		// that themselves contain form elements - the escaping was needed
		// to make sure that those elements don't get parsed too early.
		$form_def = str_replace( array( '&#123;', '&#124;', '&#125;' ), array( '{', '|', '}' ), $form_def );
		// And another hack - replace the 'free text' standard input with
		// a field declaration to get it to be handled as a field.
		$form_def = str_replace( 'standard input|free text', 'field|<freetext>', $form_def );
		while ( $brackets_loc = strpos( $form_def, "{{{", $start_position ) ) {
			$brackets_end_loc = strpos( $form_def, "}}}", $brackets_loc );
			$bracketed_string = substr( $form_def, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) );
			$tag_components = SFUtils::getFormTagComponents( $bracketed_string );
			$tag_title = trim( $tag_components[0] );
			if ( $tag_title == 'for template' || $tag_title == 'end template' ) {
				// Create a section for everything up to here
				$section = substr( $form_def, $section_start, $brackets_loc - $section_start );
				$form_def_sections[] = $section;
				$section_start = $brackets_loc;
			}
			$start_position = $brackets_loc + 1;
		} // end while
		$form_def_sections[] = trim( substr( $form_def, $section_start ) );

		// Cycle through the form definition file, and possibly an
		// existing article as well, finding template and field
		// declarations and replacing them with form elements, either
		// blank or pre-populated, as appropriate.
		$all_fields = array();
		$data_text = "";
		$template_name = "";
		$allow_multiple = false;
		$instance_num = 0;
		$all_instances_printed = false;
		$strict_parsing = false;

		// Placeholder name in the form
		$curPlaceholder = null;
		// Used to store the HTML code of the multiple template, to reinsert it into the right spot
		// This array will keep track of all the replaced @<name>@ strings
		$placeholderFields = array();

		for ( $section_num = 0; $section_num < count( $form_def_sections ); $section_num++ ) {
			$start_position = 0;
			$template_text = "";
			// the append is there to ensure that the original
			// array doesn't get modified; is it necessary?
			$section = " " . $form_def_sections[$section_num];


			$multipleTemplateString = "";

			while ( $brackets_loc = strpos( $section, '{{{', $start_position ) ) {
				$brackets_end_loc = strpos( $section, "}}}", $brackets_loc );
				$bracketed_string = substr( $section, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) );
				$tag_components = SFUtils::getFormTagComponents( $bracketed_string );
				$tag_title = trim( $tag_components[0] );
				// =====================================================
				// for template processing
				// =====================================================
				if ( $tag_title == 'for template' ) {
					$old_template_name = $template_name;
					$template_name = trim( $tag_components[1] );
					$tif = SFTemplateInForm::create( $template_name );
					$query_template_name = str_replace( ' ', '_', $template_name );
					$add_button_text = wfMsg( 'sf_formedit_addanother' );
					// Also replace periods with underlines, since that's what
					// POST does to strings anyway.
					$query_template_name = str_replace( '.', '_', $query_template_name );
					// ...and escape apostrophes.
					$query_template_name = str_replace( "'", "\'", $query_template_name );
					// Cycle through the other components.
					for ( $i = 2; $i < count( $tag_components ); $i++ ) {
						$component = $tag_components[$i];
						if ( $component == 'multiple' ) $allow_multiple = true;
						if ( $component == 'strict' ) $strict_parsing = true;
						$sub_components = array_map( 'trim', explode( '=', $component, 2 ) );
						if ( count( $sub_components ) == 2 ) {
							if ( $sub_components[0] == 'label' ) {
								$template_label = $sub_components[1];
							} elseif ( $sub_components[0] == 'add button text' ) {
								$add_button_text = $sub_components[1];
							} elseif ( $sub_components[0] == 'embed in field' ) {
								// Placeholder on form template level. Assume that the template form def
								// will have a multiple+placeholder parameters, and get the placeholder value.
								// We expect something like TemplateName[fieldName], and convert it to the
								// TemplateName___fieldName form used internally.
								preg_match( '/\s*(.*)\[(.*)\]\s*/', $sub_components[1], $matches );
								$curPlaceholder = ( count( $matches ) > 2 ) ? self::placeholderFormat( $matches[1], $matches[2] ) : null;
								unset ( $matches );
							}
						}
					}
					// If this is the first instance, add
					// the label into the form, if there is
					// one, and add the appropriate wrapper
					// div, if this is a multiple-instance
					// template.
					if ( $old_template_name != $template_name ) {
						if ( isset( $template_label ) ) {
							$multipleTemplateString .= "<fieldset>\n";
							$multipleTemplateString .= "<legend>$template_label</legend>\n";
						}
						// If $curPlaceholder is set, it means we want to insert a
						// multiple template form's HTML into the main form's HTML.
 						// So, the HTML will be stored in $multipleTemplateString.
 						if ( $allow_multiple ) {
 							$multipleTemplateString .= "\t" . '<div class="multipleTemplateWrapper">' . "\n";
 							$multipleTemplateString .= "\t" . '<div class="multipleTemplateList">' . "\n";
 						}
					}
					if ( $curPlaceholder == null ) {
						$form_text .= $multipleTemplateString;
					}
					$template_text .= "{{" . $template_name;
					$all_fields = $tif->getAllFields();
					// remove template tag
					$section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
					$template_instance_query_values = $wgRequest->getArray( $query_template_name );
					// If we are editing a page, and this
					// template can be found more than
					// once in that page, and multiple
					// values are allowed, repeat this
					// section.
					$existing_template_text = null;
					if ( $source_is_page || $form_is_partial ) {
						// Replace underlines with spaces in template name, to allow for
						// searching on either.
						$search_template_str = str_replace( '_', ' ', $template_name );
						$preg_match_template_str = str_replace(
							array( '/', '(', ')' ),
							array( '\/', '\(', '\)' ),
							$search_template_str );
						$found_instance = preg_match( '/{{' . $preg_match_template_str . '\s*[\|}]/i', str_replace( '_', ' ', $existing_page_content ) );
						if ( $allow_multiple ) {
							// find instances of this template in the page -
							// if there's at least one, re-parse this section of the
							// definition form for the subsequent template instances in
							// this page; if there's none, don't include fields at all.
							// there has to be a more efficient way to handle multiple
							// instances of templates, one that doesn't involve re-parsing
							// the same tags, but I don't know what it is.
							if ( $found_instance ) {
								$instance_num++;
							} else {
								$all_instances_printed = true;
							}
						}
						// get the first instance of this template on the page being edited,
						// even if there are more
						if ( $found_instance ) {
							$matches = array();
							$search_pattern = '/{{' . $preg_match_template_str . '\s*[\|}]/i';
							$content_str = str_replace( '_', ' ', $existing_page_content );
							preg_match( $search_pattern, $content_str, $matches, PREG_OFFSET_CAPTURE );
							// is this check necessary?
							if ( array_key_exists( 0, $matches ) && array_key_exists( 1, $matches[0] ) ) {
								$start_char = $matches[0][1];
								$fields_start_char = $start_char + 2 + strlen( $search_template_str );
								// Skip ahead to the first real character.
								while ( in_array( $existing_page_content[$fields_start_char], array( ' ', '\n' ) ) ) {
									$fields_start_char++;
								}
								// If the next character is a pipe, skip that too.
								if ( $existing_page_content[$fields_start_char] == '|' ) {
									$fields_start_char++;
								}
								$template_contents = array( '0' => '' );
								// Cycle through template call, splitting it up by pipes ('|'),
								// except when that pipe is part of a piped link.
								$field = "";
								$uncompleted_square_brackets = 0;
								$uncompleted_curly_brackets = 2;
								$template_ended = false;
								for ( $i = $fields_start_char; ! $template_ended && ( $i < strlen( $existing_page_content ) ); $i++ ) {
									$c = $existing_page_content[$i];
									if ( $c == '[' ) {
										$uncompleted_square_brackets++;
									} elseif ( $c == ']' && $uncompleted_square_brackets > 0 ) {
										$uncompleted_square_brackets--;
									} elseif ( $c == '{' ) {
										$uncompleted_curly_brackets++;
									} elseif ( $c == '}' && $uncompleted_curly_brackets > 0 ) {
										$uncompleted_curly_brackets--;
									}
									// handle an end to a field and/or template declaration
									$template_ended = ( $uncompleted_curly_brackets == 0 && $uncompleted_square_brackets == 0 );
									$field_ended = ( $c == '|' && $uncompleted_square_brackets == 0 && $uncompleted_curly_brackets <= 2 );
									if ( $template_ended || $field_ended ) {
										// if this was the last character in the template, remove
										// the closing curly brackets
										if ( $template_ended ) {
											$field = substr( $field, 0, - 1 );
										}
										// either there's an equals sign near the beginning or not -
										// handling is similar in either way; if there's no equals
										// sign, the index of this field becomes the key
										$sub_fields = explode( '=', $field, 2 );
										if ( count( $sub_fields ) > 1 ) {
											$template_contents[trim( $sub_fields[0] )] = trim( $sub_fields[1] );
										} else {
											$template_contents[] = trim( $sub_fields[0] );
										}
										$field = '';
									} else {
										$field .= $c;
									}
								}
								// If there are uncompleted opening brackets, the whole form will get messed up -
								// display a warning.
								// (If there are too many *closing* brackets, some template stuff will end up in
								// the "free text" field - which is bad, but it's harder for the code to detect
								// the problem - though hopefully, easier for users.)
								if ( $uncompleted_curly_brackets > 0 || $uncompleted_square_brackets > 0 ) {
									$form_text .= "\t" . '<div class="warningbox">' . wfMsg( 'sf_formedit_mismatchedbrackets', $this->mPageTitle->getFullURL( array( 'action' => 'edit' ) ) ) . "</div>\n<br clear=\"both\" />\n";
								}
								$existing_template_text = substr( $existing_page_content, $start_char, $i - $start_char );
								// now remove this template from the text being edited
								// if this is a partial form, establish a new insertion point
								if ( $existing_page_content && $form_is_partial && $wgRequest->getCheck( 'partial' ) ) {
									// if something already exists, set the new insertion point
									// to its position; otherwise just let it lie
									if ( strpos( $existing_page_content, $existing_template_text ) !== false ) {
										$existing_page_content = str_replace( '{{{insertionpoint}}}', '', $existing_page_content );
										$existing_page_content = str_replace( $existing_template_text, '{{{insertionpoint}}}', $existing_page_content );
									}
								} else {
									$existing_page_content = $this->strReplaceFirst( $existing_template_text, '', $existing_page_content );
								}
								// If this is not a multiple-instance template, and we've found
								// a match in the source page, there's a good chance that this
								// page was created with this form - note that, so we don't
								// send the user a warning
								// (multiple-instance templates have a greater chance of
								// getting repeated from one form to the next)
								// - on second thought, allow even the presence of multiple-
								// instance templates to validate that this is the correct
								// form: the problem is that some forms contain *only* mutliple-
								// instance templates.
								// if (! $allow_multiple) {
								$source_page_matches_this_form = true;
								// }
							}
						}
					}
					// If the input is from the form (meaning the user has hit one
					// of the bottom row of buttons), and we're dealing with a
					// multiple template, get the values for this instance of this
					// template, then delete them from the array, so we can get the
					// next group next time - the next() command for arrays doesn't
					// seem to work here.
					if ( ( ! $source_is_page ) && $allow_multiple && $wgRequest ) {
						$all_instances_printed = true;
						if ( $old_template_name != $template_name ) {
							$all_values_for_template = $wgRequest->getArray( $query_template_name );
						}
						if ( $all_values_for_template ) {
							$cur_key = key( $all_values_for_template );
							// skip the input coming in from the "starter" div
							// TODO: this code is probably no longer necessary
							if ( $cur_key == 'num' ) {
								unset( $all_values_for_template[$cur_key] );
								$cur_key = key( $all_values_for_template );
							}
							if ( $template_instance_query_values = current( $all_values_for_template ) ) {
								$all_instances_printed = false;
								unset( $all_values_for_template[$cur_key] );
							}
						}
					}
				// =====================================================
				// end template processing
				// =====================================================
				} elseif ( $tag_title == 'end template' ) {
					if ( $source_is_page ) {
						// Add any unhandled template fields in the page as hidden variables.
						if ( isset( $template_contents ) ) {
							$form_text .= SFFormUtils::unhandledFieldsHTML( $template_name, $template_contents );
							$template_contents = null;
						}
					}
					// Remove this tag, reset some variables, and close off form HTML tag.
					$section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
					$template_name = null;
					if ( isset( $template_label ) && $curPlaceholder == null ) {
						$form_text .= "</fieldset>\n";
						unset ( $template_label );
					}
					$allow_multiple = false;
					$all_instances_printed = false;
					$instance_num = 0;
				// =====================================================
				// field processing
				// =====================================================
				} elseif ( $tag_title == 'field' ) {
					$field_name = trim( $tag_components[1] );
					$fullFieldName = $template_name . '[' . $field_name . ']';
					// cycle through the other components
					$is_mandatory = false;
					$is_hidden = false;
					$is_restricted = false;
					$is_uploadable = false;
					$is_list = false;
					$input_type = null;
					$field_args = array();
					$show_on_select = array();
					$default_value = null;
					$values = null;
					$possible_values = null;
					$semantic_property = null;
					$preload_page = null;
					$holds_template = false;

					for ( $i = 2; $i < count( $tag_components ); $i++ ) {

						$component = trim( $tag_components[$i] );

						if ( $component == 'mandatory' ) {
							$is_mandatory = true;
						} elseif ( $component == 'hidden' ) {
							$is_hidden = true;
						} elseif ( $component == 'restricted' ) {
							$is_restricted = ( ! $wgUser || ! $wgUser->isAllowed( 'editrestrictedfields' ) );
						} elseif ( $component == 'list' ) {
							$is_list = true;
						} elseif ( $component == 'edittools' ) { // free text only
							$free_text_components[] = 'edittools';
						}

						$sub_components = array_map( 'trim', explode( '=', $component, 2 ) );

						if ( count( $sub_components ) == 1 ) {
							// add handling for single-value params, for custom input types
							$field_args[$sub_components[0]] = true;

							if ( $component == 'holds template' ) {
								$is_hidden = true;
								$holds_template = true;
								$placeholderFields[] = self::placeholderFormat( $template_name, $field_name );
							}
						} elseif ( count( $sub_components ) == 2 ) {
							// First, set each value as its own entry in $field_args.
							$field_args[$sub_components[0]] = $sub_components[1];

							// Then, do all special handling.
							if ( $sub_components[0] == 'input type' ) {
								$input_type = $sub_components[1];
							} elseif ( $sub_components[0] == 'default' ) {
								$default_value = $wgParser->recursiveTagParse( $sub_components[1] );
							} elseif ( $sub_components[0] == 'preload' ) {
								// free text field has special handling
								if ( $field_name == 'free text' || $field_name == '<freetext>' ) {
									$free_text_preload_page = $sub_components[1];
								} else {
									$preload_page = $sub_components[1];
								}
							} elseif ( $sub_components[0] == 'show on select' ) {
								// html_entity_decode() is needed to turn '&gt;' to '>'
								$vals = explode( ';', html_entity_decode( $sub_components[1] ) );
								foreach ( $vals as $val ) {
									$val = trim( $val );
									if ( empty( $val ) )
										continue;
									$option_div_pair = explode( '=>', $val, 2 );
									if ( count( $option_div_pair ) > 1 ) {
										$option = $option_div_pair[0];
										$div_id = $option_div_pair[1];
										if ( array_key_exists( $div_id, $show_on_select ) )
											$show_on_select[$div_id][] = $option;
										else
											$show_on_select[$div_id] = array( $option );
									} else {
										$show_on_select[$val] = array();
									}
								}
							} elseif ( $sub_components[0] == 'autocomplete on property' ) {
								$property_name = $sub_components[1];
								$propValue = SMWPropertyValue::makeUserProperty( $property_name );
								if ( $propValue->getPropertyTypeID() == '_wpg' ) {
									$field_args['autocomplete field type'] = 'relation';
								} else {
									$field_args['autocomplete field type'] = 'attribute';
								}
								$field_args['autocompletion source'] = $sub_components[1];
							} elseif ( $sub_components[0] == 'autocomplete on category' ) {
								$field_args['autocomplete field type'] = 'category';
								$field_args['autocompletion source'] = $sub_components[1];
							} elseif ( $sub_components[0] == 'autocomplete on concept' ) {
								$field_args['autocomplete field type'] = 'concept';
								$field_args['autocompletion source'] = $sub_components[1];
							} elseif ( $sub_components[0] == 'autocomplete on namespace' ) {
								$field_args['autocomplete field type'] = 'namespace';
								$autocompletion_source = $sub_components[1];
								// special handling for "main" (blank) namespace
								if ( $autocompletion_source == "" )
									$autocompletion_source = "main";
								$field_args['autocompletion source'] = $autocompletion_source;
							} elseif ( $sub_components[0] == 'autocomplete from url' ) {
								$field_args['autocomplete field type'] = 'external_url';
								$field_args['autocompletion source'] = $sub_components[1];
								// 'external' autocompletion is always done remotely, i.e. via API
								$field_args['remote autocompletion'] = true;
							} elseif ( $sub_components[0] == 'values' ) {
								// Handle this one only after 'delimiter' has
								// also been set.
								$values = $sub_components[1];
							} elseif ( $sub_components[0] == 'values from property' ) {
								$propertyName = $sub_components[1];
								$possible_values = SFUtils::getAllValuesForProperty( $propertyName );
							} elseif ( $sub_components[0] == 'values from category' ) {
								$category_name = ucfirst( $sub_components[1] );
								$possible_values = SFUtils::getAllPagesForCategory( $category_name, 10 );
							} elseif ( $sub_components[0] == 'values from concept' ) {
								$possible_values = SFUtils::getAllPagesForConcept( $sub_components[1] );
							} elseif ( $sub_components[0] == 'values from namespace' ) {
								$possible_values = SFUtils::getAllPagesForNamespace( $sub_components[1] );
							} elseif ( $sub_components[0] == 'values dependent on' ) {
								global $sfgDependentFields;
								$sfgDependentFields[$sub_components[1]] = $fullFieldName;
							} elseif ( $sub_components[0] == 'property' ) {
								$semantic_property = $sub_components[1];
							} elseif ( $sub_components[0] == 'default filename' ) {
								$default_filename = str_replace( '&lt;page name&gt;', $page_name, $sub_components[1] );
								// Parse value, so default filename can include parser functions.
								$default_filename = $wgParser->recursiveTagParse( $default_filename );
								$field_args['default filename'] = $default_filename;
							} elseif ( $sub_components[0] == 'restricted' ) {
								$is_restricted = !array_intersect(
									$wgUser->getEffectiveGroups(), array_map( 'trim', explode( ',', $sub_components[1] ) )
								);
							}
						}
					} // end for
					// Backwards compatibility
					if ( $input_type == 'datetime with timezone' ) {
						$input_type = 'datetime';
						$field_args['include timezone'] = true;
					} elseif ( $input_type == 'text' || $input_type == 'textarea' ) {
						// Also for backwards compatibility,
						// in that once b/c goes away,
						// this will no longer be
						// necessary.
						$field_args['no autocomplete'] = true;
					}
					if ( $allow_multiple ) {
						$field_args['part_of_multiple'] = $allow_multiple;
					}
					if ( count( $show_on_select ) > 0 ) {
						$field_args['show on select'] = $show_on_select;
					}
					// Get the value from the request, if
					// it's there, and if it's not an array.
					$cur_value = null;
					$escaped_field_name = str_replace( "'", "\'", $field_name );
					if ( isset( $template_instance_query_values ) &&
						$template_instance_query_values != null &&
						is_array( $template_instance_query_values ) ) {
						// If the field name contains an
						// apostrophe, the array sometimes
						// has the apostrophe escaped, and
						// sometimes not. For now, just check
						// for both versions.
						// @TODO - figure this out.
						$field_query_val = null;
						if ( array_key_exists( $escaped_field_name, $template_instance_query_values ) ) {
							$field_query_val = $template_instance_query_values[$escaped_field_name];
						} elseif ( array_key_exists( $field_name, $template_instance_query_values ) ) {
							$field_query_val = $template_instance_query_values[$field_name];
						}
						if ( $form_submitted || ( ! empty( $field_query_val ) && ! is_array( $field_query_val ) ) ) {
							$cur_value = $field_query_val;
						}
					}

					if ( empty( $cur_value ) && !$form_submitted ) {
						if ( !is_null( $default_value ) ) {
							// Set to the default value specified in the form, if it's there.
							$cur_value = $default_value;
						} elseif ( $preload_page ) {
							$cur_value = SFFormUtils::getPreloadedText( $preload_page );
						}
					}

					// If the user is editing a page, and that page contains a call to
					// the template being processed, get the current field's value
					// from the template call
					if ( $source_is_page && ( ! empty( $existing_template_text ) ) ) {
						if ( isset( $template_contents[$field_name] ) ) {
							$cur_value = $template_contents[$field_name];

							// If the field is a placeholder, the contents of this template
							// parameter should be treated as elements parsed by an another
							// multiple template form.
							// By putting that at the very end of the parsed string, we'll
							// have it processed as a regular multiple template form.
							if ( $holds_template ) {
								$existing_page_content = $existing_page_content . $cur_value;
							}

							// Now remove this value
							// from $template_contents,
							// so that at the end we
							// can have a list of all
							// the fields that weren't
							// handled by the form.
							unset( $template_contents[$field_name] );
						} else {
							$cur_value = '';
						}
					}

					// Handle the free text field.
					if ( $field_name == '<freetext>' ) {
						// Add placeholders for the free text in both the form and
						// the page, using <free_text> tags - once all the free text
						// is known (at the end), it will get substituted in.
						if ( $is_hidden ) {
							$new_text = SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' );
						} else {
							$sfgTabIndex++;
							$sfgFieldNum++;
							if ( $cur_value === '' || is_null( $cur_value )  ) {
								$default_value = '!free_text!';
							} else {
								$default_value = $cur_value;
								// If the FCKeditor extension is installed and
								// active, the default value needs to be parsed
								// for use in the editor.
								global $wgFCKEditorDir;
								if ( $wgFCKEditorDir && strpos( $existing_page_content, '__NORICHEDITOR__' ) === false ) {
									$showFCKEditor = SFFormUtils::getShowFCKEditor();
									if ( !$form_submitted && ( $showFCKEditor & RTE_VISIBLE ) ) {
										$default_value = SFFormUtils::prepareTextForFCK( $cur_value );
									}
								}
							}
							$new_text = SFTextAreaInput::getHTML( $default_value, 'free_text', false, ( $form_is_disabled || $is_restricted ), $field_args );
							if ( in_array( 'edittools', $free_text_components ) ) {
								// borrowed from EditPage::showEditTools()
								$options[] = 'parse';
								$edittools_text = wfMsgExt( 'edittools', array( 'parse' ), array( 'content' ) );

								$new_text .= <<<END
		<div class="mw-editTools">
		$edittools_text
		</div>

END;
							}
						}
						$free_text_was_included = true;
						// add a similar placeholder to the data text
						$data_text .= "!free_text!\n";
					}

					if ( $template_name === '' || $field_name == '<freetext>' ) {
						$section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
					} else {
						if ( is_array( $cur_value ) ) {
							// first, check if it's a list
							if ( array_key_exists( 'is_list', $cur_value ) &&
									$cur_value['is_list'] == true ) {
								$cur_value_in_template = "";
								if ( array_key_exists( 'delimiter', $field_args ) ) {
									$delimiter = $field_args['delimiter'];
								} else {
									$delimiter = ",";
								}
								foreach ( $cur_value as $key => $val ) {
									if ( $key !== "is_list" ) {
										if ( $cur_value_in_template != "" ) {
											$cur_value_in_template .= $delimiter . " ";
										}
										$cur_value_in_template .= $val;
									}
								}
							} else {
								// otherwise:
								// if it has 1 or 2 elements, assume it's a checkbox; if it has
								// 3 elements, assume it's a date
								// - this handling will have to get more complex if other
								// possibilities get added
								if ( count( $cur_value ) == 1 ) {
									$cur_value_in_template = SFUtils::getWordForYesOrNo( false );
								} elseif ( count( $cur_value ) == 2 ) {
									$cur_value_in_template = SFUtils::getWordForYesOrNo( true );
								// if it's 3 or greater, assume it's a date or datetime
								} elseif ( count( $cur_value ) >= 3 ) {
									$month = $cur_value['month'];
									$day = $cur_value['day'];
									if ( $day !== '' ) {
										global $wgAmericanDates;
										if ( $wgAmericanDates == false ) {
											// pad out day to always be two digits
											$day = str_pad( $day, 2, "0", STR_PAD_LEFT );
										}
									}
									$year = $cur_value['year'];
									$hour = $minute = $second = $ampm24h = $timezone = null;
									if ( isset( $cur_value['hour'] ) ) $hour = $cur_value['hour'];
									if ( isset( $cur_value['minute'] ) ) $minute = $cur_value['minute'];
									if ( isset( $cur_value['second'] ) ) $second = $cur_value['second'];
									if ( isset( $cur_value['ampm24h'] ) ) $ampm24h = $cur_value['ampm24h'];
									if ( isset( $cur_value['timezone'] ) ) $timezone = $cur_value['timezone'];
									if ( $month !== '' && $day !== '' && $year !== '' ) {
										// special handling for American dates - otherwise, just
										// the standard year/month/day (where month is a number)
										global $wgAmericanDates;
										if ( $wgAmericanDates == true ) {
											$cur_value_in_template = "$month $day, $year";
										} else {
											$cur_value_in_template = "$year/$month/$day";
										}
										// include whatever time information we have
										if ( ! is_null( $hour ) )
											$cur_value_in_template .= " " . str_pad( intval( substr( $hour, 0, 2 ) ), 2, '0', STR_PAD_LEFT ) . ":" . str_pad( intval( substr( $minute, 0, 2 ) ), 2, '0', STR_PAD_LEFT );
										if ( ! is_null( $second ) )
											$cur_value_in_template .= ":" . str_pad( intval( substr( $second, 0, 2 ) ), 2, '0', STR_PAD_LEFT );
										if ( ! is_null( $ampm24h ) )
											$cur_value_in_template .= " $ampm24h";
										if ( ! is_null( $timezone ) )
											$cur_value_in_template .= " $timezone";
									} else {
										$cur_value_in_template = "";
									}
								}
							}
						} else { // value is not an array
							$cur_value_in_template = $cur_value;
						}
						if ( $template_name == null || $template_name === '' ) {
							$input_name = $field_name;
						} elseif ( $allow_multiple ) {
							// 'num' will get replaced by an actual index, either in PHP
							// or in Javascript, later on
							$input_name = $template_name . '[num][' . $field_name . ']';
							$field_args['origName'] = $template_name . '[' . $field_name . ']';
						} else {
							$input_name = $template_name . '[' . $field_name . ']';
						}


						// If the 'values' parameter was set, separate it based on the
						// 'delimiter' parameter, if any.
						if ( ! empty( $values ) ) {
							if ( array_key_exists( 'delimiter', $field_args ) ) {
								$delimiter = $field_args['delimiter'];
							} else {
								$delimiter = ",";
							}
							// Remove whitespaces, and un-escape characters
							$possible_values = array_map( 'trim', explode( $delimiter, $values ) );
							$possible_values = array_map( 'htmlspecialchars_decode', $possible_values );
						}

						// if we're creating the page name from a formula based on
						// form values, see if the current input is part of that formula,
						// and if so, substitute in the actual value
						if ( $form_submitted && $generated_page_name !== '' ) {
							// this line appears to be unnecessary
							// $generated_page_name = str_replace('.', '_', $generated_page_name);
							$generated_page_name = str_replace( ' ', '_', $generated_page_name );
							$escaped_input_name = str_replace( ' ', '_', $input_name );
							$generated_page_name = str_ireplace( "<$escaped_input_name>", $cur_value_in_template, $generated_page_name );
							// once the substitution is done, replace underlines back
							// with spaces
							$generated_page_name = str_replace( '_', ' ', $generated_page_name );
						}
						// disable this field if either the whole form is disabled, or
						// it's a restricted field and user doesn't have sysop privileges
						$is_disabled = ( $form_is_disabled || $is_restricted );
						// Create an SFFormField instance based on all the parameters
						// in the form definition, and any information from the template
						// definition (contained in the $all_fields parameter).
						$form_field = SFFormField::createFromDefinition( $field_name,
							$input_name, $is_mandatory, $is_hidden, $is_uploadable,
							$possible_values, $is_disabled, $is_list, $input_type,
							$field_args, $all_fields, $strict_parsing );
						// If a property was set in the form definition, overwrite whatever
						// is set in the template field - this is somewhat of a hack, since
						// parameters set in the form definition are meant to go into the
						// SFFormField object, not the SFTemplateField object it contains;
						// it seemed like too much work, though, to create an
						// SFFormField::setSemanticProperty() function just for this call
						if ( $semantic_property != null ) {
							$form_field->template_field->setSemanticProperty( $semantic_property );
						}
						$semantic_property = $form_field->template_field->getSemanticProperty();
						if ( !is_null( $semantic_property ) ) {
							global $sfgFieldProperties;
							$sfgFieldProperties[$fullFieldName] = $semantic_property;
						}


						// call hooks - unfortunately this has to be split into two
						// separate calls, because of the different variable names in
						// each case
						if ( $form_submitted ) {
							wfRunHooks( 'sfCreateFormField', array( &$form_field, &$cur_value_in_template, true ) );
						} else {
							wfRunHooks( 'sfCreateFormField', array( &$form_field, &$cur_value, false ) );
						}
						// if this is not part of a 'multiple' template, increment the
						// global tab index (used for correct tabbing)
						if ( ! array_key_exists( 'part_of_multiple', $field_args ) ) {
							$sfgTabIndex++;
						}
						// increment the global field number regardless
						$sfgFieldNum++;
						// If the field is a date field, and its default value was set
						// to 'now', and it has no current value, set $cur_value to be
						// the current date.
						if ( $default_value == 'now' &&
								// if the date is hidden, cur_value will already be set
								// to the default value
								( $cur_value === '' || $cur_value == 'now' ) ) {
							if ( $input_type == 'date' || $input_type == 'datetime' ||
									$input_type == 'year' ||
									( $input_type === '' && $form_field->getTemplateField()->getPropertyType() == '_dat' ) ) {
								// Get current time, for the time zone specified in the wiki.
								global $wgLocaltimezone;
								if ( isset( $wgLocaltimezone ) ) {
									$serverTimezone = date_default_timezone_get();
									date_default_timezone_set( $wgLocaltimezone );
								}
								$cur_time = time();
								$year = date( "Y", $cur_time );
								$month = date( "n", $cur_time );
								$day = date( "j", $cur_time );
								global $wgAmericanDates, $sfg24HourTime;
								if ( $wgAmericanDates == true ) {
									$month_names = SFFormUtils::getMonthNames();
									$month_name = $month_names[$month - 1];
									$cur_value_in_template = "$month_name $day, $year";
								} else {
									$cur_value_in_template = "$year/$month/$day";
								}
								if ( isset( $wgLocaltimezone ) ) {
									date_default_timezone_set( $serverTimezone );
								}
								if ( $input_type ==	'datetime' ) {
									if ( $sfg24HourTime ) {
										$hour = str_pad( intval( substr( date( "G", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT );
									} else {
										$hour = str_pad( intval( substr( date( "g", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT );
									}
									$minute = str_pad( intval( substr( date( "i", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT );
									$second = str_pad( intval( substr( date( "s", $cur_time ), 0, 2 ) ), 2, '0', STR_PAD_LEFT );
									if ( $sfg24HourTime ) {
										$cur_value_in_template .= " $hour:$minute:$second";
									} else {
										$ampm = date( "A", $cur_time );
										$cur_value_in_template .= " $hour:$minute:$second $ampm";
									}
								}
								if ( array_key_exists( 'include timezone', $field_args ) ) {
									$timezone = date( "T", $cur_time );
									$cur_value_in_template .= " $timezone";
								}
							}
						}
						// If the field is a text field, and its default value was set
						// to 'current user', and it has no current value, set $cur_value
						// to be the current user.
						if ( $default_value == 'current user' &&
							// if the date is hidden, cur_value will already be set
							// to the default value
							( $cur_value === '' || $cur_value == 'current user' ) ) {

							$cur_value_in_template = $wgUser->getName();
							$cur_value = $cur_value_in_template;
						}

						// Generate a hidden field with a placeholder value that will be replaced
						// by the multiple-instances template output at form submission.
						//// <input type="hidden" value="@replace_Town___mayors@" name="Town[town_mayors]" />
						if ( $holds_template ) {
							$cur_value = self::makePlaceholderInWikiText( self::placeholderFormat( $template_name, $field_name ) );
						}

						$new_text = $this->formFieldHTML( $form_field, $cur_value );

						// Add a field just after the hidden field, within the HTML, to locate
						// where the multiple-templates HTML, stored in $multipleTemplateString,
						// should be inserted.
						if ( $holds_template ) {
							$new_text .= self::makePlaceholderInFormHTML( self::placeholderFormat( $template_name, $field_name ) );
						}

						// If this field is disabled, add a hidden field holding
						// the value of this field, because disabled inputs for some
						// reason don't submit their value.
						if ( $form_field->isDisabled() ) {
							if ( $field_name == 'free text' || $field_name == '<freetext>' ) {
								$new_text .= SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' );
							} else {
								$new_text .= SFFormUtils::hiddenFieldHTML( $input_name, $cur_value );
							}
						}

						if ( $new_text ) {
							// Include the field name only for non-numeric field names.
							if ( is_numeric( $field_name ) ) {
								$template_text .= "|$cur_value_in_template";
							} else {
								// If the value is null, don't include it at all.
								if ( $cur_value_in_template !== '' ) {
									$template_text .= "\n|$field_name=$cur_value_in_template";
								}
							}
							$section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
						} else {
							$start_position = $brackets_end_loc;
						}
					}
				// =====================================================
				// standard input processing
				// =====================================================
				} elseif ( $tag_title == 'standard input' ) {
					// handle all the possible values
					$input_name = $tag_components[1];
					$input_label = null;
					$attr = array();

					// if it's a query, ignore all standard inputs except run query
					if ( ( $is_query && $input_name != 'run query' ) || ( !$is_query && $input_name == 'run query' ) ) {
						$new_text = "";
						$section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
						continue;
					}
					// set a flag so that the standard 'form bottom' won't get displayed
					$this->standardInputsIncluded = true;
					// cycle through the other components
					for ( $i = 2; $i < count( $tag_components ); $i++ ) {
						$component = $tag_components[$i];
						$sub_components = array_map( 'trim', explode( '=', $component ) );
						if ( count( $sub_components ) == 1 ) {
							if ( $sub_components[0] == 'edittools' ) {
								$free_text_components[] = 'edittools';
							}
						} elseif ( count( $sub_components ) == 2 ) {
							switch( $sub_components[0] ) {
							case 'label':
								$input_label = $sub_components[1];
								break;
							case 'class':
							case 'style':
								$attr[$sub_components[0]] = $sub_components[1];
								break;
							}
							// free text input needs more handling than the rest
							if ( $input_name == 'free text' || $input_name == '<freetext>' ) {
								if ( $sub_components[0] == 'preload' ) {
									$free_text_preload_page = $sub_components[1];
								}
							}
						}
					}
					if ( $input_name == 'summary' ) {
						$new_text = SFFormUtils::summaryInputHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'minor edit' ) {
						$new_text = SFFormUtils::minorEditInputHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'watch' ) {
						$new_text = SFFormUtils::watchInputHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'save' ) {
						$new_text = SFFormUtils::saveButtonHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'save and continue' ) {
						$new_text = SFFormUtils::saveAndContinueButtonHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'preview' ) {
						$new_text = SFFormUtils::showPreviewButtonHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'changes' ) {
						$new_text = SFFormUtils::showChangesButtonHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'cancel' ) {
						$new_text = SFFormUtils::cancelLinkHTML( $form_is_disabled, $input_label, $attr );
					} elseif ( $input_name == 'run query' ) {
						$new_text = SFFormUtils::runQueryButtonHTML( $form_is_disabled, $input_label, $attr );
					}
					$section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
				// =====================================================
				// page info processing
				// =====================================================
				} elseif ( $tag_title == 'info' ) {
					// TODO: Generate an error message if this is included more than once
					foreach ( array_slice( $tag_components, 1 ) as $component ) {
						$sub_components = array_map( 'trim', explode( '=', $component, 2 ) );
						// Tag names are case-insensitive
						$tag = strtolower( $sub_components[0] );
						if ( $tag == 'create title' || $tag == 'add title' ) {
							// Handle this only if
							// we're adding a page.
							if ( !$is_query && !$this->mPageTitle->exists() ) {
								$form_page_title = $sub_components[1];
							}
						} elseif ( $tag == 'edit title' ) {
							// Handle this only if
							// we're editing a page.
							if ( !$is_query && $this->mPageTitle->exists() ) {
								$form_page_title = $sub_components[1];
							}
						} elseif ( $tag == 'query title' ) {
							// Handle this only if
							// we're in 'RunQuery'.
							if ( $is_query ) {
								$form_page_title = $sub_components[1];
							}
						} elseif ( $tag == 'partial form' ) {
							$form_is_partial = true;
							// replacement pages may have minimal matches...
							$source_page_matches_this_form = true;
						} elseif ( $tag == 'includeonly free text' || $tag == 'onlyinclude free text' ) {
							$onlyinclude_free_text = true;
						} elseif ( $tag == 'query form at top' ) {
							// TODO - this should be made a field of
							// some non-static class that actually
							// prints the form, instead of requiring
							// a global variable.
							global $sfgRunQueryFormAtTop;
							$sfgRunQueryFormAtTop = true;
						}
					}
					$section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
				// =====================================================
				// default outer level processing
				// =====================================================
				} else { // Tag is not one of the three allowed values -
					// ignore the tag.
					$start_position = $brackets_end_loc;
				} // end if
			} // end while

			if ( ! $all_instances_printed ) {
				if ( $template_text !== '' ) {
					// For mostly aesthetic purposes, if the template call ends with
					// a bunch of pipes (i.e., it's an indexed template with unused
					// parameters at the end), remove the pipes.
					$template_text = preg_replace( '/\|*$/', '', $template_text );
					// add another newline before the final bracket, if this template
					// call is already more than one line
					if ( strpos( $template_text, "\n" ) ) {
						$template_text .= "\n";
					}
					// If we're editing an existing page, and there were fields in
					// the template call not handled by this form, preserve those.
					if ( !$allow_multiple ) {
						$template_text .= SFFormUtils::addUnhandledFields( $template_name );
					}
					$template_text .= "}}";

					// The base $template_text will contain strings like "@replace_xxx@"
					// in the hidden fields when the form is submitted.
					// On the following loops, the text for the multiple-instance templates
					// is progressively reinserted in the main data, always keeping a
					// trailing @replace_xxx@ for a given field
					// The trailing @replace_xxx@ is then deleted at the end.
					// Note: this cleanup step could also be done with a regexp, instead of
					// keeping a track array (e.g., /@replace_(.*)@/)
					$reptmp = self::makePlaceholderInWikiText( $curPlaceholder );
					if ( $curPlaceholder != null && $data_text && strpos( $data_text, $reptmp, 0 ) !== false ) {
						$data_text = preg_replace( '/' . $reptmp . '/', $template_text . $reptmp, $data_text );
					} else {
						$data_text .= $template_text . "\n";
					}

					// If there is a placeholder in the
					// text, we know that we are
					// doing a replace.
					if ( $existing_page_content && strpos( $existing_page_content, '{{{insertionpoint}}}', 0 ) !== false ) {
						$existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}(\r?\n?)/',
							preg_replace( '/\}\}/m', '}�',
								preg_replace( '/\{\{/m', '�{', $template_text ) ) .
							"\n{{{insertionpoint}}}",
							$existing_page_content );
					// otherwise, if it's a partial form, we have to add the new
					// text somewhere
					} elseif ( $form_is_partial && $wgRequest->getCheck( 'partial' ) ) {
						$existing_page_content = preg_replace( '/\}\}/m', '}�',
							preg_replace( '/\{\{/m', '�{', $template_text ) ) .
								"\n{{{insertionpoint}}}\n" . $existing_page_content;
					}
				}
			}

			if ( $allow_multiple ) {
				if ( $curPlaceholder == null ) {
					// The normal process.
					$form_text .= $this->multipleTemplateInstanceHTML( $form_is_disabled, $all_instances_printed, $section, $instance_num, $add_button_text );
				} else { // if ( $curPlaceholder != null ){
					// The template text won't be appended at the end of the template like for usual multiple template forms.
					// The HTML text will then be stored in the $multipleTemplateString variable,
					// and then added in the right @insertHTML_".$placeHolderField."@"; position
					// Optimization: actually, instead of separating the processes, the usual multiple
					// template forms could also be handled this way if a fitting placeholder tag was added.
					$multipleTemplateString .= $this->multipleTemplateInstanceHTML( $form_is_disabled, $all_instances_printed, $section, $instance_num, $add_button_text );
					// We replace the $multipleTemplateString HTML into the
					// current placeholder tag, but also add another
					// placeholder tag, to keep track of it.
					$multipleTemplateString .= self::makePlaceholderInFormHTML( $curPlaceholder );
					if ( isset( $template_label ) ) {
						$multipleTemplateString .= "</fieldset>\n";
						unset ( $template_label );
					}
					$form_text = preg_replace( '/' . self::makePlaceholderInFormHTML( $curPlaceholder ) . '/',
						$multipleTemplateString, $form_text );
				}
				if ( ! $all_instances_printed ) {
					// This will cause the section to be
					// re-parsed on the next go.
					$section_num--;
				}
			} else { // if ( $allow_multiple ) {
				$form_text .= $section;
			}
			$curPlaceholder = null;
		} // end for

		// Cleanup - everything has been browsed.
		// Remove all the remaining placeholder
		// tags in the HTML and wiki-text.
		foreach ( $placeholderFields as $stringToReplace ) {
			// remove the @<replacename>@ tags from the data that is submitted
			$data_text = preg_replace( '/' . self::makePlaceholderInWikiText( $stringToReplace ) . '/', '', $data_text );

			// remove the @<insertHTML>@ tags from the generated HTML form
			$form_text = preg_replace( '/' . self::makePlaceholderInFormHTML( $stringToReplace ) . '/', '', $form_text );
		}

		// if it wasn't included in the form definition, add the
		// 'free text' input as a hidden field at the bottom
		if ( ! $free_text_was_included ) {
			$form_text .= SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' );
		}
		// Get free text, and add to page data, as well as retroactively
		// inserting it into the form.

		// If $form_is_partial is true then either:
		// (a) we're processing a replacement (param 'partial' == 1)
		// (b) we're sending out something to be replaced (param 'partial' is missing)
		if ( $form_is_partial ) {
			if ( !$wgRequest->getCheck( 'partial' ) ) {
				$free_text = $original_page_content;
				$form_text .= SFFormUtils::hiddenFieldHTML( 'partial', 1 );
			} else {
				$free_text = null;
				$existing_page_content = preg_replace( array( '/�\{/m', '/\}�/m' ),
					array( '{{', '}}' ),
					$existing_page_content );
				$existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}/', '', $existing_page_content );
			}
		} elseif ( $source_is_page ) {
			// if the page is the source, free_text will just be whatever in the
			// page hasn't already been inserted into the form
			$free_text = trim( $existing_page_content );
		// or get it from a form submission
		} elseif ( $wgRequest->getCheck( 'free_text' ) ) {
			$free_text = $wgRequest->getVal( 'free_text' );
			if ( ! $free_text_was_included ) {
				$data_text .= "!free_text!";
			}
		// or get it from the form definition
		} elseif ( $free_text_preload_page != null ) {
			$free_text = SFFormUtils::getPreloadedText( $free_text_preload_page );
		} else {
			$free_text = null;
		}
		if ( $onlyinclude_free_text ) {
			// modify free text and data text to insert <onlyinclude> tags
			$free_text = str_replace( "<onlyinclude>", '', $free_text );
			$free_text = str_replace( "</onlyinclude>", '', $free_text );
			$free_text = trim( $free_text );
			$data_text = str_replace( '!free_text!', '<onlyinclude>!free_text!</onlyinclude>', $data_text );
		}

		wfRunHooks( 'sfModifyFreeTextField', array( &$free_text, $existing_page_content ) );
		// if the FCKeditor extension is installed, use that for the free text input
		global $wgFCKEditorDir;
		if ( $wgFCKEditorDir && strpos( $existing_page_content, '__NORICHEDITOR__' ) === false ) {
			$showFCKEditor = SFFormUtils::getShowFCKEditor();
			if ( !$form_submitted && ( $showFCKEditor & RTE_VISIBLE ) ) {
				$free_text = SFFormUtils::prepareTextForFCK( $free_text );
			}
		} else {
			$showFCKEditor = 0;
		}
		// now that we have it, substitute free text into the form and page
		$escaped_free_text = Sanitizer::safeEncodeAttribute( $free_text );
		$form_text = str_replace( '!free_text!', $escaped_free_text, $form_text );
		$data_text = str_replace( '!free_text!', $free_text, $data_text );

		// Add a warning in, if we're editing an existing page and that
		// page appears to not have been created with this form.
		if ( !$is_query && $this->mPageTitle->exists() && ( $existing_page_content !== '' ) && ! $source_page_matches_this_form ) {
			$form_text = "\t" . '<div class="warningbox">' . wfMsg( 'sf_formedit_formwarning', $this->mPageTitle->getFullURL() ) . "</div>\n<br clear=\"both\" />\n" . $form_text;
		}

		// add form bottom, if no custom "standard inputs" have been defined
		if ( !$this->standardInputsIncluded ) {
			if ( $is_query )
				$form_text .= SFFormUtils::queryFormBottom( $form_is_disabled );
			else
				$form_text .= SFFormUtils::formBottom( $form_is_disabled );
		}

		$page_article = new Article( $this->mPageTitle, 0 );

		if ( !$is_query ) {
			$form_text .= SFFormUtils::hiddenFieldHTML( 'wpStarttime', wfTimestampNow() );
			$form_text .= SFFormUtils::hiddenFieldHTML( 'wpEdittime', $page_article->getTimestamp() );
		}

		$form_text .= "\t</form>\n";

		// Add general Javascript code.
		wfRunHooks( 'sfAddJavascriptToForm', array( &$javascript_text ) );

		// @TODO The FCKeditor Javascript should be handled within
		// the FCKeditor extension itself, using the hook.
		$javascript_text = "";
		if ( $free_text_was_included && $showFCKEditor > 0 ) {
			$javascript_text .= SFFormUtils::mainFCKJavascript( $showFCKEditor, $field_args );
			if ( $showFCKEditor & ( RTE_TOGGLE_LINK | RTE_POPUP ) ) {
				$javascript_text .= SFFormUTils::FCKToggleJavascript();
			}
			if ( $showFCKEditor & RTE_POPUP ) {
				$javascript_text .= SFFormUTils::FCKPopupJavascript();
			}
		}

		// Send the autocomplete values to the browser, along with the
		// mappings of which values should apply to which fields.
		// If doing a replace, the data text is actually the modified original page
		if ( $wgRequest->getCheck( 'partial' ) )
			$data_text = $existing_page_content;

		if ( !$is_embedded ) {
			$form_page_title = $wgParser->recursiveTagParse( str_replace( "{{!}}", "|", $form_page_title ) );
		} else {
			$form_page_title = null;
		}

		// If the form has already been submitted, i.e. this is just
		// the redirect page, get rid of all the Javascript, to avoid
		// JS errors.
		if ( $form_submitted ) {
			$javascript_text = '';
		}

		$parserOutput = $wgParser->getOutput();
		$wgOut->addParserOutputNoText( $parserOutput );

		$wgParser = $oldParser;

		wfProfileOut( __METHOD__ );

		return array( $form_text, $javascript_text, $data_text, $form_page_title, $generated_page_name );
	}