diff options
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Record.php')
-rw-r--r-- | www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Record.php | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Record.php b/www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Record.php new file mode 100644 index 00000000..f4bab7e6 --- /dev/null +++ b/www/wiki/extensions/SemanticMediaWiki/includes/datavalues/SMW_DV_Record.php @@ -0,0 +1,300 @@ +<?php + +use SMW\ApplicationFactory; +use SMW\DataValueFactory; +use SMW\DataValues\AbstractMultiValue; +use SMW\DIProperty; +use SMW\DIWikiPage; +use SMWContainerSemanticData as ContainerSemanticData; +use SMWDataItem as DataItem; +use SMWDIContainer as DIContainer; + +/** + * SMWDataValue implements the handling of small sets of property-value pairs. + * The declaration of Records in SMW uses the order of values to encode the + * property that should be used, so the user only needs to enter a list of + * values. Internally, however, the property-value assignments are not stored + * with a particular order; they will only be ordered for display, following + * the declaration. This is why it is not supported to have Records using the + * same property for more than one value. + * + * The class uses DIContainer objects to return its inner state. See the + * documentation for DIContainer for details on how this "pseudo" data + * encapsulated many property assignments. Such data is stored internally + * like a page with various property-value assignments. Indeed, record values + * can be created from DIWikiPage objects (the missing information will + * be fetched from the store). + * + * @todo Enforce limitation of maximal number of values. + * @todo Enforce uniqueness of properties in declaration. + * @todo Complete internationalisation. + * + * @author Markus Krötzsch + * @ingroup SMWDataValues + */ +class SMWRecordValue extends AbstractMultiValue { + + /// cache for properties for the fields of this data value + protected $m_diProperties = null; + + /** + * @param string $typeid + */ + public function __construct( $typeid = '' ) { + parent::__construct( '_rec' ); + } + + /** + * @since 2.3 + * + * @return DIProperty[]|null + */ + public function getProperties() { + return $this->m_diProperties; + } + + /** + * @since 2.3 + * + * @param string $value + * + * @return array + */ + public function getValuesFromString( $value ) { + // #664 / T17732 + $value = str_replace( "\;", "-3B", $value ); + + // Bug 21926 / T23926 + // Values that use html entities are encoded with a semicolon + $value = htmlspecialchars_decode( $value, ENT_QUOTES ); + $values = preg_split( '/[\s]*;[\s]*/u', trim( $value ) ); + + return str_replace( "-3B", ";", $values ); + } + + protected function parseUserValue( $value ) { + + if ( $value === '' ) { + $this->addErrorMsg( [ 'smw_novalues' ] ); + return; + } + + $containerSemanticData = $this->newContainerSemanticData( $value ); + $sortKeys = []; + + $values = $this->getValuesFromString( $value ); + $valueIndex = 0; // index in value array + $propertyIndex = 0; // index in property list + $empty = true; + + foreach ( $this->getPropertyDataItems() as $diProperty ) { + + if ( !array_key_exists( $valueIndex, $values ) || $this->getErrors() !== [] ) { + break; // stop if there are no values left + } + + // generating the DVs: + if ( ( $values[$valueIndex] === '' ) || ( $values[$valueIndex] == '?' ) ) { // explicit omission + $valueIndex++; + } else { + $dataValue = DataValueFactory::getInstance()->newDataValueByProperty( + $diProperty, + $values[$valueIndex], + false, + $containerSemanticData->getSubject() + ); + + if ( $dataValue->isValid() ) { // valid DV: keep + $containerSemanticData->addPropertyObjectValue( $diProperty, $dataValue->getDataItem() ); + $sortKeys[] = $dataValue->getDataItem()->getSortKey(); + + $valueIndex++; + $empty = false; + } elseif ( ( count( $values ) - $valueIndex ) == ( count( $this->m_diProperties ) - $propertyIndex ) ) { + $containerSemanticData->addPropertyObjectValue( $diProperty, $dataValue->getDataItem() ); + $this->addError( $dataValue->getErrors() ); + ++$valueIndex; + } + } + ++$propertyIndex; + } + + if ( $empty && $this->getErrors() === [] ) { + $this->addErrorMsg( [ 'smw_novalues' ] ); + } + + // Remember the data to extend the sortkey + $containerSemanticData->setExtensionData( 'sort.data', implode( ';', $sortKeys ) ); + + $this->m_dataitem = new DIContainer( $containerSemanticData ); + } + + /** + * @see SMWDataValue::loadDataItem() + * @param $dataitem DataItem + * @return boolean + */ + protected function loadDataItem( DataItem $dataItem ) { + if ( $dataItem->getDIType() == DataItem::TYPE_CONTAINER ) { + $this->m_dataitem = $dataItem; + return true; + } elseif ( $dataItem->getDIType() == DataItem::TYPE_WIKIPAGE ) { + $semanticData = new ContainerSemanticData( $dataItem ); + $semanticData->copyDataFrom( ApplicationFactory::getInstance()->getStore()->getSemanticData( $dataItem ) ); + $this->m_dataitem = new DIContainer( $semanticData ); + return true; + } else { + return false; + } + } + + public function getShortWikiText( $linked = null ) { + if ( $this->m_caption !== false ) { + return $this->m_caption; + } + return $this->makeOutputText( 0, $linked ); + } + + public function getShortHTMLText( $linker = null ) { + if ( $this->m_caption !== false ) { + return $this->m_caption; + } + return $this->makeOutputText( 1, $linker ); + } + + public function getLongWikiText( $linked = null ) { + return $this->makeOutputText( 2, $linked ); + } + + public function getLongHTMLText( $linker = null ) { + return $this->makeOutputText( 3, $linker ); + } + + public function getWikiValue() { + return $this->makeOutputText( 4 ); + } + + /** + * Make sure that the content is reset in this case. + * @todo This is not a full reset yet (the case that property is changed after a value + * was set does not occur in the normal flow of things, hence this has low priority). + */ + public function setProperty( DIProperty $property ) { + parent::setProperty( $property ); + $this->m_diProperties = null; + } + + /** + * @since 2.1 + * + * @param DIProperty[] $properties + */ + public function setFieldProperties( array $properties ) { + foreach ( $properties as $property ) { + if ( $property instanceof DIProperty ) { + $this->m_diProperties[] = $property; + } + } + } + + /** + * @since 1.6 + * + * {@inheritDoc} + */ + public function getDataItems() { + return parent::getDataItems(); + } + + /** + * Return the array (list) of properties that the individual entries of + * this datatype consist of. + * + * @since 1.6 + * + * @todo I18N for error message. + * + * @return array of DIProperty + */ + public function getPropertyDataItems() { + + if ( $this->m_diProperties !== null ) { + return $this->m_diProperties; + } + + $this->m_diProperties = $this->getFieldProperties( $this->m_property ); + + if ( $this->m_diProperties === [] ) { // TODO internalionalize + $this->addError( 'The list of properties to be used for the data fields has not been specified properly.' ); + } + + return $this->m_diProperties; + } + + protected function makeOutputText( $type = 0, $linker = null ) { + if ( !$this->isValid() ) { + return ( ( $type == 0 ) || ( $type == 1 ) ) ? '' : $this->getErrorText(); + } + + $result = ''; + $i = 0; + foreach ( $this->getPropertyDataItems() as $propertyDataItem ) { + if ( $i == 1 ) { + $result .= ( $type == 4 ) ? '; ' : ' ('; + } elseif ( $i > 1 ) { + $result .= ( $type == 4 ) ? '; ' : ', '; + } + ++$i; + $propertyValues = $this->m_dataitem->getSemanticData()->getPropertyValues( $propertyDataItem ); // combining this with next line violates PHP strict standards + $dataItem = reset( $propertyValues ); + if ( $dataItem !== false ) { + $dataValue = DataValueFactory::getInstance()->newDataValueByItem( $dataItem, $propertyDataItem ); + $result .= $this->makeValueOutputText( $type, $dataValue, $linker ); + } else { + $result .= '?'; + } + } + if ( ( $i > 1 ) && ( $type != 4 ) ) { + $result .= ')'; + } + + return $result; + } + + protected function makeValueOutputText( $type, SMWDataValue $dataValue, $linker ) { + switch ( $type ) { + case 0: + return $dataValue->getShortWikiText( $linker ); + case 1: + return $dataValue->getShortHTMLText( $linker ); + case 2: + return $dataValue->getShortWikiText( $linker ); + case 3: + return $dataValue->getShortHTMLText( $linker ); + case 4: + return str_replace( ";", "\;", $dataValue->getWikiValue() ); + } + } + + private function newContainerSemanticData( $value ) { + + if ( $this->m_contextPage === null ) { + $containerSemanticData = ContainerSemanticData::makeAnonymousContainer(); + $containerSemanticData->skipAnonymousCheck(); + } else { + $subobjectName = '_' . hash( 'md4', $value, false ); // md4 is probably fastest of PHP's hashes + + $subject = new DIWikiPage( + $this->m_contextPage->getDBkey(), + $this->m_contextPage->getNamespace(), + $this->m_contextPage->getInterwiki(), + $subobjectName + ); + + $containerSemanticData = new ContainerSemanticData( $subject ); + } + + return $containerSemanticData; + } + +} |