diff options
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/src/SQLStore/EntityStore/StubSemanticData.php')
-rw-r--r-- | www/wiki/extensions/SemanticMediaWiki/src/SQLStore/EntityStore/StubSemanticData.php | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/src/SQLStore/EntityStore/StubSemanticData.php b/www/wiki/extensions/SemanticMediaWiki/src/SQLStore/EntityStore/StubSemanticData.php new file mode 100644 index 00000000..c049b0bd --- /dev/null +++ b/www/wiki/extensions/SemanticMediaWiki/src/SQLStore/EntityStore/StubSemanticData.php @@ -0,0 +1,384 @@ +<?php + +namespace SMW\SQLStore\EntityStore; + +use SMW\DataTypeRegistry; +use SMW\DIProperty; +use SMW\DIWikiPage; +use SMW\Exception\DataItemException; +use SMW\SQLStore\EntityStore\Exception\DataItemHandlerException; +use SMW\SQLStore\SQLStore; +use SMW\StoreFactory; +use SMWDataItem as DataItem; +use SMWSemanticData as SemanticData; + +/** + * This class provides a subclass of SemanticData that can store prefetched values + * from the SQL store, and unstub this data on demand when it is accessed. + * + * @license GNU GPL v2+ + * @since 1.8 + * + * @author Markus Krötzs + * @author mwjames + */ +class StubSemanticData extends SemanticData { + + /** + * @var SQLStore + */ + protected $store; + + /** + * Stub property data that is not part of $mPropVals and $mProperties + * yet. Entries use property keys as keys. The value is an array of + * DBkey-arrays that define individual datavalues. The stubs will be + * set up when first accessed. + * + * @since 1.8 + * + * @var array + */ + protected $mStubPropVals = []; + + /** + * DIWikiPage object that is the subject of this container. + * Subjects that are null are used to represent "internal objects" + * only. + * + * @since 1.8 + * + * @var DIWikiPage + */ + protected $mSubject; + + /** + * Whether SubSemanticData have been requested and added + * + * @var boolean + */ + private $subSemanticDataInit = false; + + /** + * @since 1.8 + * + * @param DIWikiPage $subject to which this data refers + * @param SQLStore $store (the parent store) + * @param boolean $noDuplicates stating if duplicate data should be avoided + */ + public function __construct( DIWikiPage $subject, SQLStore $store, $noDuplicates = true ) { + $this->store = $store; + parent::__construct( $subject, $noDuplicates ); + } + + /** + * Required to support php-serialization + * + * @since 2.3 + * + * @return array + */ + public function __sleep() { + return [ 'mSubject', 'mPropVals', 'mProperties', 'subSemanticData', 'mStubPropVals', 'options', 'extensionData' ]; + } + + /** + * @since 2.3 + */ + public function __wakeup() { + $this->store = StoreFactory::getStore( 'SMW\SQLStore\SQLStore' ); + } + + /** + * Create a new StubSemanticData object that holds the data of a + * given SemanticData object. Array assignments create copies in PHP + * so the arrays are distinct in input and output object. The object + * references are copied as references in a shallow way. This is + * sufficient as the data items used there are immutable. + * + * @since 1.8 + * + * @param $semanticData SemanticData + * @param SQLStore $store + * + * @return StubSemanticData + */ + public static function newFromSemanticData( SemanticData $semanticData, SQLStore $store ) { + $result = new self( $semanticData->getSubject(), $store ); + $result->mPropVals = $semanticData->mPropVals; + $result->mProperties = $semanticData->mProperties; + $result->mHasVisibleProps = $semanticData->mHasVisibleProps; + $result->mHasVisibleSpecs = $semanticData->mHasVisibleSpecs; + $result->stubObject = $semanticData->stubObject; + return $result; + } + + /** + * Get the array of all properties that have stored values. + * + * @since 1.8 + * + * @return array of SMWDIProperty objects + */ + public function getProperties() { + $this->unstubProperties(); + return parent::getProperties(); + } + + /** + * @see SemanticData::hasProperty + * @since 2.5 + * + * @param DIProperty $property + * + * @return boolean + */ + public function hasProperty( DIProperty $property ) { + $this->unstubProperties(); + return parent::hasProperty( $property ); + } + + /** + * Get the array of all stored values for some property. + * + * @since 1.8 + * + * @param DIProperty $property + * + * @return array of DataItem + */ + public function getPropertyValues( DIProperty $property ) { + if ( $property->isInverse() ) { // we never have any data for inverses + return []; + } + + if ( array_key_exists( $property->getKey(), $this->mStubPropVals ) ) { + // Not catching exception here; the + $this->unstubProperty( $property->getKey(), $property ); + $propertyTypeId = $property->findPropertyTypeID(); + $propertyDiId = DataTypeRegistry::getInstance()->getDataItemId( $propertyTypeId ); + + foreach ( $this->mStubPropVals[$property->getKey()] as $dbkeys ) { + try { + $diHandler = $this->store->getDataItemHandlerForDIType( $propertyDiId ); + $di = $diHandler->dataItemFromDBKeys( $dbkeys ); + + if ( $this->mNoDuplicates ) { + $this->mPropVals[$property->getKey()][$di->getHash()] = $di; + } else { + $this->mPropVals[$property->getKey()][] = $di; + } + } catch ( DataItemHandlerException $e ) { + // ignore data + } + } + + unset( $this->mStubPropVals[$property->getKey()] ); + } + + return parent::getPropertyValues( $property ); + } + + /** + * @see SemanticData::getSubSemanticData + * + * @note SubSemanticData are added only on request to avoid unnecessary DB + * transactions + * + * @since 2.0 + */ + public function getSubSemanticData() { + + if ( $this->subSemanticDataInit ) { + return parent::getSubSemanticData(); + } + + $this->subSemanticDataInit = true; + + foreach ( $this->getProperties() as $property ) { + + // #619 Do not resolve subobjects for redirects + if ( !DataTypeRegistry::getInstance()->isSubDataType( $property->findPropertyTypeID() ) || $this->isRedirect() ) { + continue; + } + + $this->initSubSemanticData( $property ); + } + + return parent::getSubSemanticData(); + } + + /** + * @see SemanticData::hasSubSemanticData + * + * @note This method will initialize SubSemanticData first if it wasn't done + * yet to ensure data consistency + * + * @since 2.0 + */ + public function hasSubSemanticData( $subobjectName = null ) { + + if ( !$this->subSemanticDataInit ) { + $this->getSubSemanticData(); + } + + return parent::hasSubSemanticData( $subobjectName ); + } + + /** + * @see SemanticData::findSubSemanticData + * + * @since 2.5 + */ + public function findSubSemanticData( $subobjectName ) { + + if ( !$this->subSemanticDataInit ) { + $this->getSubSemanticData(); + } + + return parent::findSubSemanticData( $subobjectName ); + } + + /** + * Remove a value for a property identified by its DataItem object. + * This method removes a property-value specified by the property and + * dataitem. If there are no more property-values for this property it + * also removes the property from the mProperties. + * + * @note There is no check whether the type of the given data item + * agrees with the type of the property. Since property types can + * change, all parts of SMW are prepared to handle mismatched data item + * types anyway. + * + * @param $property SMWDIProperty + * @param $dataItem DataItem + * + * @since 1.8 + */ + public function removePropertyObjectValue( DIProperty $property, DataItem $dataItem ) { + $this->unstubProperties(); + $this->getPropertyValues( $property ); + parent::removePropertyObjectValue($property, $dataItem); + } + + /** + * Return true if there are any visible properties. + * + * @since 1.8 + * + * @return boolean + */ + public function hasVisibleProperties() { + $this->unstubProperties(); + return parent::hasVisibleProperties(); + } + + /** + * Return true if there are any special properties that can + * be displayed. + * + * @since 1.8 + * + * @return boolean + */ + public function hasVisibleSpecialProperties() { + $this->unstubProperties(); + return parent::hasVisibleSpecialProperties(); + } + + /** + * Add data in abbreviated form so that it is only expanded if needed. + * The property key is the DB key (string) of a property value, whereas + * valuekeys is an array of DBkeys for the added value that will be + * used to initialize the value if needed at some point. If there is + * only one valuekey, a single string can be used. + * + * @since 1.8 + * @param string $propertyKey + * @param array|string $valueKeys + */ + public function addPropertyStubValue( $propertyKey, $valueKeys ) { + $this->mStubPropVals[$propertyKey][] = $valueKeys; + } + + /** + * Delete all data other than the subject. + * + * @since 1.8 + */ + public function clear() { + $this->mStubPropVals = []; + parent::clear(); + } + + /** + * Process all mProperties that have been added as stubs. + * Associated data may remain in stub form. + * + * @since 1.8 + */ + protected function unstubProperties() { + foreach ( $this->mStubPropVals as $pkey => $values ) { // unstub property values only, the value lists are still kept as stubs + try { + $this->unstubProperty( $pkey ); + } catch ( DataItemException $e ) { + // Likely cause: a property name from the DB is no longer valid. + // Do nothing; we could unset the data, but it will never be + // unstubbed anyway if there is no valid property DI for it. + } + } + } + + /** + * Unstub a single property from the stub data array. If available, an + * existing object for that property might be provided, so we do not + * need to make a new one. It is not checked if the object matches the + * property name. + * + * @since 1.8 + * + * @param string $propertyKey + * @param SMWDIProperty $diProperty if available + * + * @throws DataItemException if property key is not valid + * and $diProperty is null + */ + protected function unstubProperty( $propertyKey, $diProperty = null ) { + if ( !array_key_exists( $propertyKey, $this->mProperties ) ) { + if ( is_null( $diProperty ) ) { + $diProperty = new DIProperty( $propertyKey, false ); + } + + $this->mProperties[$propertyKey] = $diProperty; + + if ( !$diProperty->isUserDefined() ) { + if ( $diProperty->isShown() ) { + $this->mHasVisibleSpecs = true; + $this->mHasVisibleProps = true; + } + } else { + $this->mHasVisibleProps = true; + } + } + } + + protected function isRedirect() { + return $this->store->getObjectIds()->isRedirect( $this->mSubject ); + } + + private function initSubSemanticData( DIProperty $property ) { + foreach ( $this->getPropertyValues( $property ) as $value ) { + + if ( !$value instanceof DIWikiPage || $value->getSubobjectName() === '' ) { + continue; + } + + if ( $this->hasSubSemanticData( $value->getSubobjectName() ) ) { + continue; + } + + $this->addSubSemanticData( $this->store->getSemanticData( $value ) ); + } + } + +} |