379 lines
13 KiB
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;
|
|
}
|
|
}
|