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 ''; }
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 ) ); }
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" ); } }
/** * 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? }
/** * 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()); }
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(); }
/** * 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); }
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; }
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 .= '     <b>' . wfMsg('smw_result_results') . ' ' . ($offset + 1) . '– ' . ($offset + min(count($results), $limit)) . '</b>    '; 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 .= '  ' . $browselink->getHTML($linker); } $html .= "</li> \n"; } $html .= "</ul>\n"; } $html .= $navigation; } // Display query form $spectitle = $this->getTitle(); $html .= '<p> </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) . '" />' . "   \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 ); }
/** * 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 ); }
/** * 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; }
/** * 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; }
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; }
/** * 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( '{', '|', '}' ), 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 '>' 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( '<page name>', $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 ); }