Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions webserver/html/ropewiki/LocalSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -368,4 +368,4 @@
$isKnown = true;
}
return true;
};
};
52 changes: 52 additions & 0 deletions webserver/html/ropewiki/extensions/SemanticDependency/README.md
Original file line number Diff line number Diff line change
@@ -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+
Original file line number Diff line number Diff line change
@@ -1,91 +1,15 @@
<?php

// Take credit for your work.
$wgExtensionCredits['media'][] = array(

// The full path and filename of the file. This allows MediaWiki
// to display the Subversion revision number on Special:Version.
'path' => __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 "<pre>semanticdependent error: couldn't instantiate a Title</pre>";
if ( !$titletoupdate->exists() )
return "<pre>semanticdependent error: no page named " . func_get_arg(1) . "</pre>";

global $sdpfPagesToRefresh;
$sdpfPagesToRefresh[] = $titletoupdate;
return "";
//return "semanticdependent has " . count($sdpfPagesToRefresh) . " refreshes queued";
}

function SemanticDependency_usage() {
return "<pre>semanticdependent usage error; expected: #semanticdependent:PageTitle</pre>";
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+' );
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"@metadata": {
"authors": [
"Benjamin Pelletier"
]
},
"semanticdependency-desc": "{{desc|name=Semantic Dependency|url=https://ropewiki.com/}}"
}
103 changes: 103 additions & 0 deletions webserver/html/ropewiki/extensions/SemanticDependency/src/Hooks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

namespace MediaWiki\Extension\SemanticDependency;

use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Storage\EditResult;
use MediaWiki\User\UserIdentity;
use Parser;
use SMWUpdateJob;
use Title;
use WikiPage;

class Hooks {

private static $pagesToRefresh = [];

public static function onParserFirstCallInit( Parser $parser ): void {
$parser->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 '<div class="error">Error: #semanticdependent requires a page name argument</div>';
}

$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 '<div class="error">Error: Invalid page title "' . htmlspecialchars( $pageName ) . '"</div>';
}

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}" );
}
}
Loading