From 58125d15f7a888976edcf5d4d365a950a5fef8e3 Mon Sep 17 00:00:00 2001 From: Hereward Cooper Date: Tue, 7 Apr 2026 15:05:50 -0700 Subject: [PATCH] rewrite SemanticDependency --- webserver/html/ropewiki/LocalSettings.php | 4 +- .../extensions/SemanticDependency/README.md | 52 +++++++++ .../SemanticDependency/SemanticDependency.php | 100 ++--------------- .../SemanticDependency/extension.json | 39 +++++++ .../SemanticDependency/i18n/en.json | 8 ++ .../SemanticDependency/i18n/qqq.json | 8 ++ .../SemanticDependency/src/Hooks.php | 103 ++++++++++++++++++ 7 files changed, 224 insertions(+), 90 deletions(-) create mode 100644 webserver/html/ropewiki/extensions/SemanticDependency/README.md create mode 100644 webserver/html/ropewiki/extensions/SemanticDependency/extension.json create mode 100644 webserver/html/ropewiki/extensions/SemanticDependency/i18n/en.json create mode 100644 webserver/html/ropewiki/extensions/SemanticDependency/i18n/qqq.json create mode 100644 webserver/html/ropewiki/extensions/SemanticDependency/src/Hooks.php diff --git a/webserver/html/ropewiki/LocalSettings.php b/webserver/html/ropewiki/LocalSettings.php index a7da8ff..1b1edf0 100644 --- a/webserver/html/ropewiki/LocalSettings.php +++ b/webserver/html/ropewiki/LocalSettings.php @@ -252,7 +252,7 @@ $egMapsCoordinateDirectional = false; wfLoadExtension('Maps'); -require_once "$IP/extensions/SemanticDependency/SemanticDependency.php"; +wfLoadExtension('SemanticDependency'); # Rename edit tabs to "edit" and "edit source" $wgPageFormsRenameEditTabs = true; @@ -368,4 +368,4 @@ $isKnown = true; } return true; -}; +}; \ No newline at end of file diff --git a/webserver/html/ropewiki/extensions/SemanticDependency/README.md b/webserver/html/ropewiki/extensions/SemanticDependency/README.md new file mode 100644 index 0000000..e2caad0 --- /dev/null +++ b/webserver/html/ropewiki/extensions/SemanticDependency/README.md @@ -0,0 +1,52 @@ +# Semantic Dependency Extension + +Allows pages to specify that other pages should have their semantic data updated when the current page is saved. + +**Note: [Extension:SemanticDependencyUpdater](https://www.mediawiki.org/wiki/Extension:SemanticDependencyUpdater) seems to do the same job, and is probably worth checking out once the site is running an up to date mediawiki version** + + +## Usage + +In a template, use the parser function to declare a dependency: + +```mediawiki +{{#semanticdependent:PageName}} +``` + +When the page containing this parser function is saved, `PageName` will have its semantic data refreshed automatically. + +## Example + +In `Template:Condition`: +```mediawiki +{{#semanticdependent:{{{Location|}}}}} +``` + +When a condition report is saved, the canyon page (Location) will automatically update its semantic properties (like `Has condition date`). + +## Installation + +Add to `LocalSettings.php`: + +```php +wfLoadExtension( 'SemanticDependency' ); +``` + +## Configuration + +### Enable Logging + +```php +// Enable debug logging (disabled by default) +$wgSemanticDependencyEnableLogging = true; + +// Optional: Send logs to specific file +$wgDebugLogGroups['SemanticDependency'] = '/tmp/SemanticDependency.log'; +``` + +Logs are also written to the PHP error log with `[SemanticDependency]` prefix. + +## Requirements + +- MediaWiki 1.39+ +- Semantic MediaWiki 4+ \ No newline at end of file diff --git a/webserver/html/ropewiki/extensions/SemanticDependency/SemanticDependency.php b/webserver/html/ropewiki/extensions/SemanticDependency/SemanticDependency.php index 581377c..497dbce 100644 --- a/webserver/html/ropewiki/extensions/SemanticDependency/SemanticDependency.php +++ b/webserver/html/ropewiki/extensions/SemanticDependency/SemanticDependency.php @@ -1,91 +1,15 @@ __FILE__, - - // The name of the extension, which will appear on Special:Version. - 'name' => 'Semantic Dependency', - - // A description of the extension, which will appear on Special:Version. - 'description' => 'Allows pages to specify that other pages should have their semantic data updated in response to an update of the current page', - - // Alternatively, you can specify a message key for the description. - //'descriptionmsg' => 'exampleextension-desc', - - // The version of the extension, which will appear on Special:Version. - // This can be a number or a string. - 'version' => '0.1', - - // Your name, which will appear on Special:Version. - 'author' => 'Benjamin Pelletier', - - // The URL to a wiki page/web page with information about the extension, - // which will appear on Special:Version. - 'url' => 'http://ropewiki.com/', - -); -// Specify the function that will initialize the parser function. -$wgHooks['ParserFirstCallInit'][] = 'SemanticDependencySetupParserFunction'; - -// Hook the page save completion event as well -$wgHooks['PageContentSaveComplete'][] = 'SemanticDependencyPageContentSaveComplete'; - -// Allow translation of the parser function name -$wgExtensionMessagesFiles['SemanticDependency'] = dirname( __FILE__ ) . '/SemanticDependency.i18n.php'; - -// Tell MediaWiki that the parser function exists. -function SemanticDependencySetupParserFunction( &$parser ) { - - // Create a function hook associating the "semanticdependent" magic word with the - // SemanticDependencyParserFunction() function. See: the section - // 'setFunctionHook' below for details. - $parser->setFunctionHook( 'semanticdependent', 'SemanticDependencyRenderParserFunction' ); - - // Return true so that MediaWiki continues to load extensions. - return true; -} - -// Actually perform the refreshes after the page is saved -$sdpfPagesToRefresh = array(); -function SemanticDependencyPageContentSaveComplete( $article, $user, $content, $summary, $isMinor, $isWatch, $section, $flags, $revision, $status, $baseRevId ) { - global $sdpfPagesToRefresh; - foreach ($sdpfPagesToRefresh as $t) { - $updatejob = new SMWUpdateJob( $t ); - $updatejob->run(); - - //$refreshcmd = "php " . getcwd() . "/extensions/SemanticMediaWiki/maintenance/SMW_refreshData.php -s " . $t->getArticleID() . " -n 0"; - //exec($refreshcmd); - } - return true; -} - -// Render the output of the tag extension -function SemanticDependencyRenderParserFunction( $parser ) { - - // The input parameters are wikitext with templates expanded. - // The output should be wikitext too. - - if (func_num_args() == 0) - return SemanticDependency_usage(); - - $titletoupdate = Title::newFromText( func_get_arg(1) ); - - if ( is_null( $titletoupdate ) ) - return "
semanticdependent error: couldn't instantiate a Title
"; - if ( !$titletoupdate->exists() ) - return "
semanticdependent error: no page named " . func_get_arg(1) . "
"; - - global $sdpfPagesToRefresh; - $sdpfPagesToRefresh[] = $titletoupdate; - return ""; - //return "semanticdependent has " . count($sdpfPagesToRefresh) . " refreshes queued"; -} - -function SemanticDependency_usage() { - return "
semanticdependent usage error; expected: #semanticdependent:PageTitle
"; +if ( function_exists( 'wfLoadExtension' ) ) { + wfLoadExtension( 'SemanticDependency' ); + $wgMessagesDirs['SemanticDependency'] = __DIR__ . '/i18n'; + $wgExtensionMessagesFiles['SemanticDependencyMagic'] = __DIR__ . '/SemanticDependency.i18n.php'; + wfWarn( + 'Deprecated PHP entry point used for SemanticDependency extension. ' . + 'Please use wfLoadExtension instead, ' . + 'see https://www.mediawiki.org/wiki/Extension_registration for more details.' + ); + return; +} else { + die( 'This version of the SemanticDependency extension requires MediaWiki 1.25+' ); } diff --git a/webserver/html/ropewiki/extensions/SemanticDependency/extension.json b/webserver/html/ropewiki/extensions/SemanticDependency/extension.json new file mode 100644 index 0000000..71bfae2 --- /dev/null +++ b/webserver/html/ropewiki/extensions/SemanticDependency/extension.json @@ -0,0 +1,39 @@ +{ + "name": "Semantic Dependency", + "version": "2.0.0", + "author": [ + "Benjamin Pelletier" + ], + "url": "https://ropewiki.com/", + "descriptionmsg": "semanticdependency-desc", + "license-name": "GPL-2.0-or-later", + "type": "semantic", + "requires": { + "MediaWiki": ">= 1.39.0", + "extensions": { + "SemanticMediaWiki": "*" + } + }, + "MessagesDirs": { + "SemanticDependency": [ + "i18n" + ] + }, + "ExtensionMessagesFiles": { + "SemanticDependencyMagic": "SemanticDependency.i18n.php" + }, + "AutoloadNamespaces": { + "MediaWiki\\Extension\\SemanticDependency\\": "src/" + }, + "Hooks": { + "ParserFirstCallInit": "MediaWiki\\Extension\\SemanticDependency\\Hooks::onParserFirstCallInit", + "PageSaveComplete": "MediaWiki\\Extension\\SemanticDependency\\Hooks::onPageSaveComplete" + }, + "config": { + "SemanticDependencyEnableLogging": { + "value": false, + "description": "Enable debug logging for SemanticDependency operations" + } + }, + "manifest_version": 2 +} diff --git a/webserver/html/ropewiki/extensions/SemanticDependency/i18n/en.json b/webserver/html/ropewiki/extensions/SemanticDependency/i18n/en.json new file mode 100644 index 0000000..1e382e0 --- /dev/null +++ b/webserver/html/ropewiki/extensions/SemanticDependency/i18n/en.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Benjamin Pelletier" + ] + }, + "semanticdependency-desc": "Allows pages to specify that other pages should have their semantic data updated in response to an update of the current page" +} diff --git a/webserver/html/ropewiki/extensions/SemanticDependency/i18n/qqq.json b/webserver/html/ropewiki/extensions/SemanticDependency/i18n/qqq.json new file mode 100644 index 0000000..ee91e1d --- /dev/null +++ b/webserver/html/ropewiki/extensions/SemanticDependency/i18n/qqq.json @@ -0,0 +1,8 @@ +{ + "@metadata": { + "authors": [ + "Benjamin Pelletier" + ] + }, + "semanticdependency-desc": "{{desc|name=Semantic Dependency|url=https://ropewiki.com/}}" +} diff --git a/webserver/html/ropewiki/extensions/SemanticDependency/src/Hooks.php b/webserver/html/ropewiki/extensions/SemanticDependency/src/Hooks.php new file mode 100644 index 0000000..3a44086 --- /dev/null +++ b/webserver/html/ropewiki/extensions/SemanticDependency/src/Hooks.php @@ -0,0 +1,103 @@ +setFunctionHook( 'semanticdependent', [ self::class, 'renderParserFunction' ] ); + } + + public static function renderParserFunction( Parser $parser, string $pageName = '' ): string { + if ( $pageName === '' ) { + self::log( 'ERROR: #semanticdependent called with no arguments' ); + return '
Error: #semanticdependent requires a page name argument
'; + } + + $pageName = trim( $pageName ); + self::log( "Parser function called with page name: {$pageName}" ); + + $title = Title::newFromText( $pageName ); + + if ( $title === null ) { + self::log( "ERROR: Could not create Title object for: {$pageName}" ); + return '
Error: Invalid page title "' . htmlspecialchars( $pageName ) . '"
'; + } + + if ( !$title->exists() ) { + self::log( "WARNING: Page does not exist: {$pageName}" ); + } + + self::$pagesToRefresh[] = $title; + self::log( "Queued page for refresh: {$pageName} (total queued: " . count( self::$pagesToRefresh ) . ")" ); + + return ''; + } + + public static function onPageSaveComplete( + $wikiPage, + $user, + $summary, + $flags, + $revisionRecord, + $editResult + ): void { + $articleTitle = $wikiPage->getTitle()->getText(); + self::log( "PageSaveComplete hook called for page: {$articleTitle}" ); + self::log( "Number of pages queued for refresh: " . count( self::$pagesToRefresh ) ); + + if ( count( self::$pagesToRefresh ) === 0 ) { + self::log( "No pages to refresh, returning early" ); + return; + } + + foreach ( self::$pagesToRefresh as $title ) { + if ( !$title->exists() ) { + self::log( "Skipping non-existent page: " . $title->getText() ); + continue; + } + + $targetTitle = $title->getText(); + self::log( "Starting update job for dependent page: {$targetTitle}" ); + + try { + $updateJob = new SMWUpdateJob( $title ); + $result = $updateJob->run(); + + if ( $result ) { + self::log( "Successfully completed update job for: {$targetTitle}" ); + } else { + self::log( "WARNING: Update job returned false for: {$targetTitle}" ); + } + } catch ( \Exception $e ) { + self::log( "ERROR updating {$targetTitle}: " . $e->getMessage() ); + } + } + + self::log( "PageSaveComplete hook completed for: {$articleTitle}" ); + self::$pagesToRefresh = []; + } + + private static function log( string $message ): void { + $config = MediaWikiServices::getInstance()->getMainConfig(); + $loggingEnabled = $config->get( 'SemanticDependencyEnableLogging' ); + + if ( !$loggingEnabled ) { + return; + } + + wfDebugLog( 'SemanticDependency', $message ); + error_log( "[SemanticDependency] {$message}" ); + } +}