gplx/mediawiki/extensions/SemanticMediaWiki/includes/SMW_PageSchemas.php

379 lines
13 KiB
PHP

<?php
/**
* Functions for handling Semantic MediaWiki data within the Page Schemas
* extension.
*
* @author Ankit Garg
* @author Yaron Koren
* @ingroup SMW
*/
use MediaWiki\Context\RequestContext;
use MediaWiki\Html\Html;
use MediaWiki\MediaWikiServices;
use MediaWiki\Xml\Xml;
class SMWPageSchemas extends PSExtensionHandler {
public static function getDisplayColor() {
return '#DEF';
}
public static function getTemplateDisplayString() {
return 'Connecting property';
}
public static function getFieldDisplayString() {
return 'Semantic property';
}
/**
* Returns the display info for the "connecting property" (if any)
* of the #subobject call (if any) in this template.
*/
public static function getTemplateDisplayValues( $templateXML ) {
foreach ( $templateXML->children() as $tag => $child ) {
if ( $tag == "semanticmediawiki_ConnectingProperty" ) {
$propName = $child->attributes()->name;
$values = [];
return [ $propName, $values ];
}
}
return null;
}
/**
* Returns the display info for the property (if any is defined)
* for a single field in the Page Schemas XML.
*/
public static function getFieldDisplayValues( $fieldXML ) {
foreach ( $fieldXML->children() as $tag => $child ) {
if ( $tag == "semanticmediawiki_Property" ) {
$propName = $child->attributes()->name;
$values = [];
foreach ( $child->children() as $prop => $value ) {
$values[$prop] = (string)$value;
}
return [ $propName, $values ];
}
}
return null;
}
/**
* Returns the set of SMW property data from the entire page schema.
*/
static function getAllPropertyData( $pageSchemaObj ) {
$propertyDataArray = [];
$psTemplates = $pageSchemaObj->getTemplates();
foreach ( $psTemplates as $psTemplate ) {
$psTemplateFields = $psTemplate->getFields();
foreach ( $psTemplateFields as $psTemplateField ) {
$prop_array = $psTemplateField->getObject( 'semanticmediawiki_Property' );
if ( empty( $prop_array ) ) {
continue;
}
// If property name is blank, set it to the
// field name.
if ( !array_key_exists( 'name', $prop_array ) || empty( $prop_array['name'] ) ) {
$prop_array['name'] = $psTemplateField->getName();
}
$propertyDataArray[] = $prop_array;
}
}
return $propertyDataArray;
}
/**
* Constructs XML for the "connecting property", based on what was
* submitted in the 'edit schema' form.
*/
public static function createTemplateXMLFromForm() {
global $wgRequest;
$xmlPerTemplate = [];
foreach ( $wgRequest->getValues() as $var => $val ) {
if ( substr( $var, 0, 24 ) == 'smw_connecting_property_' ) {
$templateNum = substr( $var, 24 );
$xml = '<semanticmediawiki_ConnectingProperty name="' . $val . '" />';
$xmlPerTemplate[$templateNum] = $xml;
}
}
return $xmlPerTemplate;
}
static function getConnectingPropertyName( $psTemplate ) {
// TODO - there should be a more direct way to get
// this data.
$smwConnectingPropertyArray = $psTemplate->getObject( 'semanticmediawiki_ConnectingProperty' );
return PageSchemas::getValueFromObject( $smwConnectingPropertyArray, 'name' );
}
/**
* Sets the list of property pages defined by the passed-in
* Page Schemas object.
*/
public static function getPagesToGenerate( $pageSchemaObj ) {
$pagesToGenerate = [];
$psTemplates = $pageSchemaObj->getTemplates();
$titleFactory = MediaWikiServices::getInstance()->getTitleFactory();
foreach ( $psTemplates as $psTemplate ) {
$smwConnectingPropertyName = self::getConnectingPropertyName( $psTemplate );
if ( $smwConnectingPropertyName === null ) {
continue;
}
$pagesToGenerate[] = $titleFactory->makeTitleSafe( SMW_NS_PROPERTY, $smwConnectingPropertyName );
}
$propertyDataArray = self::getAllPropertyData( $pageSchemaObj );
foreach ( $propertyDataArray as $propertyData ) {
$title = $titleFactory->makeTitleSafe( SMW_NS_PROPERTY, $propertyData['name'] );
$pagesToGenerate[] = $title;
}
return $pagesToGenerate;
}
/**
* Constructs XML for the SMW property, based on what was submitted
* in the 'edit schema' form.
*/
public static function createFieldXMLFromForm() {
global $wgRequest;
$fieldNum = -1;
$xmlPerField = [];
foreach ( $wgRequest->getValues() as $var => $val ) {
if ( substr( $var, 0, 18 ) == 'smw_property_name_' ) {
$fieldNum = substr( $var, 18 );
$xml = '<semanticmediawiki_Property name="' . $val . '" >';
} elseif ( substr( $var, 0, 18 ) == 'smw_property_type_' ) {
$xml .= '<Type>' . $val . '</Type>';
} elseif ( substr( $var, 0, 16 ) == 'smw_linked_form_' ) {
if ( $val !== '' ) {
$xml .= '<LinkedForm>' . $val . '</LinkedForm>';
}
} elseif ( substr( $var, 0, 11 ) == 'smw_values_' ) {
if ( $val !== '' ) {
// replace the comma substitution character that has no chance of
// being included in the values list - namely, the ASCII beep
$listSeparator = ',';
$allowed_values_str = str_replace( "\\$listSeparator", "\a", $val );
$allowed_values_array = explode( $listSeparator, $allowed_values_str );
foreach ( $allowed_values_array as $value ) {
// replace beep back with comma, trim
$value = str_replace( "\a", $listSeparator, trim( $value ) );
$xml .= '<AllowedValue>' . $value . '</AllowedValue>';
}
}
$xml .= '</semanticmediawiki_Property>';
$xmlPerField[$fieldNum] = $xml;
}
}
return $xmlPerField;
}
/**
* Returns the HTML necessary for getting information about the
* "connecting property" within the Page Schemas 'editschema' page.
*/
public static function getTemplateEditingHTML( $psTemplate ) {
// Only display this if the Semantic Internal Objects extension
// isn't displaying something similar.
if ( class_exists( 'SIOPageSchemas' ) ) {
return null;
}
$prop_array = [];
$hasExistingValues = false;
if ( $psTemplate !== null ) {
$prop_array = $psTemplate->getObject( 'semanticmediawiki_ConnectingProperty' );
if ( $prop_array !== null ) {
$hasExistingValues = true;
}
}
$text = '<p>' . 'Name of property to connect this template\'s fields to the rest of the page:' . ' ' . '(should only be used if this template can have multiple instances)' . ' ';
$propName = PageSchemas::getValueFromObject( $prop_array, 'name' );
$text .= Html::input( 'smw_connecting_property_num', $propName, 'text', [ 'size' => 15 ] ) . "\n";
return [ $text, $hasExistingValues ];
}
/**
* Returns the HTML necessary for getting information about a regular
* semantic property within the Page Schemas 'editschema' page.
*/
public static function getFieldEditingHTML( $psTemplateField ) {
$smwgContLang = smwfContLang();
$prop_array = [];
$hasExistingValues = false;
if ( $psTemplateField !== null ) {
$prop_array = $psTemplateField->getObject( 'semanticmediawiki_Property' );
if ( $prop_array !== null ) {
$hasExistingValues = true;
}
}
$html_text = '<p>' . wfMessage( 'ps-optional-name' )->escaped() . ' ';
$propName = PageSchemas::getValueFromObject( $prop_array, 'name' );
$html_text .= Html::input( 'smw_property_name_num', $propName, 'text', [ 'size' => 15 ] ) . "\n";
$propType = PageSchemas::getValueFromObject( $prop_array, 'Type' );
$select_body = "";
$datatype_labels = $smwgContLang->getDatatypeLabels();
foreach ( $datatype_labels as $label ) {
$optionAttrs = [];
if ( $label == $propType ) {
$optionAttrs['selected'] = 'selected';
}
$select_body .= "\t" . Xml::element( 'option', $optionAttrs, $label ) . "\n";
}
$propertyDropdownAttrs = [
'id' => 'property_dropdown',
'name' => 'smw_property_type_num',
'value' => $propType ?? ''
];
$html_text .= "Type: " . Xml::tags( 'select', $propertyDropdownAttrs, $select_body ) . "</p>\n";
// This can't be last, because of the hacky way the XML is
// ocnstructed from this form's output.
if ( defined( 'SF_VERSION' ) ) {
$html_text .= '<p>' . wfMessage( 'sf_createproperty_linktoform' )->escaped() . ' ';
$linkedForm = PageSchemas::getValueFromObject( $prop_array, 'LinkedForm' );
$html_text .= Html::input( 'smw_linked_form_num', $linkedForm, 'text', [ 'size' => 15 ] ) . "\n";
$html_text .= "(for Page properties only)</p>\n";
}
$html_text .= '<p>If you want this property to only be allowed to have certain values, enter the list of allowed values, separated by commas (if a value contains a comma, replace it with "\,"):</p>';
$allowedValsInputAttrs = [
'size' => 80
];
$allowedValues = PageSchemas::getValueFromObject( $prop_array, 'allowed_values' );
if ( $allowedValues === null ) {
$allowed_val_string = '';
} else {
$allowed_val_string = implode( ', ', $allowedValues );
}
$html_text .= '<p>' . Html::input( 'smw_values_num', $allowed_val_string, 'text', $allowedValsInputAttrs ) . "</p>\n";
return [ $html_text, $hasExistingValues ];
}
/**
* Creates the property page for each property specified in the
* passed-in Page Schemas XML object.
*/
public static function generatePages( $pageSchemaObj, $selectedPages ) {
$services = MediaWikiServices::getInstance();
$titleFactory = $services->getTitleFactory();
$datatypeLabels = smwfContLang()->getDatatypeLabels();
$pageTypeLabel = $datatypeLabels['_wpg'];
$jobs = [];
$jobParams = [];
$jobParams['user_id'] = RequestContext::getMain()->getUser()->getId();
// First, create jobs for all "connecting properties".
$psTemplates = $pageSchemaObj->getTemplates();
foreach ( $psTemplates as $psTemplate ) {
$smwConnectingPropertyName = self::getConnectingPropertyName( $psTemplate );
if ( $smwConnectingPropertyName === null ) {
continue;
}
$propTitle = $titleFactory->makeTitleSafe( SMW_NS_PROPERTY, $smwConnectingPropertyName );
if ( !in_array( $propTitle, $selectedPages ) ) {
continue;
}
$jobParams['page_text'] = self::createPropertyText( $pageTypeLabel, null, null );
$jobs[] = new PSCreatePageJob( $propTitle, $jobParams );
}
// Second, create jobs for all regular properties.
$propertyDataArray = self::getAllPropertyData( $pageSchemaObj );
foreach ( $propertyDataArray as $propertyData ) {
$propTitle = $titleFactory->makeTitleSafe( SMW_NS_PROPERTY, $propertyData['name'] );
if ( !in_array( $propTitle, $selectedPages ) ) {
continue;
}
$propertyType = array_key_exists( 'Type', $propertyData ) ? $propertyData['Type'] : null;
$propertyAllowedValues = array_key_exists( 'allowed_values', $propertyData ) ? $propertyData['allowed_values'] : null;
$propertyLinkedForm = array_key_exists( 'LinkedForm', $propertyData ) ? $propertyData['LinkedForm'] : null;
$jobParams['page_text'] = self::createPropertyText( $propertyType, $propertyAllowedValues, $propertyLinkedForm );
$jobs[] = new PSCreatePageJob( $propTitle, $jobParams );
}
$services->getJobQueueGroup()->push( $jobs );
}
/**
* Creates the text for a property page.
*/
public static function createPropertyText( $propertyType, $allowedValues, $linkedForm = null ) {
$smwgContLang = smwfContLang();
$propLabels = $smwgContLang->getPropertyLabels();
$hasTypeLabel = $propLabels['_TYPE'];
$typeTag = "[[$hasTypeLabel::$propertyType]]";
$text = wfMessage( 'smw-createproperty-isproperty', $typeTag )->inContentLanguage()->text();
if ( $linkedForm !== '' && defined( 'SF_VERSION' ) ) {
global $sfgContLang;
$sfPropLabels = $sfgContLang->getPropertyLabels();
$defaultFormTag = "[[{$sfPropLabels[SF_SP_HAS_DEFAULT_FORM]}::$linkedForm]]";
$text .= ' ' . wfMessage( 'sf_property_linkstoform', $defaultFormTag )->inContentLanguage()->text();
}
if ( $allowedValues != null ) {
$text .= "\n\n" . wfMessage( 'smw-createproperty-allowedvals', MediaWikiServices::getInstance()->getContentLanguage()->formatNum( count( $allowedValues ) ) )->inContentLanguage()->text();
foreach ( $allowedValues as $value ) {
$prop_labels = $smwgContLang->getPropertyLabels();
$text .= "\n* [[" . $prop_labels['_PVAL'] . "::$value]]";
}
}
return $text;
}
/**
* Returns either the "connecting property", or a field property, based
* on the XML passed from the Page Schemas extension.
*/
public static function createPageSchemasObject( $tagName, $xml ) {
if ( $tagName == "semanticmediawiki_ConnectingProperty" ) {
foreach ( $xml->children() as $tag => $child ) {
if ( $tag == $tagName ) {
$smw_array = [];
$propName = $child->attributes()->name;
$smw_array['name'] = (string)$propName;
foreach ( $child->children() as $prop => $value ) {
$smw_array[$prop] = (string)$value;
}
return $smw_array;
}
}
} elseif ( $tagName == "semanticmediawiki_Property" ) {
foreach ( $xml->children() as $tag => $child ) {
if ( $tag == $tagName ) {
$smw_array = [];
$propName = $child->attributes()->name;
$smw_array['name'] = (string)$propName;
$allowed_values = [];
$count = 0;
foreach ( $child->children() as $prop => $value ) {
if ( $prop == "AllowedValue" ) {
$allowed_values[$count++] = $value;
} else {
$smw_array[$prop] = (string)$value;
}
}
$smw_array['allowed_values'] = $allowed_values;
return $smw_array;
}
}
}
return null;
}
}