-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor to use new registration standard
- Loading branch information
Showing
3 changed files
with
240 additions
and
215 deletions.
There are no files selected for viewing
379 changes: 164 additions & 215 deletions
379
SemanticDependencyUpdater.php → SemanticDependencyUpdater.hooks.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,215 +1,164 @@ | ||
<?php | ||
|
||
/* | ||
* SemanticDependencyUpdater is a MediaWiki extension that monitors changes in the semantic data of a wiki page. | ||
* The affected page can the Semantic Dependency Updater property to define which pages should also be updated. | ||
* This can be defined through a list of pages or for more advanced use cases, a query string. | ||
* | ||
* This extension requires Semantic MediaWiki >= 2.3 (http://www.semantic-mediawiki.org) | ||
* | ||
* This extension is slightly based on Remco C. de Boers https://www.mediawiki.org/wiki/Extension:SemanticDummyEditor | ||
* | ||
* @author Simon Heimler, gesinn.it GmbH & Co | ||
*/ | ||
|
||
if ( !defined( 'MEDIAWIKI' ) ) { | ||
die(); | ||
} | ||
|
||
if ( !defined( 'SMW_VERSION' ) ) { | ||
die( "ERROR: Semantic MediaWiki must be installed for Semantic Dummy Editor to run!" ); | ||
} | ||
|
||
define( 'SDU_VERSION', '1.3.2' ); | ||
|
||
$wgExtensionCredits[defined( 'SEMANTIC_EXTENSION_TYPE' ) ? 'semantic' : 'other'][] = [ | ||
'name' => 'SemanticDependencyUpdater', | ||
'author' => [ | ||
'[https://www.mediawiki.org/wiki/User:Fannon Simon Heimler]', | ||
'[https://www.mediawiki.org/wiki/User:Planetenxin Alexander Gesinn]', | ||
'[https://www.mediawiki.org/wiki/User:Rcdeboer Remco C. de Boer]', | ||
], | ||
'url' => 'http://www.mediawiki.org/wiki/Extension:SemanticDependencyUpdater', | ||
'description' => 'Monitors semantic data changes and updates dependend pages', | ||
'version' => SDU_VERSION, | ||
]; | ||
|
||
global $wgExtensionFunctions; | ||
$wgExtensionFunctions[] = 'SemanticDependencyUpdater::setup'; | ||
$wgJobClasses['DummyEditJob'] = 'DummyEditJob'; | ||
|
||
$wgSDUProperty = 'Semantic Dependency'; | ||
$wgSDUUseJobQueue = false; | ||
|
||
class SemanticDependencyUpdater { | ||
|
||
public static function setup() { | ||
global $wgHooks; | ||
$wgHooks['SMW::SQLStore::AfterDataUpdateComplete'][] = 'SemanticDependencyUpdater::onAfterDataUpdateComplete'; | ||
} | ||
|
||
public static function onAfterDataUpdateComplete( SMWStore $store, SMWSemanticData $newData, | ||
$compositePropertyTableDiffIterator ) { | ||
|
||
global $wgSDUProperty; | ||
global $wgSDUTraversed; | ||
|
||
if ( !isset( $wgSDUTraversed ) ) { | ||
$wgSDUTraversed = []; | ||
} | ||
|
||
$wgSDUProperty = str_replace( ' ', '_', $wgSDUProperty ); | ||
$subject = $newData->getSubject(); | ||
$title = $subject->getTitle(); | ||
$id = $title->getPrefixedDBKey(); | ||
|
||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --> " . $title ); | ||
|
||
|
||
// FIRST CHECK: Does the page data contain a $wgSUTPropertyName semantic property ? | ||
$properties = $newData->getProperties(); | ||
$diffTable = $compositePropertyTableDiffIterator->getOrderedDiffByTable(); | ||
|
||
if ( !isset( $properties[$wgSDUProperty] ) ) { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] <-- No SDU property found" ); | ||
return true; | ||
} | ||
|
||
|
||
// SECOND CHECK: Have there been actual changes in the data? (Ignore internal SMW data!) | ||
// TODO: Introduce an explicit list of Semantic Properties to watch ? | ||
unset( $diffTable['smw_fpt_mdat'] ); // Ignore SMW's internal properties "smw_fpt_mdat" | ||
|
||
if ( count( $diffTable ) > 0 ) { | ||
// wfDebugLog('SemanticDependencyUpdater', "[SDU] diffTable: " . print_r($diffTable, true)); | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] -----> Data changes detected" ); | ||
} else { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] <-- No semantic data changes detected" ); | ||
return true; | ||
} | ||
|
||
|
||
// THIRD CHECK: Has this page been already traversed more than twice? | ||
// This should only be the case when SMW errors occur. | ||
// In that case, the diffTable contains everything and SDU can't know if changes happend | ||
if ( array_key_exists( $id, $wgSDUTraversed ) ) { | ||
$wgSDUTraversed[$id] = $wgSDUTraversed[$id] + 1; | ||
} else { | ||
$wgSDUTraversed[$id] = 1; | ||
} | ||
if ( $wgSDUTraversed[$id] > 2 ) { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] <-- Already traversed" ); | ||
return true; | ||
} | ||
|
||
|
||
// QUERY AND UPDATE DEPENDENCIES | ||
|
||
$dataItem = $newData->getPropertyValues( $properties[$wgSDUProperty] ); | ||
|
||
foreach ( $dataItem as $valueItem ) { | ||
SemanticDependencyUpdater::updatePagesMatchingQuery( $valueItem->getString() ); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* @param string $queryString Query string, excluding [[ and ]] brackets | ||
*/ | ||
private static function updatePagesMatchingQuery( $queryString ) { | ||
|
||
global $sfgListSeparator; | ||
|
||
$queryString = str_replace( 'AND', ']] [[', $queryString ); | ||
$queryString = str_replace( 'OR', ']] OR [[', $queryString ); | ||
|
||
// If SF is installed, get the separator character and change it into || | ||
// Otherwise SDU won't work with multi-value properties | ||
if ( isset( $sfgListSeparator ) ) { | ||
$queryString = rtrim( $queryString, $sfgListSeparator ); | ||
$queryString = str_replace( $sfgListSeparator, ' || ', $queryString ); | ||
} | ||
|
||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --------> [[$queryString]]" ); | ||
|
||
$store = smwfGetStore(); | ||
|
||
$params = [ | ||
'limit' => 10000, | ||
]; | ||
$processedParams = SMWQueryProcessor::getProcessedParams( $params ); | ||
$query = | ||
SMWQueryProcessor::createQuery( "[[$queryString]]", $processedParams, SMWQueryProcessor::SPECIAL_PAGE ); | ||
$result = $store->getQueryResult( $query ); // SMWQueryResult | ||
$wikiPageValues = $result->getResults(); // array of SMWWikiPageValues | ||
|
||
// TODO: This can be optimized by collecting a list of all pages first, make them unique | ||
// and do the dummy edit afterwards | ||
// TODO: A threshold when to switch to Queue Jobs might be smarter | ||
foreach ( $wikiPageValues as $page ) { | ||
SemanticDependencyUpdater::dummyEdit( $page->getTitle() ); | ||
} | ||
|
||
return; | ||
} | ||
|
||
/** | ||
* Save a null revision in the page's history to propagate the update | ||
* | ||
* @param Title $title | ||
*/ | ||
public static function dummyEdit( $title ) { | ||
global $wgSDUUseJobQueue; | ||
|
||
if ( $wgSDUUseJobQueue ) { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --------> [Edit Job] $title" ); | ||
$job = new DummyEditJob( $title ); | ||
$job->insert(); | ||
} else { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --------> [Edit] $title" ); | ||
$page = WikiPage::newFromID( $title->getArticleId() ); | ||
if ( $page ) { // prevent NPE when page not found | ||
$content = $page->getContent( Revision::RAW ); | ||
$text = ContentHandler::getContentText( $content ); | ||
$page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), | ||
"[SemanticDependencyUpdater] Null edit." ); // since this is a null edit, the edit summary will be ignored. | ||
$page->doPurge(); // required since SMW 2.5.1 | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
||
class DummyEditJob extends Job { | ||
|
||
function __construct( $title, $params = '', $id = 0 ) { | ||
parent::__construct( 'DummyEditJob', $title, $params, $id ); | ||
} | ||
|
||
/** | ||
* Run the job | ||
* @return boolean success | ||
*/ | ||
function run() { | ||
wfProfileIn( __METHOD__ ); | ||
|
||
if ( is_null( $this->title ) ) { | ||
$this->error = "DummyEditJob: Invalid title"; | ||
wfProfileOut( __METHOD__ ); | ||
return false; | ||
} | ||
|
||
$page = WikiPage::newFromID( $this->title->getArticleId() ); | ||
if ( $page ) { // prevent NPE when page not found | ||
$content = $page->getContent( Revision::RAW ); | ||
$text = ContentHandler::getContentText( $content ); | ||
$page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), | ||
"[SemanticDependencyUpdater] Null edit." ); // since this is a null edit, the edit summary will be ignored. | ||
$page->doPurge(); // required since SMW 2.5.1 | ||
} | ||
|
||
wfProfileOut( __METHOD__ ); | ||
return true; | ||
} | ||
} | ||
<?php | ||
/** | ||
* Created by PhpStorm. | ||
* User: Sebastian | ||
* Date: 21.08.2018 | ||
* Time: 08:56 | ||
*/ | ||
|
||
namespace SDU; | ||
|
||
use SMW; | ||
use SMWStore; | ||
use SMWSemanticData; | ||
use SMWQueryProcessor; | ||
use Revision; | ||
use WikiPage; | ||
use ContentHandler; | ||
|
||
class Hooks { | ||
|
||
public static function setup() { | ||
|
||
if ( !defined( 'MEDIAWIKI' ) ) { | ||
die(); | ||
} | ||
|
||
if ( !defined( 'SMW_VERSION' ) ) { | ||
die( "ERROR: Semantic MediaWiki must be installed for Semantic Dependency Updater to run!" ); | ||
} | ||
|
||
global $wgHooks; | ||
// registered Hook this way to make sure SMW is loaded | ||
$wgHooks['SMW::SQLStore::AfterDataUpdateComplete'][] = 'SDU\Hooks::onAfterDataUpdateComplete'; | ||
} | ||
|
||
public static function onAfterDataUpdateComplete( SMWStore $store, SMWSemanticData $newData, | ||
$compositePropertyTableDiffIterator ) { | ||
global $wgSDUProperty; | ||
global $wgSDUTraversed; | ||
|
||
if ( !isset( $wgSDUTraversed ) ) { | ||
$wgSDUTraversed = []; | ||
} | ||
|
||
$wgSDUProperty = str_replace( ' ', '_', $wgSDUProperty ); | ||
$subject = $newData->getSubject(); | ||
$title = $subject->getTitle(); | ||
$id = $title->getPrefixedDBKey(); | ||
|
||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --> " . $title ); | ||
|
||
|
||
// FIRST CHECK: Does the page data contain a $wgSUTPropertyName semantic property ? | ||
$properties = $newData->getProperties(); | ||
$diffTable = $compositePropertyTableDiffIterator->getOrderedDiffByTable(); | ||
|
||
if ( !isset( $properties[$wgSDUProperty] ) ) { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] <-- No SDU property found" ); | ||
return true; | ||
} | ||
|
||
// SECOND CHECK: Have there been actual changes in the data? (Ignore internal SMW data!) | ||
// TODO: Introduce an explicit list of Semantic Properties to watch ? | ||
unset( $diffTable['smw_fpt_mdat'] ); // Ignore SMW's internal properties "smw_fpt_mdat" | ||
|
||
if ( count( $diffTable ) > 0 ) { | ||
// wfDebugLog('SemanticDependencyUpdater', "[SDU] diffTable: " . print_r($diffTable, true)); | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] -----> Data changes detected" ); | ||
} else { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] <-- No semantic data changes detected" ); | ||
return true; | ||
} | ||
|
||
|
||
// THIRD CHECK: Has this page been already traversed more than twice? | ||
// This should only be the case when SMW errors occur. | ||
// In that case, the diffTable contains everything and SDU can't know if changes happend | ||
if ( array_key_exists( $id, $wgSDUTraversed ) ) { | ||
$wgSDUTraversed[$id] = $wgSDUTraversed[$id] + 1; | ||
} else { | ||
$wgSDUTraversed[$id] = 1; | ||
} | ||
if ( $wgSDUTraversed[$id] > 2 ) { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] <-- Already traversed" ); | ||
return true; | ||
} | ||
|
||
|
||
// QUERY AND UPDATE DEPENDENCIES | ||
|
||
$dataItem = $newData->getPropertyValues( $properties[$wgSDUProperty] ); | ||
|
||
foreach ( $dataItem as $valueItem ) { | ||
Hooks::updatePagesMatchingQuery( $valueItem->getString() ); | ||
} | ||
|
||
return true; | ||
} | ||
/** | ||
* @param string $queryString Query string, excluding [[ and ]] brackets | ||
*/ | ||
private static function updatePagesMatchingQuery( $queryString ) { | ||
|
||
global $sfgListSeparator; | ||
|
||
$queryString = str_replace( 'AND', ']] [[', $queryString ); | ||
$queryString = str_replace( 'OR', ']] OR [[', $queryString ); | ||
|
||
// If SF is installed, get the separator character and change it into || | ||
// Otherwise SDU won't work with multi-value properties | ||
if ( isset( $sfgListSeparator ) ) { | ||
$queryString = rtrim( $queryString, $sfgListSeparator ); | ||
$queryString = str_replace( $sfgListSeparator, ' || ', $queryString ); | ||
} | ||
|
||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --------> [[$queryString]]" ); | ||
|
||
$store = smwfGetStore(); | ||
|
||
$params = [ | ||
'limit' => 10000, | ||
]; | ||
$processedParams = SMWQueryProcessor::getProcessedParams( $params ); | ||
$query = | ||
SMWQueryProcessor::createQuery( "[[$queryString]]", $processedParams, SMWQueryProcessor::SPECIAL_PAGE ); | ||
$result = $store->getQueryResult( $query ); // SMWQueryResult | ||
$wikiPageValues = $result->getResults(); // array of SMWWikiPageValues | ||
|
||
// TODO: This can be optimized by collecting a list of all pages first, make them unique | ||
// and do the dummy edit afterwards | ||
// TODO: A threshold when to switch to Queue Jobs might be smarter | ||
foreach ( $wikiPageValues as $page ) { | ||
Hooks::dummyEdit( $page->getTitle() ); | ||
} | ||
|
||
return; | ||
} | ||
|
||
/** | ||
* Save a null revision in the page's history to propagate the update | ||
* | ||
* @param Title $title | ||
*/ | ||
public static function dummyEdit( $title ) { | ||
global $wgSDUUseJobQueue; | ||
|
||
if ( $wgSDUUseJobQueue ) { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --------> [Edit Job] $title" ); | ||
$job = new DummyEditJob( $title ); | ||
$job->insert(); | ||
} else { | ||
wfDebugLog( 'SemanticDependencyUpdater', "[SDU] --------> [Edit] $title" ); | ||
$page = WikiPage::newFromID( $title->getArticleId() ); | ||
if ( $page ) { // prevent NPE when page not found | ||
$content = $page->getContent( Revision::RAW ); | ||
$text = ContentHandler::getContentText( $content ); | ||
$page->doEditContent( ContentHandler::makeContent( $text, $page->getTitle() ), | ||
"[SemanticDependencyUpdater] Null edit." ); // since this is a null edit, the edit summary will be ignored. | ||
$page->doPurge(); // required since SMW 2.5.1 | ||
} | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.