function getCategoryDefinedByTemplate($templateTitle) { global $wgContLang; $templateText = SFUtils::getPageText($templateTitle); $cat_ns_name = $wgContLang->getNsText(NS_TEMPLATE); if (preg_match_all("/\\[\\[(Category|{$cat_ns_name}):([^\\]]*)\\]\\]/", $templateText, $matches)) { // Get the last match - if there's more than one // category tag, there's a good chance that the last // one will be the relevant one - the others are // probably part of inline queries. $categoryName = trim(end($matches[2])); // If there's a pipe, remove it and anything after it. $locationOfPipe = strpos($categoryName, '|'); if ($locationOfPipe !== false) { $categoryName = substr($categoryName, 0, $locationOfPipe); } return $categoryName; } return ""; }
public static function createPageWithForm($title, $formName) { global $sfgFormPrinter; $formTitle = Title::makeTitleSafe(SF_NS_FORM, $formName); $formDefinition = SFUtils::getPageText($formTitle); $preloadContent = null; // Allow outside code to set/change the preloaded text. Hooks::run('sfEditFormPreloadText', array(&$preloadContent, $title, $formTitle)); list($formText, $javascriptText, $dataText, $formPageTitle, $generatedPageName) = $sfgFormPrinter->formHTML($formDefinition, false, false, null, $preloadContent, 'Some very long page name that will hopefully never get created ABCDEF123', null); $params = array(); // Get user "responsible" for all auto-generated // pages from red links. $userID = 1; global $sfgAutoCreateUser; if (!is_null($sfgAutoCreateUser)) { $user = User::newFromName($sfgAutoCreateUser); if (!is_null($user)) { $userID = $user->getId(); } } $params['user_id'] = $userID; $params['page_text'] = $dataText; $job = new SFCreatePageJob($title, $params); $jobs = array($job); if (class_exists('JobQueueGroup')) { JobQueueGroup::singleton()->push($jobs); } else { // MW <= 1.20 Job::batchInsert($jobs); } }
/** * Automatically creates a page that's red-linked from the page being * viewed, if there's a property pointing from anywhere to that page * that's defined with the 'Creates pages with form' special property */ static function createLinkedPage($title, $incoming_properties) { // if we're in a 'special' page, just exit - this is to prevent // constant additions being made from the 'Special:RecentChanges' // page, which shows pages that were previously deleted as red // links, even if they've since been recreated. The same might // hold true for other special pages. global $wgTitle; if (empty($wgTitle)) { return false; } if ($wgTitle->getNamespace() == NS_SPECIAL) { return false; } foreach ($incoming_properties as $property_name) { $auto_create_forms = self::getFormsThatPagePointsTo($property_name, SMW_NS_PROPERTY, self::AUTO_CREATE_FORM); if (count($auto_create_forms) > 0) { global $sfgFormPrinter; $form_name = $auto_create_forms[0]; $form_title = Title::makeTitleSafe(SF_NS_FORM, $form_name); $form_definition = SFUtils::getPageText($form_title); $preloadContent = null; // allow extensions to set/change the preload text wfRunHooks('sfEditFormPreloadText', array(&$preloadContent, $title, $form_title)); list($form_text, $javascript_text, $data_text, $form_page_title, $generated_page_name) = $sfgFormPrinter->formHTML($form_definition, false, false, null, $preloadContent, 'Some very long page name that will hopefully never get created ABCDEF123', null); $params = array(); // Get user "responsible" for all auto-generated // pages from red links. $userID = 1; global $sfgAutoCreateUser; if (!is_null($sfgAutoCreateUser)) { $user = User::newFromName($sfgAutoCreateUser); if (!is_null($user)) { $userID = $user->getId(); } } $params['user_id'] = $userID; $params['page_text'] = $data_text; $job = new SFCreatePageJob($title, $params); Job::batchInsert(array($job)); return true; } } return false; }
function printPage($form_name, $embedded = false) { global $wgOut, $wgRequest, $sfgFormPrinter, $wgParser, $sfgRunQueryFormAtTop; global $wgUser; // Get contents of form-definition page. $form_title = Title::makeTitleSafe(SF_NS_FORM, $form_name); if (!$form_title || !$form_title->exists()) { if ($form_name === '') { $text = Html::element('p', array('class' => 'error'), wfMessage('sf_runquery_badurl')->text()) . "\n"; } else { $text = Html::rawElement('p', array('class' => 'error'), wfMessage('sf_formstart_badform', SFUtils::linkText(SF_NS_FORM, $form_name))->parse()) . "\n"; } $wgOut->addHTML($text); return; } // Initialize variables. $form_definition = SFUtils::getPageText($form_title); if ($embedded) { $run_query = false; $content = null; $raw = false; } else { $run_query = $wgRequest->getCheck('wpRunQuery'); $content = $wgRequest->getVal('wpTextbox1'); $raw = $wgRequest->getBool('raw', false); } $form_submitted = $run_query; if ($raw) { $wgOut->setArticleBodyOnly(true); } // If user already made some action, ignore the edited // page and just get data from the query string. if (!$embedded && $wgRequest->getVal('query') == 'true') { $edit_content = null; $is_text_source = false; } elseif ($content != null) { $edit_content = $content; $is_text_source = true; } else { $edit_content = null; $is_text_source = true; } list($form_text, $javascript_text, $data_text, $form_page_title) = $sfgFormPrinter->formHTML($form_definition, $form_submitted, $is_text_source, $form_title->getArticleID(), $edit_content, null, null, true, $embedded); $text = ""; // Get the text of the results. $resultsText = ''; if ($form_submitted) { // @TODO - fix RunQuery's parsing so that this check // isn't needed. if ($wgParser->getOutput() == null) { $headItems = array(); } else { $headItems = $wgParser->getOutput()->getHeadItems(); } foreach ($headItems as $key => $item) { $wgOut->addHeadItem($key, "\t\t" . $item . "\n"); } $wgParser->mOptions = ParserOptions::newFromUser($wgUser); $resultsText = $wgParser->parse($data_text, $this->getTitle(), $wgParser->mOptions)->getText(); } // Get the full text of the form. $fullFormText = ''; $additionalQueryHeader = ''; $dividerText = ''; if (!$raw) { // Create the "additional query" header, and the // divider text - one of these (depending on whether // the query form is at the top or bottom) is displayed // if the form has already been submitted. if ($form_submitted) { $additionalQueryHeader = "\n" . Html::element('h2', null, wfMessage('sf_runquery_additionalquery')->text()) . "\n"; $dividerText = "\n<hr style=\"margin: 15px 0;\" />\n"; } $action = htmlspecialchars($this->getTitle($form_name)->getLocalURL()); $fullFormText .= <<<END \t<form id="sfForm" name="createbox" action="{$action}" method="post" class="createbox"> END; $fullFormText .= Html::hidden('query', 'true'); $fullFormText .= $form_text; } // Either don't display a query form at all, or display the // query form at the top, and the results at the bottom, or the // other way around, depending on the settings. if ($wgRequest->getVal('additionalquery') == 'false') { $text .= $resultsText; } elseif ($sfgRunQueryFormAtTop) { $text .= Html::openElement('div', array('class' => 'sf-runquery-formcontent')); $text .= $fullFormText; $text .= $dividerText; $text .= Html::closeElement('div'); $text .= $resultsText; } else { $text .= $resultsText; $text .= Html::openElement('div', array('class' => 'sf-runquery-formcontent')); $text .= $additionalQueryHeader; $text .= $fullFormText; $text .= Html::closeElement('div'); } if ($embedded) { $text = "<div class='runQueryEmbedded'>{$text}</div>"; } // Armor against doBlockLevels() $text = preg_replace('/^ +/m', '', $text); // Now write everything to the screen. $wgOut->addHTML($text); SFUtils::addFormRLModules($embedded ? $wgParser : null); $script = "\t\t" . '<script type="text/javascript">' . "\n" . $javascript_text . '</script>' . "\n"; if ($embedded) { if (method_exists('ResourceLoader', 'makeInlineScript')) { // MW 1.25+ $wgParser->getOutput()->addHeadItem(ResourceLoader::makeInlineScript($javascript_text)); } else { $wgParser->getOutput()->addHeadItem($script); } } else { if (method_exists('ResourceLoader', 'makeInlineScript')) { // MW 1.25+ $wgOut->addScript(ResourceLoader::makeInlineScript($javascript_text)); } else { $wgOut->addScript($script); } $po = $wgParser->getOutput(); if ($po) { // addParserOutputMetadata was introduced in 1.24 when addParserOutputNoText was deprecated if (method_exists($wgOut, 'addParserOutputMetadata')) { $wgOut->addParserOutputMetadata($po); } else { $wgOut->addParserOutputNoText($po); } } } // Finally, set the page title - previously, this had to be // called after addParserOutputNoText() for it to take effect; // now the order doesn't matter. if (!$embedded) { if ($form_page_title != null) { $wgOut->setPageTitle($form_page_title); } else { $s = wfMessage('sf_runquery_title', $form_title->getText())->text(); $wgOut->setPageTitle($s); } } }
function getAllFieldsCargo($templateTitle) { $cargoFieldsOfTemplateParams = array(); $templateFields = array(); // First, get the table name, and fields, declared for this // template. $templatePageID = $templateTitle->getArticleID(); $tableSchemaString = CargoUtils::getPageProp($templatePageID, 'CargoFields'); // See if there even is DB storage for this template - if not, // exit. if (is_null($tableSchemaString)) { return null; } $tableSchema = CargoTableSchema::newFromDBString($tableSchemaString); $tableName = CargoUtils::getPageProp($templatePageID, 'CargoTableName'); // Then, match template params to Cargo table fields, by // parsing call(s) to #cargo_store. $templateText = SFUtils::getPageText($templateTitle); // Ignore 'noinclude' sections and 'includeonly' tags. $templateText = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $templateText); $templateText = strtr($templateText, array('<includeonly>' => '', '</includeonly>' => '')); // Let's find every #cargo_store tag. // Unfortunately, it doesn't seem possible to use a regexp // search for this, because it's hard to know which set of // double brackets represents the end of such a call. Instead, // we'll do some manual parsing. $cargoStoreLocations = array(); $curPos = 0; while (true) { $newPos = strpos($templateText, "#cargo_store:", $curPos); if ($newPos === false) { break; } $curPos = $newPos + 13; $cargoStoreLocations[] = $curPos; } $cargoStoreCalls = array(); foreach ($cargoStoreLocations as $locNum => $startPos) { $numUnclosedBrackets = 2; if ($locNum < count($cargoStoreLocations) - 1) { $lastPos = $cargoStoreLocations[$locNum + 1]; } else { $lastPos = strlen($templateText) - 1; } $curCargoStoreCall = ''; $curPos = $startPos; while ($curPos <= $lastPos) { $curChar = $templateText[$curPos]; $curCargoStoreCall .= $curChar; if ($curChar == '}') { $numUnclosedBrackets--; } elseif ($curChar == '{') { $numUnclosedBrackets++; } if ($numUnclosedBrackets == 0) { break; } $curPos++; } $cargoStoreCalls[] = $curCargoStoreCall; } foreach ($cargoStoreCalls as $cargoStoreCall) { if (preg_match_all('/([^|{]*?)=\\s*{{{([^|}]*)/mis', $cargoStoreCall, $matches)) { foreach ($matches[1] as $i => $cargoFieldName) { $templateParameter = trim($matches[2][$i]); $cargoFieldsOfTemplateParams[$templateParameter] = $cargoFieldName; } } } // Now, combine the two sets of information into an array of // SFTemplateFields objects. $fieldDescriptions = $tableSchema->mFieldDescriptions; foreach ($cargoFieldsOfTemplateParams as $templateParameter => $cargoField) { $templateField = SFTemplateField::create($templateParameter, $templateParameter); if (array_key_exists($cargoField, $fieldDescriptions)) { $fieldDescription = $fieldDescriptions[$cargoField]; $templateField->setCargoFieldData($tableName, $cargoField, $fieldDescription); } $templateFields[] = $templateField; } return $templateFields; }
/** * Get the fields of the template, along with the semantic property * attached to each one (if any), by parsing the text of the template. */ function getAllFields() { global $wgContLang; $templateFields = array(); $fieldNamesArray = array(); // The way this works is that fields are found and then stored // in an array based on their location in the template text, so // that they can be returned in the order in which they appear // in the template, not the order in which they were found. // Some fields can be found more than once (especially if // they're part of an "#if" statement), so they're only // recorded the first time they're found. $template_title = Title::makeTitleSafe(NS_TEMPLATE, $this->mTemplateName); if (isset($template_title)) { $templateText = SFUtils::getPageText($template_title); // Ignore 'noinclude' sections and 'includeonly' tags. $templateText = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $templateText); $templateText = strtr($templateText, array('<includeonly>' => '', '</includeonly>' => '')); // First, look for "arraymap" parser function calls // that map a property onto a list. if ($ret = preg_match_all('/{{#arraymap:{{{([^|}]*:?[^|}]*)[^\\[]*\\[\\[([^:]*:?[^:]*)::/mis', $templateText, $matches)) { foreach ($matches[1] as $i => $field_name) { if (!in_array($field_name, $fieldNamesArray)) { $propertyName = $matches[2][$i]; $this->handlePropertySettingInTemplate($field_name, $propertyName, true, $templateFields, $templateText); $fieldNamesArray[] = $field_name; } } } elseif ($ret === false) { // There was an error in the preg_match_all() // call - let the user know about it. if (preg_last_error() == PREG_BACKTRACK_LIMIT_ERROR) { print 'Semantic Forms error: backtrace limit exceeded during parsing! Please increase the value of <a href="http://www.php.net/manual/en/pcre.configuration.php#ini.pcre.backtrack-limit">pcre.backtrack_limit</a> in php.ini or LocalSettings.php.'; } } // Second, look for normal property calls. if (preg_match_all('/\\[\\[([^:|\\[\\]]*:*?[^:|\\[\\]]*)::{{{([^\\]\\|}]*).*?\\]\\]/mis', $templateText, $matches)) { foreach ($matches[1] as $i => $propertyName) { $field_name = trim($matches[2][$i]); if (!in_array($field_name, $fieldNamesArray)) { $propertyName = trim($propertyName); $this->handlePropertySettingInTemplate($field_name, $propertyName, false, $templateFields, $templateText); $fieldNamesArray[] = $field_name; } } } // Then, get calls to #set, #set_internal and // #subobject. (Thankfully, they all have similar // syntax). if (preg_match_all('/#(set|set_internal|subobject):(.*?}}})\\s*}}/mis', $templateText, $matches)) { foreach ($matches[2] as $match) { if (preg_match_all('/([^|{]*?)=\\s*{{{([^|}]*)/mis', $match, $matches2)) { foreach ($matches2[1] as $i => $propertyName) { $fieldName = trim($matches2[2][$i]); if (!in_array($fieldName, $fieldNamesArray)) { $propertyName = trim($propertyName); $this->handlePropertySettingInTemplate($fieldName, $propertyName, false, $templateFields, $templateText); $fieldNamesArray[] = $fieldName; } } } } } // Then, get calls to #declare. (This is really rather // optional, since no one seems to use #declare.) if (preg_match_all('/#declare:(.*?)}}/mis', $templateText, $matches)) { foreach ($matches[1] as $match) { $setValues = explode('|', $match); foreach ($setValues as $valuePair) { $keyAndVal = explode('=', $valuePair); if (count($keyAndVal) == 2) { $propertyName = trim($keyAndVal[0]); $fieldName = trim($keyAndVal[1]); if (!in_array($fieldName, $fieldNamesArray)) { $this->handlePropertySettingInTemplate($fieldName, $propertyName, false, $templateFields, $templateText); $fieldNamesArray[] = $fieldName; } } } } } // Finally, get any non-semantic fields defined. if (preg_match_all('/{{{([^|}]*)/mis', $templateText, $matches)) { foreach ($matches[1] as $fieldName) { $fieldName = trim($fieldName); if (!empty($fieldName) && !in_array($fieldName, $fieldNamesArray)) { $cur_pos = stripos($templateText, $fieldName); $templateFields[$cur_pos] = SFTemplateField::create($fieldName, $wgContLang->ucfirst($fieldName)); $fieldNamesArray[] = $fieldName; } } } } ksort($templateFields); return $templateFields; }
/** * Parse the form definition and return it */ public static function getFormDefinition(Parser $parser, $form_def = null, $form_id = null) { if ($form_id !== null) { $cachedDef = self::getFormDefinitionFromCache($form_id, $parser); if ($cachedDef !== null) { return $cachedDef; } } if ($form_id !== null) { $form_title = Title::newFromID($form_id); $form_def = SFUtils::getPageText($form_title); } elseif ($form_def == null) { // No id, no text -> nothing to do return ''; } // Remove <noinclude> sections and <includeonly> tags from form definition $form_def = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $form_def); $form_def = strtr($form_def, array('<includeonly>' => '', '</includeonly>' => '')); // We need to replace all SF tags in the form definition by strip items. But we can not just use // the Parser strip state because the Parser would during parsing replace all strip items and then // mangle them into HTML code. So we have to use our own. Which means we also can not just use // Parser::insertStripItem() (see below). $rnd = wfRandomString(32); // This regexp will find any SF triple braced tags (including correct handling of contained braces), i.e. // {{{field|foo|default={{Bar}}}}} is not a problem. When used with preg_match and friends, $matches[0] will // contain the whole SF tag, $matches[1] will contain the tag without the enclosing triple braces. $regexp = '#\\{\\{\\{((?>[^\\{\\}]+)|(\\{((?>[^\\{\\}]+)|(?-2))*\\}))*\\}\\}\\}#'; $items = array(); // replace all SF tags by strip markers $form_def = preg_replace_callback($regexp, function (array $matches) use(&$items, $rnd) { $markerIndex = count($items); $items[] = $matches[0]; return "{$rnd}-item-{$markerIndex}-{$rnd}"; }, $form_def); // parse wiki-text if (isset($parser->mInParse) && $parser->mInParse === true) { $form_def = $parser->recursiveTagParse($form_def); $output = $parser->getOutput(); } else { $title = is_object($parser->getTitle()) ? $parser->getTitle() : new Title(); $output = $parser->parse($form_def, $title, $parser->getOptions()); $form_def = $output->getText(); } $form_def = preg_replace_callback("/{$rnd}-item-(\\d+)-{$rnd}/", function (array $matches) use($items) { $markerIndex = (int) $matches[1]; return $items[$markerIndex]; }, $form_def); if ($output->getCacheTime() == -1) { $form_article = Article::newFromID($form_id); self::purgeCache($form_article); wfDebug("Caching disabled for form definition {$form_id}\n"); } elseif ($form_id !== null) { self::cacheFormDefinition($form_id, $form_def, $parser); } return $form_def; }
function getAllFieldsCargo($templateTitle) { $cargoFieldsOfTemplateParams = array(); $templateFields = array(); // First, get the table name, and fields, declared for this // template. $templatePageID = $templateTitle->getArticleID(); $tableSchemaString = CargoUtils::getPageProp($templatePageID, 'CargoFields'); // See if there even is DB storage for this template - if not, // exit. if (is_null($tableSchemaString)) { return null; } $tableSchema = CargoTableSchema::newFromDBString($tableSchemaString); $tableName = CargoUtils::getPageProp($templatePageID, 'CargoTableName'); // Then, match template params to Cargo table fields, by // parsing call(s) to #cargo_store. $templateText = SFUtils::getPageText($templateTitle); // Ignore 'noinclude' sections and 'includeonly' tags. $templateText = StringUtils::delimiterReplace('<noinclude>', '</noinclude>', '', $templateText); $templateText = strtr($templateText, array('<includeonly>' => '', '</includeonly>' => '')); if (preg_match_all('/#cargo_store:(.*?}})\\s*}}/mis', $templateText, $matches)) { foreach ($matches[1] as $match) { if (preg_match_all('/([^|{]*?)=\\s*{{{([^|}]*)/mis', $match, $matches2)) { foreach ($matches2[1] as $i => $cargoFieldName) { $templateParameter = trim($matches2[2][$i]); $cargoFieldsOfTemplateParams[$templateParameter] = $cargoFieldName; } } } } // Now, combine the two sets of information into an array of // SFTemplateFields objects. $fieldDescriptions = $tableSchema->mFieldDescriptions; foreach ($cargoFieldsOfTemplateParams as $templateParameter => $cargoField) { $templateField = SFTemplateField::create($templateParameter, $templateParameter); if (array_key_exists($cargoField, $fieldDescriptions)) { $fieldDescription = $fieldDescriptions[$cargoField]; $templateField->setCargoFieldData($tableName, $cargoField, $fieldDescription); } $templateFields[] = $templateField; } return $templateFields; }