diff options
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/src/SQLStore/ConceptCache.php')
-rw-r--r-- | www/wiki/extensions/SemanticMediaWiki/src/SQLStore/ConceptCache.php | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/src/SQLStore/ConceptCache.php b/www/wiki/extensions/SemanticMediaWiki/src/SQLStore/ConceptCache.php new file mode 100644 index 00000000..f228ff88 --- /dev/null +++ b/www/wiki/extensions/SemanticMediaWiki/src/SQLStore/ConceptCache.php @@ -0,0 +1,270 @@ +<?php + +namespace SMW\SQLStore; + +use SMW\DIConcept; +use SMW\DIProperty; +use SMW\DIWikiPage; +use SMW\ProcessingErrorMsgHandler; +use SMW\SQLStore\QueryEngine\ConceptQuerySegmentBuilder; +use SMWSQLStore3; +use SMWWikiPageValue; +use Title; + +/** + * @license GNU GPL v2+ + * @since 2.2 + * + * @author Jeroen De Dauw < jeroendedauw@gmail.com > + */ +class ConceptCache { + + /** + * @var SMWSQLStore3 + */ + private $store; + + /** + * @var ConceptQuerySegmentBuilder + */ + private $conceptQuerySegmentBuilder; + + /** + * @var integer + */ + private $upperLimit = 50; + + /** + * @since 2.2 + * + * @param SMWSQLStore3 $store + * @param ConceptQuerySegmentBuilder $conceptQueryResolver + */ + public function __construct( SMWSQLStore3 $store, ConceptQuerySegmentBuilder $conceptQuerySegmentBuilder ) { + $this->store = $store; + $this->conceptQuerySegmentBuilder = $conceptQuerySegmentBuilder; + } + + /** + * @since 2.2 + * + * @param integer $upperLimit + */ + public function setUpperLimit( $upperLimit ) { + $this->upperLimit = (int)$upperLimit; + } + + /** + * Refresh the concept cache for the given concept. + * + * @since 1.8 + * @param $concept Title + * @return array of error strings (empty if no errors occurred) + */ + public function refreshConceptCache( Title $concept ) { + + $errors = array_merge( + $this->conceptQuerySegmentBuilder->getErrors(), + $this->refresh( $concept ) + ); + + $this->conceptQuerySegmentBuilder->cleanUp(); + + return ProcessingErrorMsgHandler::normalizeAndDecodeMessages( $errors ); + } + + /** + * Delete the concept cache for the given concept. + * + * @param $concept Title + */ + public function deleteConceptCache( $concept ) { + $this->delete( $concept ); + } + + /** + * @param Title $concept + * + * @return string[] array with error messages + */ + public function refresh( Title $concept ) { + global $wgDBtype; + + $db = $this->store->getConnection(); + + $cid = $this->store->smwIds->getSMWPageID( $concept->getDBkey(), SMW_NS_CONCEPT, '', '' ); + $cid_c = $this->getIdOfConcept( $concept ); + + if ( $cid !== $cid_c ) { + return [ "Skipping redirect concept." ]; + } + + $conceptQueryText = $this->getConceptCacheText( $concept ); + + if ( $conceptQueryText === false ) { + $this->deleteConceptById( $cid ); + + return [ "No concept description found." ]; + } + + // Pre-process query: + $querySegment = $this->conceptQuerySegmentBuilder->getQuerySegmentFrom( + $conceptQueryText + ); + + if ( $querySegment === null || $querySegment->joinfield === '' || $querySegment->joinTable === '' ) { + return []; + } + + // TODO: catch db exception + $db->delete( + SMWSQLStore3::CONCEPT_CACHE_TABLE, + [ 'o_id' => $cid ], + __METHOD__ + ); + + $concCacheTableName = $db->tablename( SMWSQLStore3::CONCEPT_CACHE_TABLE ); + + // MySQL just uses INSERT IGNORE, no extra conditions + $where = $querySegment->where; + + if ( $wgDBtype == 'postgres' ) { + // PostgresQL: no INSERT IGNORE, check for duplicates explicitly + // This code doesn't work and has created all sorts of issues therefore use LEFT JOIN instead + // http://people.planetpostgresql.org/dfetter/index.php?/archives/48-Adding-Only-New-Rows-INSERT-IGNORE,-Done-Right.html + // $where = $querySegment->where . ( $querySegment->where ? ' AND ' : '' ) . + // "NOT EXISTS (SELECT NULL FROM $concCacheTableName" . + // " WHERE {$concCacheTableName}.s_id = {$querySegment->alias}.s_id " . + // " AND {$concCacheTableName}.o_id = {$querySegment->alias}.o_id )"; + $querySegment->from = str_replace( 'INNER JOIN', 'LEFT JOIN', $querySegment->from ); + } + + $db->query( "INSERT " . ( ( $wgDBtype == 'postgres' ) ? '' : 'IGNORE ' ) . + "INTO $concCacheTableName" . + " SELECT DISTINCT {$querySegment->joinfield} AS s_id, $cid AS o_id FROM " . + $db->tableName( $querySegment->joinTable ) . " AS {$querySegment->alias}" . + $querySegment->from . + ( $where ? ' WHERE ' : '' ) . $where . " LIMIT ". $this->upperLimit, + __METHOD__ + ); + + $db->update( + 'smw_fpt_conc', + [ 'cache_date' => strtotime( "now" ), 'cache_count' => $db->affectedRows() ], + [ 's_id' => $cid ], + __METHOD__ + ); + + return []; + } + + /** + * @param Title $concept + * + * @return string + */ + public function getConceptCacheText( Title $concept ) { + $values = $this->store->getPropertyValues( + DIWikiPage::newFromTitle( $concept ), + new DIProperty( '_CONC' ) + ); + + /** + * @var bool|DIConcept $di + */ + $di = end( $values ); + $conceptQueryText = $di === false ?: $di->getConceptQuery(); + + return $conceptQueryText; + } + + public function delete( Title $concept ) { + $this->deleteConceptById( $this->getIdOfConcept( $concept ) ); + } + + /** + * @param Title $concept + * + * @return int + */ + private function getIdOfConcept( Title $concept ) { + return $this->store->smwIds->getSMWPageID( + $concept->getDBkey(), + SMW_NS_CONCEPT, + '', + '', + false + ); + } + + /** + * @param int $conceptId + */ + private function deleteConceptById( $conceptId ) { + // TODO: exceptions should be caught + + $db = $this->store->getConnection(); + + $db->delete( + SMWSQLStore3::CONCEPT_CACHE_TABLE, + [ 'o_id' => $conceptId ], + __METHOD__ + ); + + $db->update( + 'smw_fpt_conc', + [ 'cache_date' => null, 'cache_count' => null ], + [ 's_id' => $conceptId ], + __METHOD__ + ); + } + + /** + * @param Title|SMWWikiPageValue|DIWikiPage $concept + * + * @return DIConcept|null + */ + public function getStatus( $concept ) { + $db = $this->store->getConnection(); + + $cid = $this->store->smwIds->getSMWPageID( + $concept->getDBkey(), + $concept->getNamespace(), + '', + '', + false + ); + + // TODO: catch db exception + + $row = $db->selectRow( + 'smw_fpt_conc', + [ 'concept_txt', 'concept_features', 'concept_size', 'concept_depth', 'cache_date', 'cache_count' ], + [ 's_id' => $cid ], + __METHOD__ + ); + + if ( $row === false ) { + return null; + } + + $dataItem = new DIConcept( + $concept, + null, + $row->concept_features, + $row->concept_size, + $row->concept_depth + ); + + if ( $row->cache_date ) { + $dataItem->setCacheStatus( 'full' ); + $dataItem->setCacheDate( $row->cache_date ); + $dataItem->setCacheCount( $row->cache_count ); + } else { + $dataItem->setCacheStatus( 'empty' ); + } + + return $dataItem; + } + +} |