r61002 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r61001‎ | r61002 | r61003 >
Date:06:54, 13 January 2010
Author:siebrand
Status:deferred
Tags:
Comment:
stylize.php and svn props.
Modified paths:
  • /trunk/extensions/SemanticNotifyMe/COPYING (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/INSTALL (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/README (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/RELEASE-NOTES (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/SMW_NMDBHelper.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/SMW_NMStorage.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/SMW_NotifyProcessor.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/SNM_Initialize.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/jobs/SMW_NMRefreshJob.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/jobs/SMW_NMSendMailJob.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/storage/SMW_NMStorageSQL.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/includes/storage/SMW_SQLStore2_QueriesNM.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/languages/SMW_NMLanguage.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/languages/SMW_NMLanguageEn.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMWNotifyMe.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMW_NMSendMailAsync.php (modified) (history)
  • /trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMW_NotAjaxAccess.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMW_NMSendMailAsync.php
@@ -1,67 +1,64 @@
2 -<?php
3 -/*
4 - * Created on 2009/3/25
5 - *
6 - * Author: Dch
7 - */
8 -
9 -
10 -//get Parameter
11 -$wgRequestTime = microtime(true);
12 -
13 -/** */
14 -# Abort if called from a web server
15 -if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) {
16 - print "This script must be run from the command line\n";
17 - exit();
18 -}
19 -
20 -
21 -if( version_compare( PHP_VERSION, '5.0.0' ) < 0 ) {
22 - print "Sorry! This version of MediaWiki requires PHP 5; you are running " .
23 - PHP_VERSION . ".\n\n" .
24 - "If you are sure you already have PHP 5 installed, it may be " .
25 - "installed\n" .
26 - "in a different path from PHP 4. Check with your system administrator.\n";
27 - die( -1 );
28 -}
29 -
30 -// copy from user class
31 -function getUserNMOption( $str ) {
32 - $options = array();
33 - $a = explode( "\n", $str );
34 - foreach ( $a as $s ) {
35 - $m = array();
36 - if ( preg_match( "/^(.[^=]*)=(.*)$/", $s, $m ) ) {
37 - $options[$m[1]] = $m[2];
38 - }
39 - }
40 - return $options['enotifyme'];
41 -}
42 -
43 -// include commandLine script which provides some basic
44 -// methodes for maintenance scripts
45 -$mediaWikiLocation = dirname(__FILE__) . '/../../../..';
46 -require_once "$mediaWikiLocation/maintenance/commandLine.inc";
47 -
48 -$sStore = smwfGetSemanticStore();
49 -$msgs = $sStore->getUnmailedNMMessages();
50 -foreach($msgs as $msg) {
51 - // send notifications by mail
52 - $user_info = $sStore->getUserInfo($msg['user_id']);
53 - if(($user_info->user_email != '') && getUserNMOption($user_info->user_options)) {
54 - $name = (($user_info->user_real_name=='')?$user_info->user_name:$user_info->user_real_name);
55 - $body = "Dear Mr./Mrs. $name,<br/>".$msg['notify'].
56 - "<br/><br/>Sincerely yours,<br/>SMW NotifyMe Bot";
57 -
58 - UserMailer::send( //userMailer(
59 - new MailAddress($user_info->user_email, $name),
60 - new MailAddress($wgEmergencyContact, 'Admin'),
61 - 'New SMW Notification comes, from '.$wgSitename,
62 - $body,
63 - new MailAddress($wgEmergencyContact, 'Admin'),
64 - true
65 - );
66 - }
67 -}
68 -?>
 2+<?php
 3+/*
 4+ * Created on 2009/3/25
 5+ *
 6+ * Author: Dch
 7+ */
 8+
 9+// get Parameter
 10+$wgRequestTime = microtime( true );
 11+
 12+/** */
 13+# Abort if called from a web server
 14+if ( isset( $_SERVER ) && array_key_exists( 'REQUEST_METHOD', $_SERVER ) ) {
 15+ print "This script must be run from the command line\n";
 16+ exit();
 17+}
 18+
 19+if ( version_compare( PHP_VERSION, '5.0.0' ) < 0 ) {
 20+ print "Sorry! This version of MediaWiki requires PHP 5; you are running " .
 21+ PHP_VERSION . ".\n\n" .
 22+ "If you are sure you already have PHP 5 installed, it may be " .
 23+ "installed\n" .
 24+ "in a different path from PHP 4. Check with your system administrator.\n";
 25+ die( - 1 );
 26+}
 27+
 28+// copy from user class
 29+function getUserNMOption( $str ) {
 30+ $options = array();
 31+ $a = explode( "\n", $str );
 32+ foreach ( $a as $s ) {
 33+ $m = array();
 34+ if ( preg_match( "/^(.[^=]*)=(.*)$/", $s, $m ) ) {
 35+ $options[$m[1]] = $m[2];
 36+ }
 37+ }
 38+ return $options['enotifyme'];
 39+}
 40+
 41+// include commandLine script which provides some basic
 42+// methodes for maintenance scripts
 43+$mediaWikiLocation = dirname( __FILE__ ) . '/../../../..';
 44+require_once "$mediaWikiLocation/maintenance/commandLine.inc";
 45+
 46+$sStore = smwfGetSemanticStore();
 47+$msgs = $sStore->getUnmailedNMMessages();
 48+foreach ( $msgs as $msg ) {
 49+ // send notifications by mail
 50+ $user_info = $sStore->getUserInfo( $msg['user_id'] );
 51+ if ( ( $user_info->user_email != '' ) && getUserNMOption( $user_info->user_options ) ) {
 52+ $name = ( ( $user_info->user_real_name == '' ) ? $user_info->user_name:$user_info->user_real_name );
 53+ $body = "Dear Mr./Mrs. $name,<br/>" . $msg['notify'] .
 54+ "<br/><br/>Sincerely yours,<br/>SMW NotifyMe Bot";
 55+
 56+ UserMailer::send( // userMailer(
 57+ new MailAddress( $user_info->user_email, $name ),
 58+ new MailAddress( $wgEmergencyContact, 'Admin' ),
 59+ 'New SMW Notification comes, from ' . $wgSitename,
 60+ $body,
 61+ new MailAddress( $wgEmergencyContact, 'Admin' ),
 62+ true
 63+ );
 64+ }
 65+}
Property changes on: trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMW_NMSendMailAsync.php
___________________________________________________________________
Name: svn:eol-style
6966 + native
Index: trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMW_NotAjaxAccess.php
@@ -1,111 +1,110 @@
2 -<?php
3 -
4 -global $wgAjaxExportList;
5 -global $smwgNMIP;
6 -
7 -require_once($smwgNMIP . '/includes/SMW_NotifyProcessor.php');
8 -$wgAjaxExportList[] = 'smwf_nm_NotifyAccess';
9 -
10 -
11 -function smwf_nm_NotifyAccess($method, $params) {
12 - $p_array = explode(",", $params);
13 - global $smwgQEnabled;
14 -
15 - $result="Query disabled.";
16 - if($method == "updateMail"){
17 - global $wgUser;
18 - $wgUser->setOption( 'enotifyme', $params );
19 - $wgUser->saveSettings();
20 - return 'Update NotifyMe mail setting successfully!';
21 - }
22 - else if($method == "addNotify"){
23 - if ($smwgQEnabled) {
24 - $result = SMWNotifyProcessor::addNotify(str_replace('&amp;', '&', str_replace('&comma;', ',', $p_array[0])),
25 - str_replace('&amp;', '&', str_replace('&comma;', ',', $p_array[3])),
26 - $p_array[1], $p_array[2], implode(",", array_slice($p_array, 4)));
27 - }
28 - return $result;
29 - }
30 - else if($method == "getQueryResult"){
31 - if ($smwgQEnabled) {
32 - $params .= '
33 -| format=table
34 -| link=all';
35 -
36 - // parse params and answer query
37 - SMWQueryProcessor::processFunctionParams(SMWNotifyProcessor::getQueryRawParams($params),$querystring,$params,$printouts);
38 -
39 - $result = SMWQueryProcessor::getResultFromQueryString($querystring,$params,$printouts, SMW_OUTPUT_WIKI);
40 - switch ($params->format) {
41 - case 'timeline':
42 - return $result;
43 - break;
44 - case 'eventline':
45 - return $result;
46 - break;
47 - case 'googlepie':
48 - return $result[0];
49 - break;
50 - case 'googlebar':
51 - return $result[0];
52 - break;
53 - case 'exhibit':
54 - return $result;
55 - break;
56 - default:
57 - }
58 - global $wgParser;
59 -
60 - if ( ($wgParser->getTitle() instanceof Title) && ($wgParser->getOptions() instanceof ParserOptions) ) {
61 - $result = $wgParser->recursiveTagParse($result);
62 - } else {
63 - global $wgTitle;
64 - $popt = new ParserOptions();
65 - $popt->setEditSection(false);
66 - $pout = $wgParser->parse($result . '__NOTOC__', $wgTitle, $popt);
67 - /// NOTE: as of MW 1.14SVN, there is apparently no better way to hide the TOC
68 - SMWOutputs::requireFromParserOutput($pout);
69 - $result = $pout->getText();
70 - }
71 -
72 - // add target="_new" for all links
73 - $pattern = "|<a|i";
74 - $result = preg_replace($pattern, '<a target="_new"', $result);
75 - }
76 - return $result;
77 - }
78 - else if($method == "updateStates"){
79 - if ($smwgQEnabled) {
80 - $result = SMWNotifyProcessor::updateStates($p_array);
81 - }
82 - return $result;
83 - }
84 - else if($method == "updateReportAll"){
85 - if ($smwgQEnabled) {
86 - $result = SMWNotifyProcessor::updateReportAll($p_array);
87 - }
88 - return $result;
89 - }
90 - else if($method == "updateShowAll"){
91 - if ($smwgQEnabled) {
92 - $result = SMWNotifyProcessor::updateShowAll($p_array);
93 - }
94 - return $result;
95 - }
96 - else if($method == "updateDelegates"){
97 - if ($smwgQEnabled) {
98 - $result = SMWNotifyProcessor::updateDelegates(explode("|", $params));
99 - }
100 - return $result;
101 - }
102 - else if($method == "delNotify"){
103 - if ($smwgQEnabled) {
104 - $result = SMWNotifyProcessor::delNotify($p_array);
105 - }
106 - return $result;
107 - }
108 - else {
109 - return "Operation failed, please retry later.";
110 - }
111 -}
112 -?>
\ No newline at end of file
 2+<?php
 3+
 4+global $wgAjaxExportList;
 5+global $smwgNMIP;
 6+
 7+require_once( $smwgNMIP . '/includes/SMW_NotifyProcessor.php' );
 8+$wgAjaxExportList[] = 'smwf_nm_NotifyAccess';
 9+
 10+
 11+function smwf_nm_NotifyAccess( $method, $params ) {
 12+ $p_array = explode( ",", $params );
 13+ global $smwgQEnabled;
 14+
 15+ $result = "Query disabled.";
 16+ if ( $method == "updateMail" ) {
 17+ global $wgUser;
 18+ $wgUser->setOption( 'enotifyme', $params );
 19+ $wgUser->saveSettings();
 20+ return 'Update NotifyMe mail setting successfully!';
 21+ }
 22+ else if ( $method == "addNotify" ) {
 23+ if ( $smwgQEnabled ) {
 24+ $result = SMWNotifyProcessor::addNotify( str_replace( '&amp;', '&', str_replace( '&comma;', ',', $p_array[0] ) ),
 25+ str_replace( '&amp;', '&', str_replace( '&comma;', ',', $p_array[3] ) ),
 26+ $p_array[1], $p_array[2], implode( ",", array_slice( $p_array, 4 ) ) );
 27+ }
 28+ return $result;
 29+ }
 30+ else if ( $method == "getQueryResult" ) {
 31+ if ( $smwgQEnabled ) {
 32+ $params .= '
 33+| format=table
 34+| link=all';
 35+
 36+ // parse params and answer query
 37+ SMWQueryProcessor::processFunctionParams( SMWNotifyProcessor::getQueryRawParams( $params ), $querystring, $params, $printouts );
 38+
 39+ $result = SMWQueryProcessor::getResultFromQueryString( $querystring, $params, $printouts, SMW_OUTPUT_WIKI );
 40+ switch ( $params->format ) {
 41+ case 'timeline':
 42+ return $result;
 43+ break;
 44+ case 'eventline':
 45+ return $result;
 46+ break;
 47+ case 'googlepie':
 48+ return $result[0];
 49+ break;
 50+ case 'googlebar':
 51+ return $result[0];
 52+ break;
 53+ case 'exhibit':
 54+ return $result;
 55+ break;
 56+ default:
 57+ }
 58+ global $wgParser;
 59+
 60+ if ( ( $wgParser->getTitle() instanceof Title ) && ( $wgParser->getOptions() instanceof ParserOptions ) ) {
 61+ $result = $wgParser->recursiveTagParse( $result );
 62+ } else {
 63+ global $wgTitle;
 64+ $popt = new ParserOptions();
 65+ $popt->setEditSection( false );
 66+ $pout = $wgParser->parse( $result . '__NOTOC__', $wgTitle, $popt );
 67+ // / NOTE: as of MW 1.14SVN, there is apparently no better way to hide the TOC
 68+ SMWOutputs::requireFromParserOutput( $pout );
 69+ $result = $pout->getText();
 70+ }
 71+
 72+ // add target="_new" for all links
 73+ $pattern = "|<a|i";
 74+ $result = preg_replace( $pattern, '<a target="_new"', $result );
 75+ }
 76+ return $result;
 77+ }
 78+ else if ( $method == "updateStates" ) {
 79+ if ( $smwgQEnabled ) {
 80+ $result = SMWNotifyProcessor::updateStates( $p_array );
 81+ }
 82+ return $result;
 83+ }
 84+ else if ( $method == "updateReportAll" ) {
 85+ if ( $smwgQEnabled ) {
 86+ $result = SMWNotifyProcessor::updateReportAll( $p_array );
 87+ }
 88+ return $result;
 89+ }
 90+ else if ( $method == "updateShowAll" ) {
 91+ if ( $smwgQEnabled ) {
 92+ $result = SMWNotifyProcessor::updateShowAll( $p_array );
 93+ }
 94+ return $result;
 95+ }
 96+ else if ( $method == "updateDelegates" ) {
 97+ if ( $smwgQEnabled ) {
 98+ $result = SMWNotifyProcessor::updateDelegates( explode( "|", $params ) );
 99+ }
 100+ return $result;
 101+ }
 102+ else if ( $method == "delNotify" ) {
 103+ if ( $smwgQEnabled ) {
 104+ $result = SMWNotifyProcessor::delNotify( $p_array );
 105+ }
 106+ return $result;
 107+ }
 108+ else {
 109+ return "Operation failed, please retry later.";
 110+ }
 111+}
Property changes on: trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMW_NotAjaxAccess.php
___________________________________________________________________
Name: svn:eol-style
113112 + native
Index: trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMWNotifyMe.php
@@ -1,406 +1,403 @@
2 -<?php
3 -
4 -if (!defined('MEDIAWIKI')) die();
5 -
6 -
7 -
8 -global $IP;
9 -require_once( $IP . "/includes/SpecialPage.php" );
10 -require_once( "SMW_NotAjaxAccess.php" );
11 -
12 -global $smwgNMIP;
13 -
14 -require_once($smwgNMIP . '/includes/SMW_NotifyProcessor.php');
15 -
16 -/*
17 - * Standard class that is resopnsible for the creation of the Special Page
18 - */
19 -class SMWNotifyMe extends SpecialPage {
20 - public function __construct() {
21 - parent::__construct('NotifyMe');
22 - }
23 -/*
24 - * Overloaded function that is responsible for the creation of the Special Page
25 - */
26 - public function execute() {
27 -
28 - global $wgRequest, $wgOut, $smwgNMScriptPath, $wgUser;
29 -
30 - # Get query parameters
31 - $feedFormat = $wgRequest->getVal( 'feed' );
32 - if($feedFormat=='rss') {
33 - # 10 seconds server-side caching max
34 - $wgOut->setSquidMaxage( 10 );
35 -
36 - global $smwgNMMaxFeedItems;
37 - $limit = ($smwgNMMaxFeedItems > 0) ? $smwgNMMaxFeedItems : 20;
38 -
39 - $dbr = wfGetDB( DB_SLAVE );
40 - $id = $wgRequest->getVal( 'uid' );
41 - $type = "uid";
42 - if($id) {
43 - # Get last modified date, for client caching
44 - # Don't use this if we are using the patrol feature, patrol changes don't update the timestamp
45 - $lastmod = $dbr->selectField( 'smw_nm_rss', 'MAX(timestamp)', array('user_id'=>$id), 'NotifyMeRSS' );
46 - } else {
47 - $type = "nid";
48 - $id = $wgRequest->getVal( 'nid' );
49 - $lastmod = $dbr->selectField( 'smw_nm_rss', 'MAX(timestamp)', array('notify_id'=>$id), 'NotifyMeRSS' );
50 - }
51 - if( $lastmod && $wgOut->checkLastModified( $lastmod ) ){
52 - # Client cache fresh and headers sent, nothing more to do.
53 - return;
54 - }
55 - $this->rcOutputFeed( $feedFormat, $type, $id, $limit, $lastmod, true );
56 - } else {
57 - $user_id = $wgUser->getId();
58 -
59 - $wgOut->setPageTitle(wfMsg('smw_notifyme'));
60 -
61 - if($user_id > 0) {
62 - $isSysop = in_array('sysop', $wgUser->getEffectiveGroups());
63 - if($isSysop) {
64 - SMWNotifyMe::addAutocomplete();
65 - }
66 -
67 - $imagepath = $smwgNMScriptPath . '/skins/images/';
68 -
69 - $html = '<div id="nmcontent">
70 - <div id="shade" style="display:none"></div>
71 - <div id="fullpreviewbox" style="display:none">
72 - <div id="fullpreview"></div>
73 - <span class="nmbutton" onclick="$(\'fullpreviewbox\', \'shade\').invoke(\'toggle\')"><img src="'. $imagepath. 'delete.png"/>Close Preview</span></div>
74 - <div id="nmlayout">
75 - <div id="querytitle" onclick="notifyhelper.switchquery()" onmouseover="Tip(\'' . wfMsg('smw_nm_tt_query') . '\')"><a id="querytitle-link" class="minusplus" href="javascript:void(0)"></a>Notify Me Query</div>
76 - <div id="querycontent">'.$this->getQueryLayout().'</div>
77 - <div id="layouttitle" onclick="notifyhelper.switchlayout()" onmouseover="Tip(\'' . wfMsg('smw_nm_tt_nmm') . '\')"><a id="layouttitle-link" class="minusplus" href="javascript:void(0)"></a>Notify Me Manager</div>
78 - <div id="layoutcontent">' . $this->getNotifyTable().'</div>
79 - </div>
80 - </div>';
81 -
82 - global $wgEmailAuthentication, $wgEnableEmail;
83 - if ($wgEnableEmail) {
84 - if ($wgEmailAuthentication && ($wgUser->getEmail() != '') ) {
85 - if( $wgUser->getEmailAuthenticationTimestamp() ) {
86 - $disableEmailPrefs = false;
87 - } else {
88 - $disableEmailPrefs = true;
89 - }
90 - } else {
91 - $disableEmailPrefs = false;
92 - }
93 - $eEmail = $wgUser->getOption( 'enotifyme' );
94 - $html .= '<div class="nmmenubar">
95 - <input id="nmemail" type="checkbox" value="1"'.($disableEmailPrefs?' disabled':'').($eEmail?' checked':'').'/> Enable \'Notify Me\' by E-mail ';
96 - if($disableEmailPrefs) {
97 - $href = htmlspecialchars( $wgUser->getSkin()->makeSpecialUrl( 'Preferences' ) );
98 - $text = htmlspecialchars( wfMsg( 'mypreferences' ) );
99 - $html .= " (Please enable your email account in '<a href=\"$href\">$text</a>'. )";
100 - }
101 - $html .= '</div>';
102 - }
103 -
104 - $html .= '<div>
105 - RSS Feed : <input id="nmrss" size="80" type="text" title="RSS feed url" value="'.$this->getTitle()->getFullURL( 'feed=rss&uid='.$user_id ).'" />&nbsp;&nbsp;
106 - <button class="btn" onclick="notifyhelper.copyToClipboard(\'nmrss\')" onmouseover="this.className=\'btn btnhov\'; Tip(\'' . wfMsg('smw_nm_tt_clipboard') . '\')" onmouseout="this.className=\'btn\'">' . wfMsg('smw_qi_clipboard') . '</button>
107 - </div>';
108 -
109 - $html .= '<script type="text/javascript" src="' . $smwgNMScriptPath . '/scripts/NotifyMe/nm_tooltip.js"></script>';
110 - } else {
111 - $html = '<div id="nmlayout">You have not logged in, please login first. Thanks.</div>';
112 - }
113 - $wgOut->addHTML($html);
114 - }
115 - }
116 - private function getQueryLayout() {
117 - global $wgUser;
118 - $isSysop = in_array('sysop', $wgUser->getEffectiveGroups());
119 -
120 - $html = '<table style="width: 100%;"><tr><td width=40%>
121 - <table width=100%>
122 - <tr><th width=40%>Name :</th><td width=60% onmouseover="Tip(\'Name of the notification\')"><input type="text" id="nmqname"></td></tr>
123 - <tr><th nowrap>Report all :</th><td onmouseover="Tip(\'Report all semantic semantic attribes\\\' change of monitored pages\')"><input type="checkbox" checked id="nmqrall"></td></tr>
124 - <tr><th nowrap>Show all :</th><td onmouseover="Tip(\'Show all query results with notifications\')"><input type="checkbox" id="nmqsall"></td></tr>';
125 - if($isSysop) {
126 - $html .= '<tr><th nowrap>Delegate to :</th><td><input type="text" id="nmd_new" size=35>
127 - <div class="page_name_auto_complete" id="nmdiv_new"></div></td>';
128 - }
129 - $html .= '</table></td><td width=60%><table style="width: 100%;">
130 - <tr><th onmouseover="Tip(\'' . wfMsg('smw_nm_tt_qtext') . '\')">Query (table format, all link only)</th></tr>
131 - <tr><td onmouseover="Tip(\'Full query string, with {{#ask syntax\')">
132 - {{#ask:<br/>
133 - <textarea id="nmquery" cols="20" rows="6"></textarea><br/>
134 - | format=table<br/>
135 - | link=all<br/>
136 - |}}
137 - </td></tr>
138 - </table>
139 - </td></tr></table>
140 - <div class="nmmenubar">
141 - <div style="text-align:left;float:left;">
142 - <button class="btn" onclick="notifyhelper.previewQuery()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Show full preview of your query results\')" onmouseout="this.className=\'btn\'">Preview Results</button>
143 - <button class="btn" onclick="notifyhelper.doSaveToNotify('.$isSysop.')" onmouseover="this.className=\'btn btnhov\'; Tip(\'Add this notification to you NotifyMe\')" onmouseout="this.className=\'btn\'">Add to NotifyMe</button>
144 - </div><div style="text-align:right;">
145 - <button class="btn" onclick="notifyhelper.resetQuery()"onmouseout="this.className=\'btn\'" onmouseover="this.className=\'btn btnhov\'; Tip(\'Resets the entire query\')">Reset Query</button>
146 - </div></div>';
147 -
148 - return $html;
149 - }
150 -
151 - static function addAutocomplete() {
152 - global $smwgNMDelegateQuery, $smwgNMDelegateUserGroup;
153 - if(!$smwgNMDelegateQuery && !$smwgNMDelegateUserGroup) return;
154 -
155 - global $wgOut, $smwgNMScriptPath;
156 - $nmScriptPath = $smwgNMScriptPath . '/specials/SMWNotifyMe';
157 - $nmYUIBase = "http://yui.yahooapis.com/2.7.0/build/";
158 -
159 - $wgOut->addLink( array(
160 - 'rel' => 'stylesheet',
161 - 'type' => 'text/css',
162 - 'media' => "screen, projection",
163 - 'href' => $nmScriptPath . '/skins/NM_yui_autocompletion.css'
164 - ));
165 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'yahoo/yahoo-min.js"></script>' . "\n");
166 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'dom/dom-min.js"></script>' . "\n");
167 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'event/event-min.js"></script>' . "\n");
168 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'get/get-min.js"></script>' . "\n");
169 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'connection/connection-min.js"></script>' . "\n");
170 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'json/json-min.js"></script>' . "\n");
171 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'datasource/datasource-min.js"></script>' . "\n");
172 - $wgOut->addScript('<script type="text/javascript" src="' . $nmYUIBase . 'autocomplete/autocomplete-min.js"></script>' . "\n");
173 - $wgOut->addScript('<script type="text/javascript" src="' . $nmScriptPath . '/libs/NM_yui_autocompletion.js"></script>' . "\n");
174 -
175 - $pages = array();
176 - if($smwgNMDelegateUserGroup) {
177 - if($smwgNMDelegateUserGroup != "*" && !is_array($smwgNMDelegateUserGroup)) {
178 - $groups = split(",", $smwgNMDelegateUserGroup);
179 - for($i = count($groups)-1; $i>=0; --$i) {
180 - $groups[$i] = strtolower(trim(str_replace("\'", "\\\'", $groups[$i])));
181 - }
182 - }
183 - $pages = NMStorage::getDatabase()->getGroupedUsers($groups);
184 - for($i = count($pages)-1; $i>=0; --$i) {
185 - $pages[$i] = "['".str_replace("\'", "\\\'", $pages[$i])."']";
186 - }
187 - }
188 - if($smwgNMDelegateQuery) {
189 - global $smwgQDefaultNamespaces, $smwgQFeatures;
190 - $qp = new SMWQueryParser($smwgQFeatures);
191 - $qp->setDefaultNamespaces($smwgQDefaultNamespaces);
192 - $desc = $qp->getQueryDescription($smwgNMDelegateQuery);
193 -
194 - $desc->prependPrintRequest(new SMWPrintRequest(SMWPrintRequest::PRINT_THIS, ""));
195 -
196 - $query = new SMWQuery($desc, true);
197 -
198 - $query_result = smwfGetStore()->getQueryResult($query);
199 - while ($res = $query_result->getNext()) {
200 - $pages[] = "['".str_replace("\'", "\\\'", $res[0]->getNextObject()->getWikiValue())."']";
201 - }
202 - }
203 - global $smwgNMMaxAutocompleteValues;
204 - if($smwgNMMaxAutocompleteValues <= 0) {
205 - $smwgNMMaxAutocompleteValues = 10;
206 - }
207 - $wgOut->addScript('<script type="text/javascript">
208 - nmautocompletestrings = ['.join(',', $pages).'];
209 - nmMaxResultsDisplayed = '.$smwgNMMaxAutocompleteValues.';
210 - </script>');
211 - }
212 - private function getNotifyTable() {
213 - global $wgUser;
214 - $isSysop = in_array('sysop', $wgUser->getEffectiveGroups());
215 -
216 - $cols = 6;
217 - $html = '<table width="100%" class="smwtable" id="nmtable">
218 - <tr><th width="5%" onmouseover="Tip(\'Select notifications to be deleted\')">Delete?</th>
219 - <th width="20%" onmouseover="Tip(\'Name of the notification\')">Name</th>
220 - <th width="40%" onmouseover="Tip(\'Full query string, with {{#ask syntax\')" nowrap>Query String</th>
221 - <th width="5%" onmouseover="Tip(\'Report all semantic semantic attribes\\\' change of monitored pages\')" nowrap>Report All</th>
222 - <th width="5%" onmouseover="Tip(\'Show all query results with notifications\')" nowrap>Show All</th>
223 - <th width="5%" onmouseover="Tip(\'Current state of notification. Enabled?\')">Enabled?</th>';
224 - if($isSysop) {
225 - $cols ++;
226 - $html .= '<th width="20%" onmouseover="Tip(\'Add delegate users to recieve NotifyMe, separated by comma\')">Delegate</th>';
227 - }
228 - $html .= '</tr>';
229 - $notifications = SMWNotifyProcessor::getNotifications();
230 - if ($notifications != null) {
231 - foreach ($notifications as $row) {
232 - $html .= '<tr>
233 - <td><input type="checkbox" name="nmdel" value='.$row['notify_id'].'></td>
234 - <td><a target="_blank" href="'.$this->getTitle()->getFullURL( 'feed=rss&nid='.$row['notify_id'] ).'">'.$row['name'].'</a></td>
235 - <td>'.str_replace("\n", "<br/>", $row['query']).'</td>
236 - <td><input type="checkbox" '.($row['rep_all']?'checked':'').' name="nmall" value='.$row['notify_id'].'></td>
237 - <td><input type="checkbox" '.($row['show_all']?'checked':'').' name="nmsall" value='.$row['notify_id'].'></td>
238 - <td><input type="checkbox" '.($row['enable']?'checked':'').' name="nmenable" id="nmenable_'.$row['notify_id'].'" value='.$row['notify_id'].'></td>';
239 - if($isSysop) {
240 - $html .= '<td><input type="text" name="nmdelegate" id=nmd_'.$row['notify_id'].' value="'.$row['delegate'].'">
241 - <div class="page_name_auto_complete" id="nmdiv_'.$row['notify_id'].'"></div></td>';
242 - }
243 - $html .= '</tr>';
244 - }
245 - }
246 - $html .= '<tr id="nmtoolbar">
247 - <td><a href="#" onclick="notifyhelper.delall(true)">ALL</a>/<a href="#" onclick="notifyhelper.delall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.deleteNotify()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Delete the checked notifications\')" onmouseout="this.className=\'btn\'">Update</button></td>
248 - <td></td><td></td>
249 - <td><a href="#" onclick="notifyhelper.reportall(true)">ALL</a>/<a href="#" onclick="notifyhelper.reportall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.updateReportAll()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Report all semantic attributes\\\' change on checked notifications\')" onmouseout="this.className=\'btn\'">Update</button></td>
250 - <td><a href="#" onclick="notifyhelper.showall(true)">ALL</a>/<a href="#" onclick="notifyhelper.showall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.updateShowAll()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Show all query results with notifications\')" onmouseout="this.className=\'btn\'">Update</button></td>
251 - <td><a href="#" onclick="notifyhelper.enableall(true)">ALL</a>/<a href="#" onclick="notifyhelper.enableall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.updateStates()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Update the states of your notifications, enable or disable them\')" onmouseout="this.className=\'btn\'">Update</button></td>';
252 - if($isSysop)
253 - $html .= '<td><button class="btn" onclick="notifyhelper.updateDelegate()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Update delegate\')" onmouseout="this.className=\'btn\'">Update</button></td>';
254 - $html .= '</tr></table>';
255 - return $html;
256 - }
257 -
258 - // rss feed related features
259 - function rcOutputFeed( $feedFormat, $type, $id, $limit, $lastmod, $queryresult_item = false) {
260 - global $messageMemc, $wgFeedCacheTimeout;
261 - global $wgFeedClasses, $wgTitle, $wgSitename, $wgContLanguageCode;
262 -
263 - if( !isset( $wgFeedClasses[$feedFormat] ) ) {
264 - wfHttpError( 500, "Internal Server Error", "Unsupported feed type." );
265 - return false;
266 - }
267 -
268 - $timekey = wfMemcKey( 'nmfeed', $feedFormat, $type, $id, 'timestamp' );
269 - $key = wfMemcKey( 'nmfeed', $feedFormat, $type, $id, 'limit', $limit );
270 -
271 - //purge cache if requested
272 - global $wgRequest, $wgUser;
273 - $purge = $wgRequest->getVal( 'action' ) == 'purge';
274 - if ( $purge && $wgUser->isAllowed('purge') ) {
275 - $messageMemc->delete( $timekey );
276 - $messageMemc->delete( $key );
277 - }
278 -
279 - /**
280 - * Bumping around loading up diffs can be pretty slow, so where
281 - * possible we want to cache the feed output so the next visitor
282 - * gets it quick too.
283 - */
284 - $cachedFeed = false;
285 - if( ( $wgFeedCacheTimeout > 0 ) && ( $feedLastmod = $messageMemc->get( $timekey ) ) ) {
286 - /**
287 - * If the cached feed was rendered very recently, we may
288 - * go ahead and use it even if there have been edits made
289 - * since it was rendered. This keeps a swarm of requests
290 - * from being too bad on a super-frequently edited wiki.
291 - */
292 - if( time() - wfTimestamp( TS_UNIX, $feedLastmod ) < $wgFeedCacheTimeout ||
293 - wfTimestamp( TS_UNIX, $feedLastmod ) > wfTimestamp( TS_UNIX, $lastmod ) ) {
294 - wfDebug( "RC: loading feed from cache ($key; $feedLastmod; $lastmod)...\n" );
295 - $cachedFeed = $messageMemc->get( $key );
296 - } else {
297 - wfDebug( "RC: cached feed timestamp check failed ($feedLastmod; $lastmod)\n" );
298 - }
299 - }
300 -
301 - $feedTitle = $wgSitename . ' - Recent changes to ';
302 - if($type = "nid") {
303 - $dbr = wfGetDB( DB_SLAVE );
304 - $notify_name = $dbr->selectField( 'smw_nm_query', 'name', array('notify_id'=>$id), 'NotifyMeRSS' );
305 - $feedTitle .= "\"$notify_name\"";
306 - } else {
307 - $feedTitle .= "Notify Me";
308 - }
309 - $feedTitle .= ' [' . $wgContLanguageCode . ']';
310 -
311 - $feed = new $wgFeedClasses[$feedFormat](
312 - $feedTitle,
313 - 'Track the most recent changes to '.($notify_name?"\"$notify_name\"":'Notify Me').' in this feed.',
314 - $wgTitle->getFullUrl() );
315 -
316 - if( is_string( $cachedFeed ) ) {
317 - wfDebug( "RC: Outputting cached feed\n" );
318 - $feed->httpHeaders();
319 - echo $cachedFeed;
320 - } else {
321 - wfDebug( "RC: rendering new feed and caching it\n" );
322 - ob_start();
323 - $this->rcDoOutputFeed( $feed, $queryresult_item, $type, $id, $limit );
324 - $cachedFeed = ob_get_contents();
325 - ob_end_flush();
326 -
327 - $expire = 3600 * 24; # One day
328 - $messageMemc->set( $key, $cachedFeed );
329 - $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire );
330 - }
331 - return true;
332 - }
333 -
334 - function rcDoOutputFeed( &$feed, $queryresult_item, $type, $id, $limit ) {
335 - wfProfileIn( __METHOD__ );
336 -
337 - $feed->outHeader();
338 -
339 - if($queryresult_item && $type=="nid") {
340 - $dbr = wfGetDB( DB_SLAVE );
341 - $showall = $dbr->selectField( 'smw_nm_query', 'show_all', array('notify_id'=>$id), 'NotifyMeRSS' );
342 - if($showall) {
343 - $query = $dbr->selectField( 'smw_nm_query', 'query', array('notify_id'=>$id), 'NotifyMeRSS' );
344 - SMWQueryProcessor::processFunctionParams(explode("\n", $query), $querystring, $params, $printouts);
345 - $query = SMWQueryProcessor::createQuery($querystring, $params, SMWQueryProcessor::INLINE_QUERY, 'auto', $printouts);
346 - $res = smwfGetStore()->getQueryResult($query);
347 -
348 - $items = array();
349 - $labels = array();
350 - foreach ($res->getPrintRequests() as $pr) {
351 - $labels[] = $pr->getText(SMW_OUTPUT_WIKI);
352 - }
353 - $row = $res->getNext();
354 - $linker = new Linker();
355 - while ( $row !== false ) {
356 - $wikipage = $row[0]->getNextObject(); // get the object
357 - $a = new Article($wikipage->getTitle());
358 - $description = "<table style=\"width: 60em; font-size: 90%; border: 1px solid #aaaaaa; background-color: #f9f9f9; color: black; margin-bottom: 0.5em; margin-left: 1em; padding: 0.2em; clear: right; text-align:left;\"><tr><th style=\"text-align: center; background-color:#ccccff;\" colspan=\"2\"><big>".$wikipage->getText()."</big></th></tr>";
359 - $idx = 0;
360 - foreach ($row as $field) {
361 - $description .= "<tr><td>".$labels[$idx]."</td><td>";
362 - $first_value = true;
363 - while ( ($object = $field->getNextObject()) !== false ) {
364 - if ($first_value) $first_value = false; else $description .= ', ';
365 - $description .= $object->getShortText(SMW_OUTPUT_HTML, $linker);
366 - }
367 - $description .= "</td></tr>";
368 - $idx ++;
369 - }
370 - $description .= "</table>";
371 - $items[] = array ('title'=>$wikipage->getText(),'notify'=>$description,'timestamp'=>$a->getTimestamp());
372 - $row = $res->getNext();
373 - }
374 - } else {
375 - $items = NMStorage::getDatabase()->getNotifyRSS($type, $id, $limit);
376 - }
377 - } else {
378 - $items = NMStorage::getDatabase()->getNotifyRSS($type, $id, $limit);
379 - }
380 - foreach( $items as $i ) {
381 - if(isset($i['link']) && $i['link']) {
382 - $item = new FeedItem(
383 - $i['title'],
384 - $i['notify'],
385 - $i['link'],
386 - $i['timestamp']
387 - );
388 - } else {
389 - $title = Title::makeTitle( NS_MAIN, $i['title'] );
390 - $talkpage = $title->getTalkPage();
391 - $item = new FeedItem(
392 - $title->getPrefixedText(),
393 - $i['notify'],
394 - $title->getFullURL(),
395 - $i['timestamp'],
396 - "",
397 - $talkpage->getFullURL()
398 - );
399 - }
400 - $feed->outItem( $item );
401 - }
402 -
403 - $feed->outFooter();
404 - wfProfileOut( __METHOD__ );
405 - }
406 -}
407 -?>
\ No newline at end of file
 2+<?php
 3+
 4+if ( !defined( 'MEDIAWIKI' ) ) die();
 5+
 6+global $IP;
 7+require_once( $IP . "/includes/SpecialPage.php" );
 8+require_once( "SMW_NotAjaxAccess.php" );
 9+
 10+global $smwgNMIP;
 11+
 12+require_once( $smwgNMIP . '/includes/SMW_NotifyProcessor.php' );
 13+
 14+/*
 15+ * Standard class that is resopnsible for the creation of the Special Page
 16+ */
 17+class SMWNotifyMe extends SpecialPage {
 18+ public function __construct() {
 19+ parent::__construct( 'NotifyMe' );
 20+ }
 21+/*
 22+ * Overloaded function that is responsible for the creation of the Special Page
 23+ */
 24+ public function execute() {
 25+
 26+ global $wgRequest, $wgOut, $smwgNMScriptPath, $wgUser;
 27+
 28+ # Get query parameters
 29+ $feedFormat = $wgRequest->getVal( 'feed' );
 30+ if ( $feedFormat == 'rss' ) {
 31+ # 10 seconds server-side caching max
 32+ $wgOut->setSquidMaxage( 10 );
 33+
 34+ global $smwgNMMaxFeedItems;
 35+ $limit = ( $smwgNMMaxFeedItems > 0 ) ? $smwgNMMaxFeedItems : 20;
 36+
 37+ $dbr = wfGetDB( DB_SLAVE );
 38+ $id = $wgRequest->getVal( 'uid' );
 39+ $type = "uid";
 40+ if ( $id ) {
 41+ # Get last modified date, for client caching
 42+ # Don't use this if we are using the patrol feature, patrol changes don't update the timestamp
 43+ $lastmod = $dbr->selectField( 'smw_nm_rss', 'MAX(timestamp)', array( 'user_id' => $id ), 'NotifyMeRSS' );
 44+ } else {
 45+ $type = "nid";
 46+ $id = $wgRequest->getVal( 'nid' );
 47+ $lastmod = $dbr->selectField( 'smw_nm_rss', 'MAX(timestamp)', array( 'notify_id' => $id ), 'NotifyMeRSS' );
 48+ }
 49+ if ( $lastmod && $wgOut->checkLastModified( $lastmod ) ) {
 50+ # Client cache fresh and headers sent, nothing more to do.
 51+ return;
 52+ }
 53+ $this->rcOutputFeed( $feedFormat, $type, $id, $limit, $lastmod, true );
 54+ } else {
 55+ $user_id = $wgUser->getId();
 56+
 57+ $wgOut->setPageTitle( wfMsg( 'smw_notifyme' ) );
 58+
 59+ if ( $user_id > 0 ) {
 60+ $isSysop = in_array( 'sysop', $wgUser->getEffectiveGroups() );
 61+ if ( $isSysop ) {
 62+ SMWNotifyMe::addAutocomplete();
 63+ }
 64+
 65+ $imagepath = $smwgNMScriptPath . '/skins/images/';
 66+
 67+ $html = '<div id="nmcontent">
 68+ <div id="shade" style="display:none"></div>
 69+ <div id="fullpreviewbox" style="display:none">
 70+ <div id="fullpreview"></div>
 71+ <span class="nmbutton" onclick="$(\'fullpreviewbox\', \'shade\').invoke(\'toggle\')"><img src="' . $imagepath . 'delete.png"/>Close Preview</span></div>
 72+ <div id="nmlayout">
 73+ <div id="querytitle" onclick="notifyhelper.switchquery()" onmouseover="Tip(\'' . wfMsg( 'smw_nm_tt_query' ) . '\')"><a id="querytitle-link" class="minusplus" href="javascript:void(0)"></a>Notify Me Query</div>
 74+ <div id="querycontent">' . $this->getQueryLayout() . '</div>
 75+ <div id="layouttitle" onclick="notifyhelper.switchlayout()" onmouseover="Tip(\'' . wfMsg( 'smw_nm_tt_nmm' ) . '\')"><a id="layouttitle-link" class="minusplus" href="javascript:void(0)"></a>Notify Me Manager</div>
 76+ <div id="layoutcontent">' . $this->getNotifyTable() . '</div>
 77+ </div>
 78+ </div>';
 79+
 80+ global $wgEmailAuthentication, $wgEnableEmail;
 81+ if ( $wgEnableEmail ) {
 82+ if ( $wgEmailAuthentication && ( $wgUser->getEmail() != '' ) ) {
 83+ if ( $wgUser->getEmailAuthenticationTimestamp() ) {
 84+ $disableEmailPrefs = false;
 85+ } else {
 86+ $disableEmailPrefs = true;
 87+ }
 88+ } else {
 89+ $disableEmailPrefs = false;
 90+ }
 91+ $eEmail = $wgUser->getOption( 'enotifyme' );
 92+ $html .= '<div class="nmmenubar">
 93+ <input id="nmemail" type="checkbox" value="1"' . ( $disableEmailPrefs ? ' disabled':'' ) . ( $eEmail ? ' checked':'' ) . '/> Enable \'Notify Me\' by E-mail ';
 94+ if ( $disableEmailPrefs ) {
 95+ $href = htmlspecialchars( $wgUser->getSkin()->makeSpecialUrl( 'Preferences' ) );
 96+ $text = htmlspecialchars( wfMsg( 'mypreferences' ) );
 97+ $html .= " (Please enable your email account in '<a href=\"$href\">$text</a>'. )";
 98+ }
 99+ $html .= '</div>';
 100+ }
 101+
 102+ $html .= '<div>
 103+ RSS Feed : <input id="nmrss" size="80" type="text" title="RSS feed url" value="' . $this->getTitle()->getFullURL( 'feed=rss&uid=' . $user_id ) . '" />&nbsp;&nbsp;
 104+ <button class="btn" onclick="notifyhelper.copyToClipboard(\'nmrss\')" onmouseover="this.className=\'btn btnhov\'; Tip(\'' . wfMsg( 'smw_nm_tt_clipboard' ) . '\')" onmouseout="this.className=\'btn\'">' . wfMsg( 'smw_qi_clipboard' ) . '</button>
 105+ </div>';
 106+
 107+ $html .= '<script type="text/javascript" src="' . $smwgNMScriptPath . '/scripts/NotifyMe/nm_tooltip.js"></script>';
 108+ } else {
 109+ $html = '<div id="nmlayout">You have not logged in, please login first. Thanks.</div>';
 110+ }
 111+ $wgOut->addHTML( $html );
 112+ }
 113+ }
 114+ private function getQueryLayout() {
 115+ global $wgUser;
 116+ $isSysop = in_array( 'sysop', $wgUser->getEffectiveGroups() );
 117+
 118+ $html = '<table style="width: 100%;"><tr><td width=40%>
 119+ <table width=100%>
 120+ <tr><th width=40%>Name :</th><td width=60% onmouseover="Tip(\'Name of the notification\')"><input type="text" id="nmqname"></td></tr>
 121+ <tr><th nowrap>Report all :</th><td onmouseover="Tip(\'Report all semantic semantic attribes\\\' change of monitored pages\')"><input type="checkbox" checked id="nmqrall"></td></tr>
 122+ <tr><th nowrap>Show all :</th><td onmouseover="Tip(\'Show all query results with notifications\')"><input type="checkbox" id="nmqsall"></td></tr>';
 123+ if ( $isSysop ) {
 124+ $html .= '<tr><th nowrap>Delegate to :</th><td><input type="text" id="nmd_new" size=35>
 125+ <div class="page_name_auto_complete" id="nmdiv_new"></div></td>';
 126+ }
 127+ $html .= '</table></td><td width=60%><table style="width: 100%;">
 128+ <tr><th onmouseover="Tip(\'' . wfMsg( 'smw_nm_tt_qtext' ) . '\')">Query (table format, all link only)</th></tr>
 129+ <tr><td onmouseover="Tip(\'Full query string, with {{#ask syntax\')">
 130+ {{#ask:<br/>
 131+ <textarea id="nmquery" cols="20" rows="6"></textarea><br/>
 132+ | format=table<br/>
 133+ | link=all<br/>
 134+ |}}
 135+ </td></tr>
 136+ </table>
 137+ </td></tr></table>
 138+ <div class="nmmenubar">
 139+ <div style="text-align:left;float:left;">
 140+ <button class="btn" onclick="notifyhelper.previewQuery()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Show full preview of your query results\')" onmouseout="this.className=\'btn\'">Preview Results</button>
 141+ <button class="btn" onclick="notifyhelper.doSaveToNotify(' . $isSysop . ')" onmouseover="this.className=\'btn btnhov\'; Tip(\'Add this notification to you NotifyMe\')" onmouseout="this.className=\'btn\'">Add to NotifyMe</button>
 142+ </div><div style="text-align:right;">
 143+ <button class="btn" onclick="notifyhelper.resetQuery()"onmouseout="this.className=\'btn\'" onmouseover="this.className=\'btn btnhov\'; Tip(\'Resets the entire query\')">Reset Query</button>
 144+ </div></div>';
 145+
 146+ return $html;
 147+ }
 148+
 149+ static function addAutocomplete() {
 150+ global $smwgNMDelegateQuery, $smwgNMDelegateUserGroup;
 151+ if ( !$smwgNMDelegateQuery && !$smwgNMDelegateUserGroup ) return;
 152+
 153+ global $wgOut, $smwgNMScriptPath;
 154+ $nmScriptPath = $smwgNMScriptPath . '/specials/SMWNotifyMe';
 155+ $nmYUIBase = "http://yui.yahooapis.com/2.7.0/build/";
 156+
 157+ $wgOut->addLink( array(
 158+ 'rel' => 'stylesheet',
 159+ 'type' => 'text/css',
 160+ 'media' => "screen, projection",
 161+ 'href' => $nmScriptPath . '/skins/NM_yui_autocompletion.css'
 162+ ) );
 163+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'yahoo/yahoo-min.js"></script>' . "\n" );
 164+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'dom/dom-min.js"></script>' . "\n" );
 165+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'event/event-min.js"></script>' . "\n" );
 166+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'get/get-min.js"></script>' . "\n" );
 167+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'connection/connection-min.js"></script>' . "\n" );
 168+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'json/json-min.js"></script>' . "\n" );
 169+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'datasource/datasource-min.js"></script>' . "\n" );
 170+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmYUIBase . 'autocomplete/autocomplete-min.js"></script>' . "\n" );
 171+ $wgOut->addScript( '<script type="text/javascript" src="' . $nmScriptPath . '/libs/NM_yui_autocompletion.js"></script>' . "\n" );
 172+
 173+ $pages = array();
 174+ if ( $smwgNMDelegateUserGroup ) {
 175+ if ( $smwgNMDelegateUserGroup != "*" && !is_array( $smwgNMDelegateUserGroup ) ) {
 176+ $groups = split( ",", $smwgNMDelegateUserGroup );
 177+ for ( $i = count( $groups ) - 1; $i >= 0; --$i ) {
 178+ $groups[$i] = strtolower( trim( str_replace( "\'", "\\\'", $groups[$i] ) ) );
 179+ }
 180+ }
 181+ $pages = NMStorage::getDatabase()->getGroupedUsers( $groups );
 182+ for ( $i = count( $pages ) - 1; $i >= 0; --$i ) {
 183+ $pages[$i] = "['" . str_replace( "\'", "\\\'", $pages[$i] ) . "']";
 184+ }
 185+ }
 186+ if ( $smwgNMDelegateQuery ) {
 187+ global $smwgQDefaultNamespaces, $smwgQFeatures;
 188+ $qp = new SMWQueryParser( $smwgQFeatures );
 189+ $qp->setDefaultNamespaces( $smwgQDefaultNamespaces );
 190+ $desc = $qp->getQueryDescription( $smwgNMDelegateQuery );
 191+
 192+ $desc->prependPrintRequest( new SMWPrintRequest( SMWPrintRequest::PRINT_THIS, "" ) );
 193+
 194+ $query = new SMWQuery( $desc, true );
 195+
 196+ $query_result = smwfGetStore()->getQueryResult( $query );
 197+ while ( $res = $query_result->getNext() ) {
 198+ $pages[] = "['" . str_replace( "\'", "\\\'", $res[0]->getNextObject()->getWikiValue() ) . "']";
 199+ }
 200+ }
 201+ global $smwgNMMaxAutocompleteValues;
 202+ if ( $smwgNMMaxAutocompleteValues <= 0 ) {
 203+ $smwgNMMaxAutocompleteValues = 10;
 204+ }
 205+ $wgOut->addScript( '<script type="text/javascript">
 206+ nmautocompletestrings = [' . join( ',', $pages ) . '];
 207+ nmMaxResultsDisplayed = ' . $smwgNMMaxAutocompleteValues . ';
 208+ </script>' );
 209+ }
 210+ private function getNotifyTable() {
 211+ global $wgUser;
 212+ $isSysop = in_array( 'sysop', $wgUser->getEffectiveGroups() );
 213+
 214+ $cols = 6;
 215+ $html = '<table width="100%" class="smwtable" id="nmtable">
 216+ <tr><th width="5%" onmouseover="Tip(\'Select notifications to be deleted\')">Delete?</th>
 217+ <th width="20%" onmouseover="Tip(\'Name of the notification\')">Name</th>
 218+ <th width="40%" onmouseover="Tip(\'Full query string, with {{#ask syntax\')" nowrap>Query String</th>
 219+ <th width="5%" onmouseover="Tip(\'Report all semantic semantic attribes\\\' change of monitored pages\')" nowrap>Report All</th>
 220+ <th width="5%" onmouseover="Tip(\'Show all query results with notifications\')" nowrap>Show All</th>
 221+ <th width="5%" onmouseover="Tip(\'Current state of notification. Enabled?\')">Enabled?</th>';
 222+ if ( $isSysop ) {
 223+ $cols ++;
 224+ $html .= '<th width="20%" onmouseover="Tip(\'Add delegate users to recieve NotifyMe, separated by comma\')">Delegate</th>';
 225+ }
 226+ $html .= '</tr>';
 227+ $notifications = SMWNotifyProcessor::getNotifications();
 228+ if ( $notifications != null ) {
 229+ foreach ( $notifications as $row ) {
 230+ $html .= '<tr>
 231+ <td><input type="checkbox" name="nmdel" value=' . $row['notify_id'] . '></td>
 232+ <td><a target="_blank" href="' . $this->getTitle()->getFullURL( 'feed=rss&nid=' . $row['notify_id'] ) . '">' . $row['name'] . '</a></td>
 233+ <td>' . str_replace( "\n", "<br/>", $row['query'] ) . '</td>
 234+ <td><input type="checkbox" ' . ( $row['rep_all'] ? 'checked':'' ) . ' name="nmall" value=' . $row['notify_id'] . '></td>
 235+ <td><input type="checkbox" ' . ( $row['show_all'] ? 'checked':'' ) . ' name="nmsall" value=' . $row['notify_id'] . '></td>
 236+ <td><input type="checkbox" ' . ( $row['enable'] ? 'checked':'' ) . ' name="nmenable" id="nmenable_' . $row['notify_id'] . '" value=' . $row['notify_id'] . '></td>';
 237+ if ( $isSysop ) {
 238+ $html .= '<td><input type="text" name="nmdelegate" id=nmd_' . $row['notify_id'] . ' value="' . $row['delegate'] . '">
 239+ <div class="page_name_auto_complete" id="nmdiv_' . $row['notify_id'] . '"></div></td>';
 240+ }
 241+ $html .= '</tr>';
 242+ }
 243+ }
 244+ $html .= '<tr id="nmtoolbar">
 245+ <td><a href="#" onclick="notifyhelper.delall(true)">ALL</a>/<a href="#" onclick="notifyhelper.delall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.deleteNotify()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Delete the checked notifications\')" onmouseout="this.className=\'btn\'">Update</button></td>
 246+ <td></td><td></td>
 247+ <td><a href="#" onclick="notifyhelper.reportall(true)">ALL</a>/<a href="#" onclick="notifyhelper.reportall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.updateReportAll()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Report all semantic attributes\\\' change on checked notifications\')" onmouseout="this.className=\'btn\'">Update</button></td>
 248+ <td><a href="#" onclick="notifyhelper.showall(true)">ALL</a>/<a href="#" onclick="notifyhelper.showall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.updateShowAll()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Show all query results with notifications\')" onmouseout="this.className=\'btn\'">Update</button></td>
 249+ <td><a href="#" onclick="notifyhelper.enableall(true)">ALL</a>/<a href="#" onclick="notifyhelper.enableall(false)">NONE</a>&nbsp; <button class="btn" onclick="notifyhelper.updateStates()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Update the states of your notifications, enable or disable them\')" onmouseout="this.className=\'btn\'">Update</button></td>';
 250+ if ( $isSysop )
 251+ $html .= '<td><button class="btn" onclick="notifyhelper.updateDelegate()" onmouseover="this.className=\'btn btnhov\'; Tip(\'Update delegate\')" onmouseout="this.className=\'btn\'">Update</button></td>';
 252+ $html .= '</tr></table>';
 253+ return $html;
 254+ }
 255+
 256+ // rss feed related features
 257+ function rcOutputFeed( $feedFormat, $type, $id, $limit, $lastmod, $queryresult_item = false ) {
 258+ global $messageMemc, $wgFeedCacheTimeout;
 259+ global $wgFeedClasses, $wgTitle, $wgSitename, $wgContLanguageCode;
 260+
 261+ if ( !isset( $wgFeedClasses[$feedFormat] ) ) {
 262+ wfHttpError( 500, "Internal Server Error", "Unsupported feed type." );
 263+ return false;
 264+ }
 265+
 266+ $timekey = wfMemcKey( 'nmfeed', $feedFormat, $type, $id, 'timestamp' );
 267+ $key = wfMemcKey( 'nmfeed', $feedFormat, $type, $id, 'limit', $limit );
 268+
 269+ // purge cache if requested
 270+ global $wgRequest, $wgUser;
 271+ $purge = $wgRequest->getVal( 'action' ) == 'purge';
 272+ if ( $purge && $wgUser->isAllowed( 'purge' ) ) {
 273+ $messageMemc->delete( $timekey );
 274+ $messageMemc->delete( $key );
 275+ }
 276+
 277+ /**
 278+ * Bumping around loading up diffs can be pretty slow, so where
 279+ * possible we want to cache the feed output so the next visitor
 280+ * gets it quick too.
 281+ */
 282+ $cachedFeed = false;
 283+ if ( ( $wgFeedCacheTimeout > 0 ) && ( $feedLastmod = $messageMemc->get( $timekey ) ) ) {
 284+ /**
 285+ * If the cached feed was rendered very recently, we may
 286+ * go ahead and use it even if there have been edits made
 287+ * since it was rendered. This keeps a swarm of requests
 288+ * from being too bad on a super-frequently edited wiki.
 289+ */
 290+ if ( time() - wfTimestamp( TS_UNIX, $feedLastmod ) < $wgFeedCacheTimeout ||
 291+ wfTimestamp( TS_UNIX, $feedLastmod ) > wfTimestamp( TS_UNIX, $lastmod ) ) {
 292+ wfDebug( "RC: loading feed from cache ($key; $feedLastmod; $lastmod)...\n" );
 293+ $cachedFeed = $messageMemc->get( $key );
 294+ } else {
 295+ wfDebug( "RC: cached feed timestamp check failed ($feedLastmod; $lastmod)\n" );
 296+ }
 297+ }
 298+
 299+ $feedTitle = $wgSitename . ' - Recent changes to ';
 300+ if ( $type = "nid" ) {
 301+ $dbr = wfGetDB( DB_SLAVE );
 302+ $notify_name = $dbr->selectField( 'smw_nm_query', 'name', array( 'notify_id' => $id ), 'NotifyMeRSS' );
 303+ $feedTitle .= "\"$notify_name\"";
 304+ } else {
 305+ $feedTitle .= "Notify Me";
 306+ }
 307+ $feedTitle .= ' [' . $wgContLanguageCode . ']';
 308+
 309+ $feed = new $wgFeedClasses[$feedFormat](
 310+ $feedTitle,
 311+ 'Track the most recent changes to ' . ( $notify_name ? "\"$notify_name\"":'Notify Me' ) . ' in this feed.',
 312+ $wgTitle->getFullUrl() );
 313+
 314+ if ( is_string( $cachedFeed ) ) {
 315+ wfDebug( "RC: Outputting cached feed\n" );
 316+ $feed->httpHeaders();
 317+ echo $cachedFeed;
 318+ } else {
 319+ wfDebug( "RC: rendering new feed and caching it\n" );
 320+ ob_start();
 321+ $this->rcDoOutputFeed( $feed, $queryresult_item, $type, $id, $limit );
 322+ $cachedFeed = ob_get_contents();
 323+ ob_end_flush();
 324+
 325+ $expire = 3600 * 24; # One day
 326+ $messageMemc->set( $key, $cachedFeed );
 327+ $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire );
 328+ }
 329+ return true;
 330+ }
 331+
 332+ function rcDoOutputFeed( &$feed, $queryresult_item, $type, $id, $limit ) {
 333+ wfProfileIn( __METHOD__ );
 334+
 335+ $feed->outHeader();
 336+
 337+ if ( $queryresult_item && $type == "nid" ) {
 338+ $dbr = wfGetDB( DB_SLAVE );
 339+ $showall = $dbr->selectField( 'smw_nm_query', 'show_all', array( 'notify_id' => $id ), 'NotifyMeRSS' );
 340+ if ( $showall ) {
 341+ $query = $dbr->selectField( 'smw_nm_query', 'query', array( 'notify_id' => $id ), 'NotifyMeRSS' );
 342+ SMWQueryProcessor::processFunctionParams( explode( "\n", $query ), $querystring, $params, $printouts );
 343+ $query = SMWQueryProcessor::createQuery( $querystring, $params, SMWQueryProcessor::INLINE_QUERY, 'auto', $printouts );
 344+ $res = smwfGetStore()->getQueryResult( $query );
 345+
 346+ $items = array();
 347+ $labels = array();
 348+ foreach ( $res->getPrintRequests() as $pr ) {
 349+ $labels[] = $pr->getText( SMW_OUTPUT_WIKI );
 350+ }
 351+ $row = $res->getNext();
 352+ $linker = new Linker();
 353+ while ( $row !== false ) {
 354+ $wikipage = $row[0]->getNextObject(); // get the object
 355+ $a = new Article( $wikipage->getTitle() );
 356+ $description = "<table style=\"width: 60em; font-size: 90%; border: 1px solid #aaaaaa; background-color: #f9f9f9; color: black; margin-bottom: 0.5em; margin-left: 1em; padding: 0.2em; clear: right; text-align:left;\"><tr><th style=\"text-align: center; background-color:#ccccff;\" colspan=\"2\"><big>" . $wikipage->getText() . "</big></th></tr>";
 357+ $idx = 0;
 358+ foreach ( $row as $field ) {
 359+ $description .= "<tr><td>" . $labels[$idx] . "</td><td>";
 360+ $first_value = true;
 361+ while ( ( $object = $field->getNextObject() ) !== false ) {
 362+ if ( $first_value ) $first_value = false; else $description .= ', ';
 363+ $description .= $object->getShortText( SMW_OUTPUT_HTML, $linker );
 364+ }
 365+ $description .= "</td></tr>";
 366+ $idx ++;
 367+ }
 368+ $description .= "</table>";
 369+ $items[] = array ( 'title' => $wikipage->getText(), 'notify' => $description, 'timestamp' => $a->getTimestamp() );
 370+ $row = $res->getNext();
 371+ }
 372+ } else {
 373+ $items = NMStorage::getDatabase()->getNotifyRSS( $type, $id, $limit );
 374+ }
 375+ } else {
 376+ $items = NMStorage::getDatabase()->getNotifyRSS( $type, $id, $limit );
 377+ }
 378+ foreach ( $items as $i ) {
 379+ if ( isset( $i['link'] ) && $i['link'] ) {
 380+ $item = new FeedItem(
 381+ $i['title'],
 382+ $i['notify'],
 383+ $i['link'],
 384+ $i['timestamp']
 385+ );
 386+ } else {
 387+ $title = Title::makeTitle( NS_MAIN, $i['title'] );
 388+ $talkpage = $title->getTalkPage();
 389+ $item = new FeedItem(
 390+ $title->getPrefixedText(),
 391+ $i['notify'],
 392+ $title->getFullURL(),
 393+ $i['timestamp'],
 394+ "",
 395+ $talkpage->getFullURL()
 396+ );
 397+ }
 398+ $feed->outItem( $item );
 399+ }
 400+
 401+ $feed->outFooter();
 402+ wfProfileOut( __METHOD__ );
 403+ }
 404+}
Property changes on: trunk/extensions/SemanticNotifyMe/specials/SMWNotifyMe/SMWNotifyMe.php
___________________________________________________________________
Name: svn:eol-style
408405 + native
Index: trunk/extensions/SemanticNotifyMe/INSTALL
@@ -1,18 +1,18 @@
2 -== Requirements ==
3 -
4 -* MediaWiki 1.13.5
5 -* Semantic MediaWiki 1.4.2
6 -* PHP 5.x or greater installed and working
7 -* MySQL >= 4.0.14 (version required by MediaWiki)
8 -* Halo extension 1.4.4 (optional)
9 -
10 -== Installation ==
11 -
12 -Edit $IP/LocalSettings.php and add:
13 -
14 - include_once('extensions/SemanticNotifyMe/includes/SNM_Initialize.php');
15 -
16 -Apply this patch, $IP/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php
17 -line 1268, add the following
18 - $title = Title::makeTitle(NS_SPECIAL, 'SMWNotifyMe');
19 - $updatejobs[] = new SMWNMRefreshJob($title);
 2+== Requirements ==
 3+
 4+* MediaWiki 1.13.5
 5+* Semantic MediaWiki 1.4.2
 6+* PHP 5.x or greater installed and working
 7+* MySQL >= 4.0.14 (version required by MediaWiki)
 8+* Halo extension 1.4.4 (optional)
 9+
 10+== Installation ==
 11+
 12+Edit $IP/LocalSettings.php and add:
 13+
 14+ include_once('extensions/SemanticNotifyMe/includes/SNM_Initialize.php');
 15+
 16+Apply this patch, $IP/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php
 17+line 1268, add the following
 18+ $title = Title::makeTitle(NS_SPECIAL, 'SMWNotifyMe');
 19+ $updatejobs[] = new SMWNMRefreshJob($title);
Property changes on: trunk/extensions/SemanticNotifyMe/INSTALL
___________________________________________________________________
Name: svn:eol-style
2020 + native
Index: trunk/extensions/SemanticNotifyMe/RELEASE-NOTES
@@ -1,9 +1,9 @@
2 -For a documentation of all features, see http://www.mediawiki.org/wiki/Extension:Semantic_NotifyMe
3 -
4 -== Semantic NotifyMe 0.5 ==
5 -
6 -This is a pre-alpha version of the Semantic NotifyMe extensions.
7 -It includes:
8 -
9 -* support for realtime notification on Semantic property/value changing
10 -* Special:NotifyMe, manage all NotifyMe notifications, delegation enabled
 2+For a documentation of all features, see http://www.mediawiki.org/wiki/Extension:Semantic_NotifyMe
 3+
 4+== Semantic NotifyMe 0.5 ==
 5+
 6+This is a pre-alpha version of the Semantic NotifyMe extensions.
 7+It includes:
 8+
 9+* support for realtime notification on Semantic property/value changing
 10+* Special:NotifyMe, manage all NotifyMe notifications, delegation enabled
Property changes on: trunk/extensions/SemanticNotifyMe/RELEASE-NOTES
___________________________________________________________________
Name: svn:eol-style
1111 + native
Index: trunk/extensions/SemanticNotifyMe/includes/SMW_NotifyProcessor.php
@@ -1,1655 +1,1655 @@
2 -<?php
3 -/**
4 - * This file contains a static class for accessing functions to generate and execute
5 - * notify me semantic queries and to serialise their results.
6 - *
7 - * @author dch
8 - */
9 -
10 -global $smwgIP, $smwgNMIP ;
11 -require_once($smwgIP . '/includes/storage/SMW_Store.php');
12 -require_once( $smwgNMIP . '/includes/SMW_NMStorage.php' );
13 -
14 -/**
15 - * Static class for accessing functions to generate and execute semantic queries
16 - * and to serialise their results.
17 - */
18 -class SMWNotifyProcessor {
19 -
20 - static public function getNotifications() {
21 - $sStore = NMStorage::getDatabase();
22 - global $wgUser;
23 - $user_id = $wgUser->getId();
24 -
25 - $notifications = $sStore->getNotifications($user_id);
26 -
27 - return $notifications;
28 - }
29 -
30 - /**
31 - * Enable a NotifyMe with specified id and querystring
32 - *
33 - * used for inline query only
34 - */
35 - static public function enableNotify($notify_id, $querystring, &$msg = NULL) {
36 - wfProfileIn('SMWNotifyProcessor::enableNotify (SMW)');
37 -
38 - $sStore = NMStorage::getDatabase();
39 - global $smwgQDefaultNamespaces;
40 -
41 - SMWQueryProcessor::processFunctionParams(SMWNotifyProcessor::getQueryRawParams($querystring),$querystring,$params,$printouts);
42 - $relatedArticles = array();
43 - foreach($printouts as $po) {
44 - if($po == $params['sort']) $sorted = true;
45 - $printoutArticles[] = array(
46 - 'namespace' => SMW_NS_PROPERTY,
47 - 'title' => Title::makeTitle( SMW_NS_PROPERTY, $po->getText() )->getDBkey());
48 - }
49 - if(!$sorted && isset($params['sort'])) {
50 - $printoutArticles[] = array(
51 - 'namespace' => SMW_NS_PROPERTY,
52 - 'title' => Title::makeTitle( SMW_NS_PROPERTY, $params['sort'] )->getDBkey());
53 - }
54 -
55 - $qp = new SMWNotifyParser($notify_id, $printoutArticles);
56 - $qp->setDefaultNamespaces($smwgQDefaultNamespaces);
57 - $desc = $qp->getQueryDescription($querystring);
58 -
59 - if(!$qp->m_result) {
60 - $qp->m_errors[] = "The category / instance / property page in query may not exists.";
61 - }
62 -
63 - if(isset($msg) && $qp->hasSubquery()) {
64 - $msg .= "\nThe query contains subquery, which may affect the precision of notifications.";
65 - }
66 -
67 - $query = new SMWQuery($desc, true, false);
68 - $query->setQueryString($querystring);
69 - $query->addErrors($qp->getErrors()); // keep parsing errors for later output
70 -
71 - $res = $sStore->getNMQueryResult($query);
72 -
73 - if(count($query->getErrors())>0) {
74 - if(isset($msg)) {
75 - $msg .= "\n\n" . implode('\n', $query->getErrors()) . "\n\nYou can enable the query in NotifyMe manager later.";
76 - }
77 - $sStore->disableNotifyState($notify_id);
78 - wfProfileOut('SMWNotifyProcessor::enableNotify (SMW)');
79 - return false;
80 - }
81 -
82 - $sStore->updateNMSql($notify_id, $res['sql'], $res['tmp_hierarchy']);
83 - if (count($res['page_ids']) > 0) {
84 - $add_monitor = array();
85 - foreach($res['page_ids'] as $page_id) {
86 - $add_monitor[] = array('notify_id'=>$notify_id, 'page_id'=>$page_id);
87 - }
88 - $sStore->addNotifyMonitor($add_monitor);
89 - }
90 - $sStore->updateNotifyState($notify_id, 1);
91 - wfProfileOut('SMWNotifyProcessor::enableNotify (SMW)');
92 -
93 - return true;
94 - }
95 -
96 - static public function getQueryRawParams($querystring){
97 - // read query with printouts and (possibly) other parameters like sort, order, limit, etc...
98 - $pos = strpos($querystring, "|?");
99 - if ($pos > 0) {
100 - $rawparams[] = trim(substr($querystring, 0, $pos));
101 - $ps = explode("|?", trim(substr($querystring, $pos+2)));
102 - foreach ($ps as $param) {
103 - $rawparams[] = "?" . trim($param);
104 - }
105 - } else {
106 - $ps = preg_split('/[^\|]{1}\|{1}(?!\|)/s', $querystring);
107 - if (count($ps) > 1) {
108 - // last char of query condition is missing (matched with [^\|]{1}) therefore copy from original
109 - $rawparams[] = trim(substr($querystring, 0, strlen($ps[0]) + 1));
110 - array_shift($ps); // remove the query condition
111 - // add other params for formating etc.
112 - foreach ($ps as $param)
113 - $rawparams[] = trim($param);
114 - } // no single pipe found, no params specified in query
115 - else $rawparams[] = trim($querystring);
116 - }
117 - $rawparams[] = "format=table";
118 - $rawparams[] = "link=all";
119 - return $rawparams;
120 - }
121 -
122 - static public function addNotify($rawquery, $name, $rep_all, $show_all, $delegate) {
123 - global $wgTitle;
124 - // Take care at least of some templates -- for better template support use #ask
125 - $parser = new Parser();
126 - $parserOptions = new ParserOptions();
127 - $parser->startExternalParse( $wgTitle, $parserOptions, OT_HTML );
128 - $rawquery = $parser->transformMsg( $rawquery, $parserOptions );
129 -
130 - wfProfileIn('SMWNotifyProcessor::createNotify (SMW)');
131 - $sStore = NMStorage::getDatabase();
132 - global $wgUser;
133 - $user_id = $wgUser->getId();
134 - if($user_id == 0) {
135 - wfProfileOut('SMWNotifyProcessor::createNotify (SMW)');
136 - return "You have not logged in yet, please log in and retry again. Thanks.";
137 - }
138 -
139 - // check notify query first, use QueryParser from SMW
140 - SMWQueryProcessor::processFunctionParams(SMWNotifyProcessor::getQueryRawParams($rawquery),$querystring,$params,$printouts);
141 -
142 - $qp = new SMWQueryParser();
143 - $qp->setDefaultNamespaces($smwgQDefaultNamespaces);
144 - $desc = $qp->getQueryDescription($querystring);
145 -
146 - if(count($qp->getErrors())>0) {
147 - wfProfileOut('SMWNotifyProcessor::createNotify (SMW)');
148 - return "Notify create failed!\n\n" . implode('\n', $qp->getErrors()) . "\n\nPlease check the query and retry again";
149 - }
150 -
151 - $notify_id = $sStore->addNotifyQuery($user_id, $rawquery, $name, $rep_all, $show_all, $delegate);
152 - if($notify_id == 0) {
153 - wfProfileOut('SMWNotifyProcessor::createNotify (SMW)');
154 - return "Fail to save query. Please retry later...";
155 - }
156 - wfProfileOut('SMWNotifyProcessor::createNotify (SMW)');
157 -
158 - wfProfileIn('SMWNotifyProcessor::enableNotify (SMW)');
159 - $msg = '';
160 - $result = SMWNotifyProcessor::enableNotify($notify_id, $rawquery, $msg);
161 - wfProfileOut('SMWNotifyProcessor::enableNotify (SMW)');
162 - return "1".($result?"1":"0")."$notify_id,$msg";
163 - }
164 -
165 - static public function updateStates($notify_ids) {
166 - wfProfileIn('SMWNotifyProcessor::updateStates (SMW)');
167 -
168 - $notifications = SMWNotifyProcessor::getNotifications();
169 - if ($notifications == null || !is_array($notifications)) {
170 - return "No notifications available.";
171 - }
172 - $result = true;
173 - $idx = 0;
174 - $count = count($notify_ids) - 1;
175 - $msg = '';
176 - $errs = '';
177 - $sStore = NMStorage::getDatabase();
178 - foreach ($notifications as $row) {
179 - if(($idx<$count) && ($notify_ids[$idx]==$row['notify_id'])) {
180 - if($row['enable']==0) {
181 - $m = '';
182 - $r = SMWNotifyProcessor::enableNotify($row['notify_id'], $row['query'], $m);
183 - if(!$r) {
184 - $msg .= "NotifyMe : '" . $row['name'] . "'$m\n\n";
185 - $errs .= $row['notify_id'] . ",";
186 - $result = false;
187 - }
188 - }
189 - $idx ++;
190 - } else {
191 - if($row['enable']==1) {
192 - $result = $sStore->disableNotifyState($row['notify_id']);
193 - }
194 - }
195 - }
196 -
197 - wfProfileOut('SMWNotifyProcessor::updateStates (SMW)');
198 - return $result ? "States updated successfully!" : "0$errs|\n\n$msg";
199 - }
200 -
201 - static public function updateDelegates($delegates) {
202 - wfProfileIn('SMWNotifyProcessor::updateDelegates (SMW)');
203 -
204 - $notifications = SMWNotifyProcessor::getNotifications();
205 - if ($notifications == null || !is_array($notifications)) {
206 - return "No notifications available.";
207 - }
208 - $result = true;
209 - $idx = 0;
210 - $s = explode(':', $delegates[$idx], 2);
211 - $count = count($delegates) - 1;
212 - $sStore = NMStorage::getDatabase();
213 - foreach ($notifications as $row) {
214 - if(($idx<$count) && ($s[0]==$row['notify_id'])) {
215 - $result = $sStore->updateDelegate($row['notify_id'], $s[1]);
216 - $idx ++;
217 - $s = explode(':', $delegates[$idx], 2);
218 - } else {
219 - $result = $sStore->updateDelegate($row['notify_id'], '');
220 - }
221 - if(!$result) break;
222 - }
223 -
224 - wfProfileOut('SMWNotifyProcessor::updateDelegates (SMW)');
225 - return $result ? "Delegates updated successfully!" : "Delegates updated error!";
226 - }
227 -
228 - static public function refreshNotifyMe() {
229 - wfProfileIn('SMWNotifyProcessor::refreshNotifyMe (SMW)');
230 - $notifications = NMStorage::getDatabase()->getAllNotifications();
231 - foreach ($notifications as $row) {
232 - if($row['enable']) {
233 - $result = SMWNotifyProcessor::enableNotify($row['notify_id'], $row['query']);
234 - }
235 - }
236 - wfProfileOut('SMWNotifyProcessor::refreshNotifyMe (SMW)');
237 - }
238 -
239 - static public function updateReportAll($notify_ids) {
240 - wfProfileIn('SMWNotifyProcessor::updateStates (SMW)');
241 -
242 - $notifications = SMWNotifyProcessor::getNotifications();
243 - if ($notifications == null || !is_array($notifications)) {
244 - return "No notifications available.";
245 - }
246 - $result = true;
247 - $idx = 0;
248 - $count = count($notify_ids) - 1;
249 - $sStore = NMStorage::getDatabase();
250 - foreach ($notifications as $row) {
251 - if(($idx<$count) && ($notify_ids[$idx]==$row['notify_id'])) {
252 - if($row['rep_all']==0) {
253 - $result = $sStore->updateNotifyReportAll($row['notify_id'], 1);
254 - }
255 - $idx ++;
256 - } else {
257 - if($row['rep_all']==1) {
258 - $result = $sStore->updateNotifyReportAll($row['notify_id'], 0);
259 - }
260 - }
261 - if(!$result) break;
262 - }
263 -
264 - wfProfileOut('SMWNotifyProcessor::updateStates (SMW)');
265 - return $result ? "States updated successfully!" : "States updated error!";
266 - }
267 -
268 - static public function updateShowAll($notify_ids) {
269 - wfProfileIn('SMWNotifyProcessor::updateStates (SMW)');
270 -
271 - $notifications = SMWNotifyProcessor::getNotifications();
272 - if ($notifications == null || !is_array($notifications)) {
273 - return "No notifications available.";
274 - }
275 - $result = true;
276 - $idx = 0;
277 - $count = count($notify_ids) - 1;
278 - $sStore = NMStorage::getDatabase();
279 - foreach ($notifications as $row) {
280 - if(($idx<$count) && ($notify_ids[$idx]==$row['notify_id'])) {
281 - if($row['show_all']==0) {
282 - $result = $sStore->updateNotifyShowAll($row['notify_id'], 1);
283 - }
284 - $idx ++;
285 - } else {
286 - if($row['show_all']==1) {
287 - $result = $sStore->updateNotifyShowAll($row['notify_id'], 0);
288 - }
289 - }
290 - if(!$result) break;
291 - }
292 -
293 - wfProfileOut('SMWNotifyProcessor::updateStates (SMW)');
294 - return $result ? "States updated successfully!" : "States updated error!";
295 - }
296 -
297 - static public function delNotify($notify_ids) {
298 - wfProfileIn('SMWNotifyProcessor::delNotify (SMW)');
299 - $sStore = NMStorage::getDatabase();
300 - $result = $sStore->removeNotifyQuery($notify_ids);
301 - wfProfileOut('SMWNotifyProcessor::delNotify (SMW)');
302 - return $result ? "Notification(s) deleted successfully!" : "Notification(s) deleted error!";
303 - }
304 -
305 - static protected $notifyJobs = array();
306 - static public function prepareArticleSave($title) {
307 - $page_id = $title->getArticleID();
308 - if($page_id == 0) {
309 - return;
310 - }
311 - $updates = SMWNotifyProcessor::$notifyJobs[$page_id];
312 - if(empty($updates)) {
313 - SMWNotifyProcessor::$notifyJobs[$page_id] = new SMWNotifyUpdate($title);
314 - }
315 - }
316 - static public function articleSavedComplete($title) {
317 - $page_id = $title->getArticleID();
318 - if($page_id == 0) {
319 - return;
320 - }
321 - $updates = SMWNotifyProcessor::$notifyJobs[$page_id];
322 - if(empty($updates)) {
323 - SMWNotifyProcessor::$notifyJobs[$page_id] = new SMWNotifyUpdate($title);
324 - $updates = SMWNotifyProcessor::$notifyJobs[$page_id];
325 - } else {
326 - $updates->executeNotifyUpdate();
327 - }
328 - $updates->updateNotifyMonitor();
329 - $updates->notifyUsers();
330 - unset(SMWNotifyProcessor::$notifyJobs[$page_id]);
331 - }
332 - static public function articleDelete($title, $reason) {
333 - $page_id = $title->getArticleID();
334 - if($page_id == 0) {
335 - return;
336 - }
337 - $updates = new SMWNotifyUpdate($title);
338 - $updates->executeNotifyDelete($reason);
339 - }
340 - static public function toInfoId($type, $subquery, $attr_id) {
341 - return base_convert(strval(($subquery << 8)|$type), 10, 9).'9'.$attr_id;
342 - }
343 - static public function getInfoFromId($id) {
344 - $idx = strpos($id, '9');
345 - $t = intval(base_convert(substr($id, 0, $idx), 9, 10));
346 - return array(
347 - 'type'=>$t&0xFF,
348 - 'subquery'=>$t>>8,
349 - 'attr_id'=>intval(substr($id, $idx+1))
350 - );
351 - }
352 -
353 -}
354 -
355 -// based on SMW_QueryProcessor.php (v 1.4.2)
356 -/**
357 - * Objects of this class are in charge of parsing a query string in order
358 - * to create an SMWDescription. The class and methods are not static in order
359 - * to more cleanly store the intermediate state and progress of the parser.
360 - */
361 -class SMWNotifyParser {
362 -
363 - protected $m_sepstack; // list of open blocks ("parentheses") that need closing at current step
364 - protected $m_curstring; // remaining string to be parsed (parsing eats query string from the front)
365 - var $m_errors; // empty array if all went right, array of strings otherwise
366 - protected $m_label; //label of the main query result
367 - protected $m_defaultns; //description of the default namespace restriction, or NULL if not used
368 -
369 - protected $m_categoryprefix; // cache label of category namespace . ':'
370 - protected $m_conceptprefix; // cache label of concept namespace . ':'
371 - protected $m_queryfeatures; // query features to be supported, format similar to $smwgQFeatures
372 -
373 - // added by dch
374 - protected $m_notify_id;
375 - protected $m_subquery;
376 - protected $m_printoutArticles;
377 - public $m_result;
378 -
379 - // modified by dch
380 - public function SMWNotifyParser($notify_id, $printoutArticles, $queryfeatures = false) {
381 - $this->m_notify_id = $notify_id;
382 - $this->m_printoutArticles = $printoutArticles;
383 - $this->m_result = true;
384 -
385 - global $wgContLang, $smwgQFeatures;
386 - $this->m_categoryprefix = $wgContLang->getNsText(NS_CATEGORY) . ':';
387 - $this->m_conceptprefix = $wgContLang->getNsText(SMW_NS_CONCEPT) . ':';
388 - $this->m_defaultns = NULL;
389 - $this->m_queryfeatures = $queryfeatures===false?$smwgQFeatures:$queryfeatures;
390 - }
391 -
392 - // added by dch
393 - public function hasSubquery() {
394 - return $this->m_subquery > 1;
395 - }
396 -
397 - /**
398 - * Provide an array of namespace constants that are used as default restrictions.
399 - * If NULL is given, no such default restrictions will be added (faster).
400 - */
401 - public function setDefaultNamespaces($nsarray) {
402 - $this->m_defaultns = NULL;
403 - if ($nsarray !== NULL) {
404 - foreach ($nsarray as $ns) {
405 - $this->m_defaultns = $this->addDescription($this->m_defaultns, new SMWNamespaceDescription($ns), false);
406 - }
407 - }
408 - }
409 -
410 - /**
411 - * Compute an SMWDescription from a query string. Returns whatever descriptions could be
412 - * wrestled from the given string (the most general result being SMWThingDescription if
413 - * no meaningful condition was extracted).
414 - */
415 - public function getQueryDescription($querystring) {
416 - wfProfileIn('SMWNotifyParser::getQueryDescription (SMW)');
417 - $this->m_errors = array();
418 - $this->m_label = '';
419 - $this->m_curstring = $querystring;
420 - $this->m_sepstack = array();
421 - $setNS = false;
422 -
423 - // added by dch
424 - $this->m_subquery = 0;
425 -
426 - $result = $this->getSubqueryDescription($setNS, $this->m_label);
427 - if (!$setNS) { // add default namespaces if applicable
428 - $result = $this->addDescription($this->m_defaultns, $result);
429 - }
430 - if ($result === NULL) { // parsing went wrong, no default namespaces
431 - $result = new SMWThingDescription();
432 - }
433 - wfProfileOut('SMWNotifyParser::getQueryDescription (SMW)');
434 - return $result;
435 - }
436 -
437 - /**
438 - * Return array of error messages (possibly empty).
439 - */
440 - public function getErrors() {
441 - return $this->m_errors;
442 - }
443 -
444 - /**
445 - * Return error message or empty string if no error occurred.
446 - */
447 - public function getErrorString() {
448 - return smwfEncodeMessages($this->m_errors);
449 - }
450 -
451 - /**
452 - * Return label for the results of this query (which
453 - * might be empty if no such information was passed).
454 - */
455 - public function getLabel() {
456 - return $this->m_label;
457 - }
458 -
459 -
460 - /**
461 - * Compute an SMWDescription for current part of a query, which should
462 - * be a standalone query (the main query or a subquery enclosed within
463 - * "\<q\>...\</q\>". Recursively calls similar methods and returns NULL upon error.
464 - *
465 - * The call-by-ref parameter $setNS is a boolean. Its input specifies whether
466 - * the query should set the current default namespace if no namespace restrictions
467 - * were given. If false, the calling super-query is happy to set the required
468 - * NS-restrictions by itself if needed. Otherwise the subquery has to impose the defaults.
469 - * This is so, since outermost queries and subqueries of disjunctions will have to set
470 - * their own default restrictions.
471 - *
472 - * The return value of $setNS specifies whether or not the subquery has a namespace
473 - * specification in place. This might happen automatically if the query string imposes
474 - * such restrictions. The return value is important for those callers that otherwise
475 - * set up their own restrictions.
476 - *
477 - * Note that $setNS is no means to switch on or off default namespaces in general,
478 - * but just controls query generation. For general effect, the default namespaces
479 - * should be set to NULL.
480 - *
481 - * The call-by-ref parameter $label is used to append any label strings found.
482 - */
483 - protected function getSubqueryDescription(&$setNS, &$label) {
484 - global $smwgQPrintoutLimit;
485 - wfLoadExtensionMessages('SemanticMediaWiki');
486 - $conjunction = NULL; // used for the current inner conjunction
487 - $disjuncts = array(); // (disjunctive) array of subquery conjunctions
488 - $printrequests = array(); // the printrequests found for this query level
489 - $hasNamespaces = false; // does the current $conjnuction have its own namespace restrictions?
490 - $mustSetNS = $setNS; // must ns restrictions be set? (may become true even if $setNS is false)
491 -
492 - // added by dch
493 - $subquery = $this->m_subquery;
494 - if($subquery == 0) {
495 - $relatedArticles = $this->m_printoutArticles;
496 - } else {
497 - $relatedArticles = array();
498 - }
499 - $this->m_subquery ++;
500 -
501 - $continue = ($chunk = $this->readChunk()) != ''; // skip empty subquery completely, thorwing an error
502 - while ($continue) {
503 - $setsubNS = false;
504 - switch ($chunk) {
505 - case '[[': // start new link block
506 - // modified by dch
507 - $ld = $this->getLinkDescription($setsubNS, $label, $relatedArticles);
508 -
509 - if ($ld instanceof SMWPrintRequest) {
510 - $printrequests[] = $ld;
511 - } elseif ($ld instanceof SMWDescription) {
512 - $conjunction = $this->addDescription($conjunction,$ld);
513 - }
514 - break;
515 - case '<q>': // enter new subquery, currently irrelevant but possible
516 - $this->pushDelimiter('</q>');
517 - $conjunction = $this->addDescription($conjunction, $this->getSubqueryDescription($setsubNS, $label));
518 - /// TODO: print requests from subqueries currently are ignored, should be moved down
519 - break;
520 - case 'OR': case '||': case '': case '</q>': // finish disjunction and maybe subquery
521 - if ($this->m_defaultns !== NULL) { // possibly add namespace restrictions
522 - if ( $hasNamespaces && !$mustSetNS) {
523 - // add ns restrictions to all earlier conjunctions (all of which did not have them yet)
524 - $mustSetNS = true; // enforce NS restrictions from now on
525 - $newdisjuncts = array();
526 - foreach ($disjuncts as $conj) {
527 - $newdisjuncts[] = $this->addDescription($conj, $this->m_defaultns);
528 - }
529 - $disjuncts = $newdisjuncts;
530 - } elseif ( !$hasNamespaces && $mustSetNS) {
531 - // add ns restriction to current result
532 - $conjunction = $this->addDescription($conjunction, $this->m_defaultns);
533 - }
534 - }
535 - $disjuncts[] = $conjunction;
536 - // start anew
537 - $conjunction = NULL;
538 - $hasNamespaces = false;
539 - // finish subquery?
540 - if ($chunk == '</q>') {
541 - if ($this->popDelimiter('</q>')) {
542 - $continue = false; // leave the loop
543 - } else {
544 - $this->m_errors[] = wfMsgForContent('smw_toomanyclosing', $chunk);
545 - return NULL;
546 - }
547 - } elseif ($chunk == '') {
548 - $continue = false;
549 - }
550 - break;
551 - case '+': // "... AND true" (ignore)
552 - break;
553 - default: // error: unexpected $chunk
554 - $this->m_errors[] = wfMsgForContent('smw_unexpectedpart', $chunk);
555 - //return NULL; // Try to go on, it can only get better ...
556 - }
557 - if ($setsubNS) { // namespace restrictions encountered in current conjunct
558 - $hasNamespaces = true;
559 - }
560 - if ($continue) { // read on only if $continue remained true
561 - $chunk = $this->readChunk();
562 - }
563 - }
564 -
565 - if (count($disjuncts) > 0) { // make disjunctive result
566 - $result = NULL;
567 - foreach ($disjuncts as $d) {
568 - if ($d === NULL) {
569 - $this->m_errors[] = wfMsgForContent('smw_emptysubquery');
570 - $setNS = false;
571 - return NULL;
572 - } else {
573 - $result = $this->addDescription($result, $d, false);
574 - }
575 - }
576 - } else {
577 - $this->m_errors[] = wfMsgForContent('smw_emptysubquery');
578 - $setNS = false;
579 - return NULL;
580 - }
581 - $setNS = $mustSetNS; // NOTE: also false if namespaces were given but no default NS descs are available
582 -
583 - $prcount = 0;
584 - foreach ($printrequests as $pr) { // add printrequests
585 - if ($prcount < $smwgQPrintoutLimit) {
586 - $result->addPrintRequest($pr);
587 - $prcount++;
588 - } else {
589 - $this->m_errors[] = wfMsgForContent('smw_overprintoutlimit');
590 - break;
591 - }
592 - }
593 -
594 - // added by dch
595 - if($this->m_result) {
596 - $sStore = NMStorage::getDatabase();
597 - $this->m_result = $sStore->addNotifyRelations($this->m_notify_id, $relatedArticles, $subquery);
598 - }
599 -
600 - return $result;
601 - }
602 -
603 - /**
604 - * Compute an SMWDescription for current part of a query, which should
605 - * be the content of "[[ ... ]]". Alternatively, if the current syntax
606 - * specifies a print request, return the print request object.
607 - * Returns NULL upon error.
608 - *
609 - * Parameters $setNS and $label have the same use as in getSubqueryDescription().
610 - */
611 - // modified by dch, add $relatedArticles
612 - protected function getLinkDescription(&$setNS, &$label, &$relatedArticles) {
613 - // This method is called when we encountered an opening '[['. The following
614 - // block could be a Category-statement, fixed object, property statements,
615 - // or according print statements.
616 - $chunk = $this->readChunk('',true,false); // NOTE: untrimmed, initial " " escapes prop. chains
617 - if ( (smwfNormalTitleText($chunk) == $this->m_categoryprefix) || // category statement or
618 - (smwfNormalTitleText($chunk) == $this->m_conceptprefix) ) { // concept statement
619 - return $this->getClassDescription($setNS, $label, $relatedArticles,
620 - (smwfNormalTitleText($chunk) == $this->m_categoryprefix));
621 - } else { // fixed subject, namespace restriction, property query, or subquery
622 - $sep = $this->readChunk('',false); //do not consume hit, "look ahead"
623 - if ( ($sep == '::') || ($sep == ':=') ) {
624 - if ($chunk{0} !=':') { // property statement
625 - return $this->getPropertyDescription($chunk, $setNS, $label, $relatedArticles);
626 - } else { // escaped article description, read part after :: to get full contents
627 - $chunk .= $this->readChunk('\[\[|\]\]|\|\||\|');
628 - return $this->getArticleDescription(trim($chunk), $setNS, $label, $relatedArticles);
629 - }
630 - } else { // Fixed article/namespace restriction. $sep should be ]] or ||
631 - return $this->getArticleDescription(trim($chunk), $setNS, $label, $relatedArticles);
632 - }
633 - }
634 - }
635 -
636 - /**
637 - * Parse a category description (the part of an inline query that
638 - * is in between "[[Category:" and the closing "]]" and create a
639 - * suitable description.
640 - */
641 - // modified by dch ,add $relatedArticles
642 - protected function getClassDescription(&$setNS, &$label, &$relatedArticles, $category=true) {
643 - global $smwgSMWBetaCompatible; // * printouts only for this old version
644 - // note: no subqueries allowed here, inline disjunction allowed, wildcards allowed
645 - $result = NULL;
646 - $continue = true;
647 - while ($continue) {
648 - $chunk = $this->readChunk();
649 - if ($chunk == '+') {
650 - //wildcard, ignore for categories (semantically meaningless, everything is in some class)
651 - } elseif ( ($chunk == '+') && $category && $smwgSMWBetaCompatible) { // print statement
652 - $chunk = $this->readChunk('\]\]|\|');
653 - if ($chunk == '|') {
654 - $printlabel = $this->readChunk('\]\]');
655 - if ($printlabel != ']]') {
656 - $chunk = $this->readChunk('\]\]');
657 - } else {
658 - $printlabel = '';
659 - $chunk = ']]';
660 - }
661 - } else {
662 - global $wgContLang;
663 - $printlabel = $wgContLang->getNSText(NS_CATEGORY);
664 - }
665 - if ($chunk == ']]') {
666 - return new SMWPrintRequest(SMWPrintRequest::PRINT_CATS, $printlabel);
667 - } else {
668 - $this->m_errors[] = wfMsgForContent('smw_badprintout');
669 - return NULL;
670 - }
671 - } else { //assume category/concept title
672 - /// NOTE: use m_c...prefix to prevent problems with, e.g., [[Category:Template:Test]]
673 - $class = Title::newFromText(($category?$this->m_categoryprefix:$this->m_conceptprefix) . $chunk);
674 - if ($class !== NULL) {
675 - $desc = $category?new SMWClassDescription($class):new SMWConceptDescription($class);
676 - $result = $this->addDescription($result, $desc, false);
677 - }
678 -
679 - // added by dch
680 - if($category) {
681 - $relatedArticles[] = array(
682 - 'namespace' => NS_CATEGORY,
683 - 'title' => $class->getDBkey());
684 - }
685 -
686 - }
687 - $chunk = $this->readChunk();
688 - $continue = ($chunk == '||') && $category; // disjunctions only for cateories
689 - }
690 -
691 - return $this->finishLinkDescription($chunk, false, $result, $setNS, $label);
692 - }
693 -
694 - /**
695 - * Parse a property description (the part of an inline query that
696 - * is in between "[[Some property::" and the closing "]]" and create a
697 - * suitable description. The "::" is the first chunk on the current
698 - * string.
699 - */
700 - // modified by dch ,add $relatedArticles
701 - protected function getPropertyDescription($propertyname, &$setNS, &$label, &$relatedArticles) {
702 - global $smwgSMWBetaCompatible; // support for old * printouts of beta
703 - wfLoadExtensionMessages('SemanticMediaWiki');
704 - $this->readChunk(); // consume separator ":=" or "::"
705 - // first process property chain syntax (e.g. "property1.property2::value"):
706 - if ($propertyname{0} == ' ') { // escape
707 - $propertynames = array($propertyname);
708 - } else {
709 - $propertynames = explode('.', $propertyname);
710 - }
711 - $properties = array();
712 - $typeid = '_wpg';
713 - foreach ($propertynames as $name) {
714 - if ($typeid != '_wpg') { // non-final property in chain was no wikipage: not allowed
715 - $this->m_errors[] = wfMsgForContent('smw_valuesubquery', $prevname);
716 - return NULL; ///TODO: read some more chunks and try to finish [[ ]]
717 - }
718 - $property = SMWPropertyValue::makeUserProperty($name);
719 - if (!$property->isValid()) { // illegal property identifier
720 - $this->m_errors = array_merge($this->m_errors, $property->getErrors());
721 - return NULL; ///TODO: read some more chunks and try to finish [[ ]]
722 - }
723 - $typeid = $property->getTypeID();
724 - $prevname = $name;
725 - $properties[] = $property;
726 -
727 - // added by dch
728 - $relatedArticles[] = array(
729 - 'namespace' => SMW_NS_PROPERTY,
730 - 'title' => $property->getDBkey());
731 -
732 - } ///NOTE: after iteration, $property and $typeid correspond to last value
733 -
734 - $innerdesc = NULL;
735 - $continue = true;
736 - while ($continue) {
737 - $chunk = $this->readChunk();
738 - switch ($chunk) {
739 - case '+': // wildcard, add namespaces for page-type properties
740 - if ( ($this->m_defaultns !== NULL) && ($typeid == '_wpg') ) {
741 - $innerdesc = $this->addDescription($innerdesc, $this->m_defaultns, false);
742 - } else {
743 - $innerdesc = $this->addDescription($innerdesc, new SMWThingDescription(), false);
744 - }
745 - $chunk = $this->readChunk();
746 - break;
747 - case '<q>': // subquery, set default namespaces
748 - if ($typeid == '_wpg') {
749 - $this->pushDelimiter('</q>');
750 - $setsubNS = true;
751 - $sublabel = '';
752 - $innerdesc = $this->addDescription($innerdesc, $this->getSubqueryDescription($setsubNS, $sublabel), false);
753 - } else { // no subqueries allowed for non-pages
754 - $this->m_errors[] = wfMsgForContent('smw_valuesubquery', end($propertynames));
755 - $innerdesc = $this->addDescription($innerdesc, new SMWThingDescription(), false);
756 - }
757 - $chunk = $this->readChunk();
758 - break;
759 - default: //normal object value or print statement
760 - // read value(s), possibly with inner [[...]]
761 - $open = 1;
762 - $value = $chunk;
763 - $continue2 = true;
764 - // read value with inner [[, ]], ||
765 - while ( ($open > 0) && ($continue2) ) {
766 - $chunk = $this->readChunk('\[\[|\]\]|\|\||\|');
767 - switch ($chunk) {
768 - case '[[': // open new [[ ]]
769 - $open++;
770 - break;
771 - case ']]': // close [[ ]]
772 - $open--;
773 - break;
774 - case '|': case '||': // terminates only outermost [[ ]]
775 - if ($open == 1) {
776 - $open = 0;
777 - }
778 - break;
779 - case '': ///TODO: report error; this is not good right now
780 - $continue2 = false;
781 - break;
782 - }
783 - if ($open != 0) {
784 - $value .= $chunk;
785 - }
786 - } ///NOTE: at this point, we normally already read one more chunk behind the value
787 -
788 - if ($typeid == '__nry') { // nary value
789 - $dv = SMWDataValueFactory::newPropertyObjectValue($property);
790 - $dv->acceptQuerySyntax();
791 - $dv->setUserValue($value);
792 - $vl = $dv->getValueList();
793 - $pm = $dv->getPrintModifier();
794 - if ($vl !== NULL) { // prefer conditions over print statements (only one possible right now)
795 - $innerdesc = $this->addDescription($innerdesc, $vl, false);
796 - } elseif ($pm !== false) {
797 - if ($chunk == '|') {
798 - $printlabel = $this->readChunk('\]\]');
799 - if ($printlabel != ']]') {
800 - $chunk = $this->readChunk('\]\]');
801 - } else {
802 - $printlabel = '';
803 - $chunk = ']]';
804 - }
805 - } else {
806 - $printlabel = $property->getWikiValue();
807 - }
808 - if ($chunk == ']]') {
809 - return new SMWPrintRequest(SMWPrintRequest::PRINT_PROP, $printlabel, $property, $pm);
810 - } else {
811 - $this->m_errors[] = wfMsgForContent('smw_badprintout');
812 - return NULL;
813 - }
814 - }
815 - } else { // unary value
816 - $comparator = SMW_CMP_EQ;
817 - $printmodifier = '';
818 - SMWNotifyParser::prepareValue($value, $comparator, $printmodifier);
819 - if ( ($value == '*') && $smwgSMWBetaCompatible ) {
820 - if ($chunk == '|') {
821 - $printlabel = $this->readChunk('\]\]');
822 - if ($printlabel != ']]') {
823 - $chunk = $this->readChunk('\]\]');
824 - } else {
825 - $printlabel = '';
826 - $chunk = ']]';
827 - }
828 - } else {
829 - $printlabel = $property->getWikiValue();
830 - }
831 - if ($chunk == ']]') {
832 - return new SMWPrintRequest(SMWPrintRequest::PRINT_PROP, $printlabel, $property, $printmodifier);
833 - } else {
834 - $this->m_errors[] = wfMsgForContent('smw_badprintout');
835 - return NULL;
836 - }
837 - } else {
838 - $dv = SMWDataValueFactory::newPropertyObjectValue($property, $value);
839 - if (!$dv->isValid()) {
840 - $this->m_errors = $this->m_errors + $dv->getErrors();
841 - $vd = new SMWThingDescription();
842 - } else {
843 - $vd = new SMWValueDescription($dv, $comparator);
844 - }
845 - $innerdesc = $this->addDescription($innerdesc, $vd, false);
846 - }
847 - }
848 - }
849 - $continue = ($chunk == '||');
850 - }
851 -
852 - if ($innerdesc === NULL) { // make a wildcard search
853 - if ( ($this->m_defaultns !== NULL) && ($typeid == '_wpg') ) {
854 - $innerdesc = $this->addDescription($innerdesc, $this->m_defaultns, false);
855 - } else {
856 - $innerdesc = $this->addDescription($innerdesc, new SMWThingDescription(), false);
857 - }
858 - $this->m_errors[] = wfMsgForContent('smw_propvalueproblem', $property->getWikiValue());
859 - }
860 - $properties = array_reverse($properties);
861 - foreach ($properties as $property) {
862 - $innerdesc = new SMWSomeProperty($property,$innerdesc);
863 - }
864 - $result = $innerdesc;
865 - return $this->finishLinkDescription($chunk, false, $result, $setNS, $label);
866 - }
867 -
868 -
869 - /**
870 - * Prepare a single value string, possibly extracting comparators and
871 - * printmodifier. $value is changed to consist only of the remaining
872 - * effective value string, or of "*" for print statements.
873 - */
874 - static public function prepareValue(&$value, &$comparator, &$printmodifier) {
875 - global $smwgQComparators, $smwgSMWBetaCompatible; // support for old * printouts of beta
876 - // get print modifier behind *
877 - if ($smwgSMWBetaCompatible) {
878 - $list = preg_split('/^\*/',$value,2);
879 - if (count($list) == 2) { //hit
880 - $value = '*';
881 - $printmodifier = $list[1];
882 - } else {
883 - $printmodifier = '';
884 - }
885 - if ($value == '*') { // printout statement
886 - return;
887 - }
888 - }
889 - $list = preg_split('/^(' . $smwgQComparators . ')/u',$value, 2, PREG_SPLIT_DELIM_CAPTURE);
890 - $comparator = SMW_CMP_EQ;
891 - if (count($list) == 3) { // initial comparator found ($list[1] should be empty)
892 - switch ($list[1]) {
893 - case '<':
894 - $comparator = SMW_CMP_LEQ;
895 - $value = $list[2];
896 - break;
897 - case '>':
898 - $comparator = SMW_CMP_GEQ;
899 - $value = $list[2];
900 - break;
901 - case '!':
902 - $comparator = SMW_CMP_NEQ;
903 - $value = $list[2];
904 - break;
905 - case '~':
906 - $comparator = SMW_CMP_LIKE;
907 - $value = $list[2];
908 - break;
909 - //default: not possible
910 - }
911 - }
912 - }
913 -
914 - /**
915 - * Parse an article description (the part of an inline query that
916 - * is in between "[[" and the closing "]]" assuming it is not specifying
917 - * a category or property) and create a suitable description.
918 - * The first chunk behind the "[[" has already been read and is
919 - * passed as a parameter.
920 - */
921 - // modified by dch ,add $relatedArticles
922 - protected function getArticleDescription($firstchunk, &$setNS, &$label, &$relatedArticles) {
923 - wfLoadExtensionMessages('SemanticMediaWiki');
924 - $chunk = $firstchunk;
925 - $result = NULL;
926 - $continue = true;
927 - //$innerdesc = NULL;
928 - while ($continue) {
929 - if ($chunk == '<q>') { // no subqueries of the form [[<q>...</q>]] (not needed)
930 - $this->m_errors[] = wfMsgForContent('smw_misplacedsubquery');
931 - return NULL;
932 - }
933 - $list = preg_split('/:/', $chunk, 3); // ":Category:Foo" "User:bar" ":baz" ":+"
934 - if ( ($list[0] == '') && (count($list)==3) ) {
935 - $list = array_slice($list, 1);
936 - }
937 - if ( (count($list) == 2) && ($list[1] == '+') ) { // try namespace restriction
938 - global $wgContLang;
939 - $idx = $wgContLang->getNsIndex($list[0]);
940 - if ($idx !== false) {
941 - $result = $this->addDescription($result, new SMWNamespaceDescription($idx), false);
942 - }
943 - } else {
944 - $value = SMWDataValueFactory::newTypeIDValue('_wpg', $chunk);
945 - if ($value->isValid()) {
946 - $result = $this->addDescription($result, new SMWValueDescription($value), false);
947 - // added by dch
948 - $relatedArticles[] = array(
949 - 'namespace' => NS_MAIN,
950 - 'title' => Title::makeTitle( NS_MAIN, $chunk )->getDBkey());
951 - }
952 - }
953 -
954 - $chunk = $this->readChunk('\[\[|\]\]|\|\||\|');
955 - if ($chunk == '||') {
956 - $chunk = $this->readChunk('\[\[|\]\]|\|\||\|');
957 - $continue = true;
958 - } else {
959 - $continue = false;
960 - }
961 - }
962 -
963 - return $this->finishLinkDescription($chunk, true, $result, $setNS, $label);
964 - }
965 -
966 - protected function finishLinkDescription($chunk, $hasNamespaces, $result, &$setNS, &$label) {
967 - wfLoadExtensionMessages('SemanticMediaWiki');
968 - if ($result === NULL) { // no useful information or concrete error found
969 - $this->m_errors[] = wfMsgForContent('smw_badqueryatom');
970 - } elseif (!$hasNamespaces && $setNS && ($this->m_defaultns !== NULL) ) {
971 - $result = $this->addDescription($result, $this->m_defaultns);
972 - $hasNamespaces = true;
973 - }
974 - $setNS = $hasNamespaces;
975 -
976 - // terminate link (assuming that next chunk was read already)
977 - if ($chunk == '|') {
978 - $chunk = $this->readChunk('\]\]');
979 - if ($chunk != ']]') {
980 - $label .= $chunk;
981 - $chunk = $this->readChunk('\]\]');
982 - } else { // empty label does not add to overall label
983 - $chunk = ']]';
984 - }
985 - }
986 - if ($chunk != ']]') {
987 - // What happended? We found some chunk that could not be processed as
988 - // link content (as in [[Category:Test<q>]]) and there was no label to
989 - // eat it. Or the closing ]] are just missing entirely.
990 - if ($chunk != '') {
991 - $this->m_errors[] = wfMsgForContent('smw_misplacedsymbol', htmlspecialchars($chunk));
992 - // try to find a later closing ]] to finish this misshaped subpart
993 - $chunk = $this->readChunk('\]\]');
994 - if ($chunk != ']]') {
995 - $chunk = $this->readChunk('\]\]');
996 - }
997 - }
998 - if ($chunk == '') {
999 - $this->m_errors[] = wfMsgForContent('smw_noclosingbrackets');
1000 - }
1001 - }
1002 - return $result;
1003 - }
1004 -
1005 - /**
1006 - * Get the next unstructured string chunk from the query string.
1007 - * Chunks are delimited by any of the special strings used in inline queries
1008 - * (such as [[, ]], <q>, ...). If the string starts with such a delimiter,
1009 - * this delimiter is returned. Otherwise the first string in front of such a
1010 - * delimiter is returned.
1011 - * Trailing and initial spaces are ignored if $trim is true, and chunks
1012 - * consisting only of spaces are not returned.
1013 - * If there is no more qurey string left to process, the empty string is
1014 - * returned (and in no other case).
1015 - *
1016 - * The stoppattern can be used to customise the matching, especially in order to
1017 - * overread certain special symbols.
1018 - *
1019 - * $consume specifies whether the returned chunk should be removed from the
1020 - * query string.
1021 - */
1022 - protected function readChunk($stoppattern = '', $consume=true, $trim=true) {
1023 - if ($stoppattern == '') {
1024 - $stoppattern = '\[\[|\]\]|::|:=|<q>|<\/q>|^' . $this->m_categoryprefix .
1025 - '|^' . $this->m_conceptprefix . '|\|\||\|';
1026 - }
1027 - $chunks = preg_split('/[\s]*(' . $stoppattern . ')/u', $this->m_curstring, 2, PREG_SPLIT_DELIM_CAPTURE);
1028 - if (count($chunks) == 1) { // no matches anymore, strip spaces and finish
1029 - if ($consume) {
1030 - $this->m_curstring = '';
1031 - }
1032 - return $trim?trim($chunks[0]):$chunks[0];
1033 - } elseif (count($chunks) == 3) { // this should generally happen if count is not 1
1034 - if ($chunks[0] == '') { // string started with delimiter
1035 - if ($consume) {
1036 - $this->m_curstring = $chunks[2];
1037 - }
1038 - return $trim?trim($chunks[1]):$chunks[1];
1039 - } else {
1040 - if ($consume) {
1041 - $this->m_curstring = $chunks[1] . $chunks[2];
1042 - }
1043 - return $trim?trim($chunks[0]):$chunks[0];
1044 - }
1045 - } else { return false; } //should never happen
1046 - }
1047 -
1048 - /**
1049 - * Enter a new subblock in the query, which must at some time be terminated by the
1050 - * given $endstring delimiter calling popDelimiter();
1051 - */
1052 - protected function pushDelimiter($endstring) {
1053 - array_push($this->m_sepstack, $endstring);
1054 - }
1055 -
1056 - /**
1057 - * Exit a subblock in the query ending with the given delimiter.
1058 - * If the delimiter does not match the top-most open block, false
1059 - * will be returned. Otherwise return true.
1060 - */
1061 - protected function popDelimiter($endstring) {
1062 - $topdelim = array_pop($this->m_sepstack);
1063 - return ($topdelim == $endstring);
1064 - }
1065 -
1066 - /**
1067 - * Extend a given description by a new one, either by adding the new description
1068 - * (if the old one is a container description) or by creating a new container.
1069 - * The parameter $conjunction determines whether the combination of both descriptions
1070 - * should be a disjunction or conjunction.
1071 - *
1072 - * In the special case that the current description is NULL, the new one will just
1073 - * replace the current one.
1074 - *
1075 - * The return value is the expected combined description. The object $curdesc will
1076 - * also be changed (if it was non-NULL).
1077 - */
1078 - protected function addDescription($curdesc, $newdesc, $conjunction = true) {
1079 - wfLoadExtensionMessages('SemanticMediaWiki');
1080 - $notallowedmessage = 'smw_noqueryfeature';
1081 - if ($newdesc instanceof SMWSomeProperty) {
1082 - $allowed = $this->m_queryfeatures & SMW_PROPERTY_QUERY;
1083 - } elseif ($newdesc instanceof SMWClassDescription) {
1084 - $allowed = $this->m_queryfeatures & SMW_CATEGORY_QUERY;
1085 - } elseif ($newdesc instanceof SMWConceptDescription) {
1086 - $allowed = $this->m_queryfeatures & SMW_CONCEPT_QUERY;
1087 - } elseif ($newdesc instanceof SMWConjunction) {
1088 - $allowed = $this->m_queryfeatures & SMW_CONJUNCTION_QUERY;
1089 - $notallowedmessage = 'smw_noconjunctions';
1090 - } elseif ($newdesc instanceof SMWDisjunction) {
1091 - $allowed = $this->m_queryfeatures & SMW_DISJUNCTION_QUERY;
1092 - $notallowedmessage = 'smw_nodisjunctions';
1093 - } else {
1094 - $allowed = true;
1095 - }
1096 - if (!$allowed) {
1097 - $this->m_errors[] = wfMsgForContent($notallowedmessage, str_replace('[', '&#x005B;', $newdesc->getQueryString()));
1098 - return $curdesc;
1099 - }
1100 - if ($newdesc === NULL) {
1101 - return $curdesc;
1102 - } elseif ($curdesc === NULL) {
1103 - return $newdesc;
1104 - } else { // we already found descriptions
1105 - if ( (($conjunction) && ($curdesc instanceof SMWConjunction)) ||
1106 - ((!$conjunction) && ($curdesc instanceof SMWDisjunction)) ) { // use existing container
1107 - $curdesc->addDescription($newdesc);
1108 - return $curdesc;
1109 - } elseif ($conjunction) { // make new conjunction
1110 - if ($this->m_queryfeatures & SMW_CONJUNCTION_QUERY) {
1111 - return new SMWConjunction(array($curdesc,$newdesc));
1112 - } else {
1113 - $this->m_errors[] = wfMsgForContent('smw_noconjunctions', str_replace('[', '&#x005B;', $newdesc->getQueryString()));
1114 - return $curdesc;
1115 - }
1116 - } else { // make new disjunction
1117 - if ($this->m_queryfeatures & SMW_DISJUNCTION_QUERY) {
1118 - return new SMWDisjunction(array($curdesc,$newdesc));
1119 - } else {
1120 - $this->m_errors[] = wfMsgForContent('smw_nodisjunctions', str_replace('[', '&#x005B;', $newdesc->getQueryString()));
1121 - return $curdesc;
1122 - }
1123 - }
1124 - }
1125 - }
1126 -}
1127 -
1128 -class SMWNotifyUpdate {
1129 - protected $m_info;
1130 - protected $m_title;
1131 - protected $m_userMsgs;
1132 - protected $m_userHtmlPropMsgs;
1133 - protected $m_userHtmlNMMsgs;
1134 - protected $m_userNMs;
1135 - protected $m_notifyHtmlPropMsgs;
1136 - protected $m_notifyHtmlMsgs;
1137 - protected $m_newMonitor;
1138 - protected $m_removeMonitored;
1139 - protected $m_subQueryNotify;
1140 -
1141 - protected $m_linker;
1142 -
1143 - protected function getSemanticInfo($title) {
1144 - $result = array();
1145 - $sStore = NMStorage::getDatabase();
1146 - $semdata = smwfGetStore()->getSemanticData($title);
1147 - foreach($semdata->getProperties() as $property) {
1148 - if (!$property->isShown() && $property->getWikiValue()!='') { // showing this is not desired, hide
1149 - continue;
1150 - } elseif ($property->isUserDefined()) { // user defined property
1151 - $property->setCaption(preg_replace('/[ ]/u','&nbsp;',$property->getWikiValue(),2));
1152 - }
1153 -
1154 - $propvalues = $semdata->getPropertyValues($property);
1155 - if($property->getWikiValue()!='') {
1156 - foreach ($propvalues as $propvalue) {
1157 - if($propvalue->getXSDValue() != '') {
1158 - $result[SMWNotifyProcessor::toInfoId(2,0,$sStore->lookupSmwId(SMW_NS_PROPERTY, $property->getXSDValue()))][] = array('name'=>$property, 'value'=>$propvalue);
1159 - }
1160 - }
1161 - } else {
1162 - foreach ($propvalues as $propvalue) {
1163 - if(($propvalue instanceof SMWWikiPageValue)&&($propvalue->getNamespace() == NS_CATEGORY)) {
1164 - $result[SMWNotifyProcessor::toInfoId(0,0,$sStore->lookupSmwId(NS_CATEGORY, $propvalue->getXSDValue()))][] = array('name'=>$propvalue, 'value'=>null);
1165 - }
1166 - }
1167 - }
1168 - }
1169 - return $result;
1170 - }
1171 -
1172 - public function SMWNotifyUpdate($title) {
1173 - $this->m_title = $title;
1174 - $this->m_userMsgs = array();
1175 - $this->m_userHtmlPropMsgs = array();
1176 - $this->m_userHtmlNMMsgs = array();
1177 - $this->m_userNMs = array();
1178 - $this->m_notifyHtmlPropMsgs = array();
1179 - $this->m_notifyHtmlMsgs = array();
1180 - $this->m_newMonitor = array();
1181 - $this->m_removeMonitored = array();
1182 - $this->m_subQueryNotify = array();
1183 - $this->m_linker = new Linker();
1184 -
1185 - $page_id = $title->getArticleID();
1186 - if(($page_id == 0) || ($this->m_title->getNamespace() != NS_MAIN)) {
1187 - return;
1188 - }
1189 - $this->m_info = $this->getSemanticInfo($this->m_title);
1190 - }
1191 - public function executeNotifyDelete($reason) {
1192 - $page_id = $this->m_title->getArticleID();
1193 - if(($page_id == 0) || ($this->m_title->getNamespace() != NS_MAIN)) {
1194 - return;
1195 - }
1196 - $page_name = $this->m_title->getText().' ('.$this->m_title->getFullUrl().')';
1197 - $page_html_name = '<a href="'.$this->m_title->getFullUrl().'">'.htmlspecialchars($this->m_title->getText()).'</a>';
1198 -
1199 - $msg .= "\r\nPage $page_name has been deleted.\r\nReason : $reason";
1200 - $sStore = NMStorage::getDatabase();
1201 - $notifications = $sStore->getMonitoredNotifications($page_id);
1202 -
1203 - foreach($notifications as $user_id=>$notifies) {
1204 - $this->m_userMsgs[$user_id] .= $msg.'\r\n( NM: ';
1205 - $hint = "<P>Page $page_html_name has been deleted.<br/>Reason : <font color='red'>".htmlspecialchars($reason)."</font></P>";
1206 - $this->m_userHtmlNMMsgs[$user_id] .= "$hint<P>Notify Me: ";
1207 - $idx = 0;
1208 - foreach($notifies as $notify_id=>$notify_detail) {
1209 - if($idx>0) {
1210 - $this->m_userMsgs[$user_id] .= ', ';
1211 - $this->m_userHtmlNMMsgs[$user_id] .= ', ';
1212 - }
1213 - $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
1214 -
1215 - $this->m_userMsgs[$user_id] .= $notify_detail['name'];
1216 - $this->m_userHtmlNMMsgs[$user_id] .= '<b>'.htmlspecialchars($notify_detail['name']).'</b>';
1217 - $idx++;
1218 - $this->m_removeMonitored[] = array('notify_id'=>$notify_id, 'page_id'=>$page_id);
1219 -
1220 - $this->m_userNMs[$user_id][] = $notify_id;
1221 - }
1222 -
1223 - $this->m_userMsgs[$user_id] .= " ).";
1224 - $this->m_userHtmlNMMsgs[$user_id] .= " does not match this page now.</P>";
1225 - }
1226 -
1227 - $this->notifyUsers();
1228 - $sStore->removeNotifyMonitor($this->m_removeMonitored);
1229 - }
1230 - function isEqual($v1, $v2) {
1231 - return (strval($v1[value]->getXSDValue()) == strval($v2[value]->getXSDValue()));
1232 - }
1233 - function getNotifyPlain($info, $key){
1234 - $i = SMWNotifyProcessor::getInfoFromId($key);
1235 - if($i[type]==0) {
1236 - return "\r\n'".$info[name]->getWikiValue()."' has been ".($info[sem_act]==0?"deleted":"added").".";
1237 - } else {
1238 - $tmp = "\r\nProperty '".$info[name]->getWikiValue()."' has been ".($info[sem_act]==0?"deleted.":($info[sem_act]==1?"modified":"added")).".";
1239 - $first = true;
1240 - foreach($info[del_vals] as $val) {
1241 - if($first) {
1242 - $tmp .= "\r\nValue '";
1243 - $first = false;
1244 - } else {
1245 - $tmp .= "', '";
1246 - }
1247 - $tmp .= $val[plain];
1248 - }
1249 - if(!$first) {
1250 - $tmp .= "' deleted.";
1251 - }
1252 - $first = true;
1253 - foreach($info[new_vals] as $val) {
1254 - if($first) {
1255 - $tmp .= "\r\nValue '";
1256 - $first = false;
1257 - } else {
1258 - $tmp .= "', '";
1259 - }
1260 - $tmp .= $val[plain];
1261 - }
1262 - if(!$first) {
1263 - $tmp .= "' added.";
1264 - }
1265 - return $tmp."\r\n";
1266 - }
1267 - }
1268 - function getNotifyHtml($info, $key){
1269 - $i = SMWNotifyProcessor::getInfoFromId($key);
1270 - if($i[type]==0) {
1271 - return "<td>Category</td>
1272 - <td>".$info[name]->getShortHTMLText($this->m_linker)."</td>
1273 - <td>".($info[sem_act]==0?"<font color='green'>remove</font>":"<font color='red'>cite</font>")."</td>
1274 - <td colspan='2'>N/A</td>";
1275 - } else {
1276 - $rows = max(count($info[del_vals]), count($info[new_vals]));
1277 - $tmp = "<tr><td rowspan='$rows'>Property</td>
1278 - <td rowspan='$rows'>".$info[name]->getShortHTMLText($this->m_linker)."</td>
1279 - <td rowspan='$rows'>".($info[sem_act]==0?"<font color='green'>remove</font>":($info[sem_act]==1?"<font color='blue'>modify</font>":"<font color='red'>cite</font>"))."</td>";
1280 - for($idx=0;$idx<$rows;++$idx) {
1281 - if($idx>0){
1282 - $tmp .= "<tr>";
1283 - }
1284 - $tmp .= "<td>".(isset($info[del_vals][$idx])?$info[del_vals][$idx][html]:"&nbsp;")."</td>
1285 - <td>".(isset($info[new_vals][$idx])?$info[new_vals][$idx][html]:"&nbsp;")."</td>
1286 - </tr>";
1287 - }
1288 - return $tmp;
1289 - }
1290 - }
1291 - public function executeNotifyUpdate() {
1292 - $page_id = $this->m_title->getArticleID();
1293 - if(($page_id == 0) || ($this->m_title->getNamespace() != NS_MAIN)) {
1294 - return;
1295 - }
1296 - $sStore = NMStorage::getDatabase();
1297 -
1298 - $info = $this->getSemanticInfo($this->m_title);
1299 - // get different
1300 - $tmp_info = array(); // type : category 0, property 2; name; sem action : del 0, modify 1, add 2; val action : del 0, add 1
1301 - foreach($this->m_info as $key=>$value) {
1302 - $i = SMWNotifyProcessor::getInfoFromId($key);
1303 - $updated = false;
1304 - if(!isset($info[$key])) {
1305 - if($i[type]==0) {
1306 - $tmp_info[$key] = array('sem_act' => 0, 'name'=>$value[0][name]);
1307 - }else {
1308 - $tmp_info[$key] = array('sem_act'=>0, 'name'=>$value[0][name], 'del_vals'=>array(), 'new_vals'=>array());
1309 - foreach($value as $v) {
1310 - $tmp_info[$key][del_vals][] = array( 'plain' => $v[value]->getWikiValue(), 'html' => $v[value]->getShortHTMLText($this->m_linker));
1311 - }
1312 - }
1313 - } else if($i[type] == 2) {
1314 - $mvalue = $info[$key];
1315 - foreach($value as $v1) {
1316 - $found = false;
1317 - foreach($mvalue as $v2) {
1318 - if($this->isEqual($v1, $v2)) {
1319 - $found = true;
1320 - break;
1321 - }
1322 - }
1323 - if(!$found) {
1324 - if(!$updated){
1325 - $updated = true;
1326 - $tmp_info[$key] = array('sem_act'=>1, 'name'=>$value[0][name], 'del_vals'=>array(), 'new_vals'=>array());
1327 - }
1328 - $tmp_info[$key][del_vals][] = array( 'plain' => $v1[value]->getWikiValue(), 'html' => $v1[value]->getShortHTMLText($this->m_linker));
1329 - }
1330 - }
1331 - foreach($mvalue as $v1) {
1332 - $found = false;
1333 - foreach($value as $v2) {
1334 - if($this->isEqual($v1, $v2)) {
1335 - $found = true;
1336 - break;
1337 - }
1338 - }
1339 - if(!$found) {
1340 - if(!$updated){
1341 - $updated = true;
1342 - $tmp_info[$key] = array('sem_act'=>1, 'name'=>$value[0][name], 'del_vals'=>array(), 'new_vals'=>array());
1343 - }
1344 - $tmp_info[$key][new_vals][] = array( 'plain' => $v1[value]->getWikiValue(), 'html' => $v1[value]->getShortHTMLText($this->m_linker));
1345 - }
1346 - }
1347 - }
1348 - }
1349 - foreach($info as $key=>$value) {
1350 - $i = SMWNotifyProcessor::getInfoFromId($key);
1351 - if(!isset($this->m_info[$key])) {
1352 - if($i[type]==0) {
1353 - $tmp_info[$key] = array('sem_act' => 2, 'name'=>$value[0][name]);
1354 - }else {
1355 - $tmp_info[$key] = array('sem_act'=>2, 'name'=>$value[0][name], 'del_vals'=>array(), 'new_vals'=>array());
1356 - foreach($value as $v) {
1357 - $tmp_info[$key][new_vals][] = array( 'plain' => $v[value]->getWikiValue(), 'html' => $v[value]->getShortHTMLText($this->m_linker));
1358 - }
1359 - }
1360 - }
1361 - }
1362 -
1363 - $notifications = $sStore->getMonitoredNotificationsDetail($page_id);
1364 - // add semantic info to report all NM
1365 - foreach($notifications as $user_id=>$notifies) {
1366 - foreach($notifies['rep_all'] as $notify_id=>$notify_name) {
1367 - foreach(array_keys($tmp_info) as $key) {
1368 - $notifications[$user_id]['semantic'][$key][$notify_id]=$notify_name;
1369 - }
1370 - }
1371 - }
1372 - $page_name = $this->m_title->getText().' ('.$this->m_title->getFullUrl().')';
1373 -
1374 - foreach($notifications as $user_id=>$notifies) {
1375 - foreach($notifies['semantic'] as $key=>$notify) {
1376 - if(isset($tmp_info[$key])) {
1377 - $hint = "";
1378 - if(!isset($this->m_userMsgs[$user_id])) {
1379 - $this->m_userMsgs[$user_id] = "\r\nSemantic attributes are changed in page $page_name.";
1380 - $hint = "Semantic attributes are changed in page <a href='".$this->m_title->getFullUrl()."'>".htmlspecialchars($this->m_title->getText())."</a>.<br/>";
1381 - $this->m_userHtmlNMMsgs[$user_id] .= $hint;
1382 - }
1383 -
1384 - $this->m_userMsgs[$user_id] .= $this->getNotifyPlain($tmp_info[$key],$key).' ( NM: ';
1385 - $propHint = $this->getNotifyHtml($tmp_info[$key],$key);
1386 - $this->m_userHtmlPropMsgs[$user_id] .= $propHint . "<tr><td colspan='5'>Notify Me: ";
1387 - $idx = 0;
1388 - foreach($notify as $notify_id=>$notify_name) {
1389 - if($idx>0) {
1390 - $this->m_userMsgs[$user_id] .= ', ';
1391 - $this->m_userHtmlPropMsgs[$user_id] .= ', ';
1392 - }
1393 - $this->m_userMsgs[$user_id] .= $notify_name;
1394 - $this->m_userHtmlPropMsgs[$user_id] .= '<b>'.htmlspecialchars($notify_name).'</b>';
1395 - $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
1396 - $this->m_notifyHtmlPropMsgs[$notify_id] .= $propHint;
1397 - $idx++;
1398 -
1399 - $this->m_userNMs[$user_id][] = $notify_id;
1400 - }
1401 - $this->m_userMsgs[$user_id] .= ' ).';
1402 - $this->m_userHtmlPropMsgs[$user_id] .= "</td></tr>";
1403 - }
1404 - }
1405 - }
1406 - // get possible subquery
1407 - $this->m_subQueryNotify = array();
1408 - $queries = $sStore->getPossibleQuery($this->m_info);
1409 - if(is_array($queries)) {
1410 - foreach($queries[1] as $notify_id=>$notify) {
1411 - $this->m_subQueryNotify[$notify_id] = $notify;
1412 - }
1413 - }
1414 -
1415 - $this->m_info = $info;
1416 - }
1417 -
1418 - // this will cost time, think we can update monitor in a single thread, like Job
1419 - public function updateNotifyMonitor() {
1420 - $page_id = $this->m_title->getArticleID();
1421 - if(($page_id == 0) || ($this->m_title->getNamespace() != NS_MAIN)) {
1422 - return;
1423 - }
1424 - $sStore = NMStorage::getDatabase();
1425 - $queries = $sStore->getPossibleQuery($this->m_info);
1426 - if(!is_array($queries)) {
1427 - return;
1428 - }
1429 - // get monitored query
1430 - $main_queries = $sStore->getMonitoredQuery($page_id);
1431 - foreach($queries[0] as $notify_id=>$notify) {
1432 - $main_queries[$notify_id] = $notify;
1433 - }
1434 -
1435 - // begin notify query on main query
1436 - $page_name = $this->m_title->getText().' ('.$this->m_title->getFullUrl().')';
1437 - $page_html_name = '<a href="'.$this->m_title->getFullUrl().'">'.htmlspecialchars($this->m_title->getText()).'</a>';
1438 -
1439 - foreach($main_queries as $notify_id=>$notify) {
1440 - $sStore->getNotifyInMainQuery($page_id, $notify_id, $notify['sql'], $notify['hierarchy'], $match, $monitoring);
1441 - if((!$monitoring) && $match) {
1442 - $this->m_userMsgs[$notify['user_id']] .= "\r\nPage $page_name matches NotifyMe '$notify[name]' now.";
1443 - $hint = "Page $page_html_name matches \"<b>".htmlspecialchars($notify[name])."</b>\" now.<br/>";
1444 - $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
1445 - $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
1446 - $this->m_newMonitor[] = array('notify_id'=>$notify_id, 'page_id'=>$page_id);
1447 - } else if((!$match) && $monitoring) {
1448 - $this->m_userMsgs[$notify['user_id']] .= "\r\nPage $page_name does not match NotifyMe '$notify[name]' now.";
1449 - $hint = "Page $page_html_name does not match \"<b>".htmlspecialchars($notify[name])."</b>\" now.<br/>";
1450 - $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
1451 - $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
1452 - $this->m_removeMonitored[] = array('notify_id'=>$notify_id, 'page_id'=>$page_id);
1453 - }
1454 - $this->m_userNMs[$notify['user_id']][] = $notify_id;
1455 - }
1456 - // begin notify query on sub query, should go through all pages
1457 - foreach($queries[1] as $notify_id=>$notify) {
1458 - $this->m_subQueryNotify[$notify_id] = $notify;
1459 - }
1460 - foreach($this->m_subQueryNotify as $notify_id=>$notify) {
1461 - $res = $sStore->getNotifyInSubquery($notify_id, $notify['sql'], $notify['hierarchy']);
1462 -
1463 - $no_matches = array_diff($res['monitoring'], $res['match']);
1464 - $matches = array_diff($res['match'], $res['monitoring']);
1465 - foreach($matches as $pid) {
1466 - $pt = $sStore->getPageTitle($pid);
1467 - if(!$pt) {
1468 - continue;
1469 - }
1470 - $t = Title::makeTitle( NS_MAIN, $pt->page_title );
1471 - $p_name = $t->getText().' ('.$t->getFullUrl().')';
1472 - $p_html_name = '<a href="'.$t->getFullUrl().'">'.htmlspecialchars($t->getText()).'</a>';
1473 -
1474 - $this->m_userMsgs[$notify['user_id']] .= "\r\nSub page $page_name changed, $p_name matches NotifyMe '$notify[name]' now.";
1475 - $hint = "Sub page $page_html_name changed, $p_html_name matches \"<b>".htmlspecialchars($notify[name])."</b>\" now.<br/>";
1476 - $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
1477 - $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
1478 - $this->m_newMonitor[] = array('notify_id'=>$notify_id, 'page_id'=>$pid);
1479 -
1480 - $this->m_userNMs[$notify['user_id']][] = $notify_id;
1481 - }
1482 - foreach($no_matches as $pid) {
1483 - $pt = $sStore->getPageTitle($pid);
1484 - if(!$pt) {
1485 - continue;
1486 - }
1487 - $t = Title::makeTitle( NS_MAIN, $pt->page_title );
1488 - $p_name = $t->getText().' ('.$t->getFullUrl().')';
1489 - $p_html_name = '<a href="'.$t->getFullUrl().'">'.htmlspecialchars($t->getText()).'</a>';
1490 -
1491 - $this->m_userMsgs[$notify['user_id']] .= "\r\nSub page $page_name changed, page $p_name does not match NotifyMe '$notify[name]' now.";
1492 - $hint = "Sub page $page_html_name changed, $p_html_name does not match \"<b>".htmlspecialchars($notify[name])."</b>\" now.<br/>";
1493 - $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
1494 - $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
1495 - $this->m_removeMonitored[] = array('notify_id'=>$notify_id, 'page_id'=>$pid);
1496 -
1497 - $this->m_userNMs[$notify['user_id']][] = $notify_id;
1498 - }
1499 - }
1500 -
1501 - $sStore->removeNotifyMonitor($this->m_removeMonitored);
1502 - $sStore->addNotifyMonitor($this->m_newMonitor);
1503 - }
1504 - private function applyStyle($html) {
1505 - $html = str_replace("class=\"smwtable\"", "style=\"background-color: #EEEEFF;\"", $html);
1506 - $html = str_replace("<th", "<th style=\"background-color: #EEEEFF;text-align: left;\"", $html);
1507 - $html = str_replace("<td", "<td style=\"background-color: #FFFFFF;padding: 1px;padding-left: 5px;padding-right: 5px;text-align: left;vertical-align: top;\"", $html);
1508 - return $html;
1509 - }
1510 - public function notifyUsers() {
1511 - global $wgSitename, $wgSMTP, $wgEmergencyContact, $wgEnotifyMeJob;
1512 - $sStore = NMStorage::getDatabase();
1513 -
1514 - $nm_send_jobs = array();
1515 - $id = 0;
1516 -
1517 - if(count($this->m_notifyHtmlMsgs) > 0) {
1518 - $notifications = $sStore->getNotifyMe(array_keys($this->m_notifyHtmlMsgs));
1519 - }
1520 - $html_style = '';
1521 -//<style>
1522 -//table.smwtable{background-color: #EEEEFF;}
1523 -//table.smwtable th{background-color: #EEEEFF;text-align: left;}
1524 -//table.smwtable td{background-color: #FFFFFF;padding: 1px;padding-left: 5px;padding-right: 5px;text-align: left;vertical-align: top;}
1525 -//table.smwtable tr.smwfooter td{font-size: 90%;line-height: 1;background-color: #EEEEFF;padding: 0px;padding-left: 5px;padding-right: 5px;text-align: right;vertical-align: top;}
1526 -//</style>';
1527 - $html_showall = array();
1528 - foreach($this->m_notifyHtmlMsgs as $notify_id=>$msg) {
1529 - $html_msg = $html_style;
1530 - $showing_all = false;
1531 - if(isset($notifications[$notify_id]) && $notifications[$notify_id]['show_all']) {
1532 - SMWQueryProcessor::processFunctionParams(explode("\n", $notifications[$notify_id]['query']), $querystring, $params, $printouts);
1533 -
1534 - $format = 'auto';
1535 - if (array_key_exists('format', $params)) {
1536 - $format = strtolower(trim($params['format']));
1537 - global $smwgResultFormats;
1538 - if ( !array_key_exists($format, $smwgResultFormats) ) {
1539 - $format = 'auto';
1540 - }
1541 - }
1542 - $query = SMWQueryProcessor::createQuery($querystring, $params, SMWQueryProcessor::INLINE_QUERY, $format, $printouts);
1543 - $res = smwfGetStore()->getQueryResult($query);
1544 - $printer = SMWQueryProcessor::getResultPrinter($format, SMWQueryProcessor::INLINE_QUERY, $res);
1545 - $result = $printer->getResult($res, $params, SMW_OUTPUT_HTML);
1546 - $html_msg .= $result . '<br/>';
1547 - $html_showall[$notify_id] = array ('name'=>$notifications[$notify_id]['name'], 'html'=>$result);
1548 -
1549 - $showing_all = true;
1550 - $link = $res->getQueryLink()->getURL();
1551 - }
1552 - global $smwgNMHideDiffWhenShowAll;
1553 - if(!($smwgNMHideDiffWhenShowAll && $showing_all)) {
1554 - $html_msg .= '<p><b>Semantic changes from last revision:</b><br/><span style="font-size: 8pt;">'.$this->m_notifyHtmlMsgs[$notify_id].'</span></P>';
1555 - if(isset($this->m_notifyHtmlPropMsgs[$notify_id])) {
1556 - $html_msg .= "<P><table class=\"smwtable\"><tr><th>Semantic type</th><th>Name</th><th>Action</th><th>Deleted</th><th>Added</th></tr>";
1557 - $html_msg .= $this->m_notifyHtmlPropMsgs[$notify_id];
1558 - $html_msg .= "</table></P>";
1559 - }
1560 - }
1561 - if($showing_all) {
1562 - $id = $sStore->addNotifyRSS('nid', $notify_id, "All current items, ".date('Y-m-d H:i:s', time()), $this->applyStyle($html_msg), $link);
1563 - } else {
1564 - $id = $sStore->addNotifyRSS('nid', $notify_id, $this->m_title->getText(), $this->applyStyle($html_msg));
1565 - }
1566 - }
1567 - foreach($this->m_userMsgs as $user_id=>$msg) {
1568 - // generate RSS items
1569 - $html_msg = $html_style;
1570 - foreach(array_unique($this->m_userNMs[$user_id]) as $showall_nid) {
1571 - if(isset($html_showall[$showall_nid])) {
1572 - $html_msg .= "<br/>All current items for \"<b>".$html_showall[$showall_nid]['name']."</b>\":<br/>";
1573 - $html_msg .= $html_showall[$showall_nid]['html'] . '<br/>';
1574 - }
1575 - }
1576 -
1577 - $html_msg .= '<p><b>Semantic changes from last revision:</b><br/><span style="font-size: 8pt;">'.$this->m_userHtmlNMMsgs[$user_id].'</span></P>';
1578 - if(isset($this->m_userHtmlPropMsgs[$user_id])) {
1579 - $html_msg .= "<P><table class=\"smwtable\"><tr><th>Semantic type</th><th>Name</th><th>Action</th><th>Deleted</th><th>Added</th></tr>";
1580 - $html_msg .= $this->m_userHtmlPropMsgs[$user_id];
1581 - $html_msg .= "</table></P>";
1582 - }
1583 -
1584 - $id = $sStore->addNotifyRSS('uid', $user_id, $this->m_title->getText(), $this->applyStyle($html_msg));
1585 -
1586 - if($wgEnotifyMeJob) {
1587 - // send notifications by mail
1588 - $user_info = $sStore->getUserInfo($user_id);
1589 - if(($user_info->user_email != '') && $this->getUserNMOption($user_info->user_options)) {
1590 - $name = (($user_info->user_real_name=='')?$user_info->user_name:$user_info->user_real_name);
1591 - $body = "Dear Mr./Mrs. $name,\r\n$msg".
1592 - "\r\n\r\nSincerely yours,\r\nSMW NotifyMe Bot";
1593 -
1594 - $params = array('to' => new MailAddress($user_info->user_email, $name),
1595 - 'from' => new MailAddress($wgEmergencyContact, 'Admin'),
1596 - 'subj' => 'New SMW Notification comes, from '.$wgSitename,
1597 - 'body' => $body,
1598 - 'replyto' => new MailAddress($wgEmergencyContact, 'Admin'));
1599 -
1600 - $nm_send_jobs[] = new SMW_NMSendMailJob($this->m_title, $params);
1601 - }
1602 - }
1603 - }
1604 -
1605 - if( $wgEnotifyMeJob ) {
1606 - if( count( $nm_send_jobs ) ) {
1607 - Job :: batchInsert($nm_send_jobs);
1608 - }
1609 - } else {
1610 - global $phpInterpreter;
1611 - if (!isset($phpInterpreter)) {
1612 - // if $phpInterpreter is not set, assume it is in search path
1613 - // if not, starting of bot will FAIL!
1614 - $phpInterpreter = "php";
1615 - }
1616 - // copy from SMW_GardeningBot.php
1617 - ob_start();
1618 - phpinfo();
1619 - $info = ob_get_contents();
1620 - ob_end_clean();
1621 - //Get Systemstring
1622 - preg_match('!\nSystem(.*?)\n!is',strip_tags($info),$ma);
1623 - //Check if it consists 'windows' as string
1624 - preg_match('/[Ww]indows/',$ma[1],$os);
1625 - global $smwgNMIP ;
1626 - if($os[0]=='' && $os[0]==null ) {
1627 -
1628 - //FIXME: $runCommand must allow whitespaces in paths too
1629 - $runCommand = "$phpInterpreter -q $smwgNMIP/specials/SMWNotifyMe/SMW_NMSendMailAsync.php";
1630 - //TODO: test async code for linux.
1631 - //low prio
1632 - $nullResult = `$runCommand > /dev/null &`;
1633 - }
1634 - else //windowze
1635 - {
1636 - $runCommand = "\"\"$phpInterpreter\" -q \"$smwgNMIP/specials/SMWNotifyMe/SMW_NMSendMailAsync.php\"\"";
1637 - $wshShell = new COM("WScript.Shell");
1638 - $runCommand = "cmd /C ".$runCommand;
1639 -
1640 - $oExec = $wshShell->Run($runCommand, 7, false);
1641 - }
1642 - }
1643 - }
1644 - // copy from user class
1645 - function getUserNMOption( $str ) {
1646 - $options = array();
1647 - $a = explode( "\n", $str );
1648 - foreach ( $a as $s ) {
1649 - $m = array();
1650 - if ( preg_match( "/^(.[^=]*)=(.*)$/", $s, $m ) ) {
1651 - $options[$m[1]] = $m[2];
1652 - }
1653 - }
1654 - return $options['enotifyme'];
1655 - }
1656 -}
 2+<?php
 3+/**
 4+ * This file contains a static class for accessing functions to generate and execute
 5+ * notify me semantic queries and to serialise their results.
 6+ *
 7+ * @author dch
 8+ */
 9+
 10+global $smwgIP, $smwgNMIP ;
 11+require_once( $smwgIP . '/includes/storage/SMW_Store.php' );
 12+require_once( $smwgNMIP . '/includes/SMW_NMStorage.php' );
 13+
 14+/**
 15+ * Static class for accessing functions to generate and execute semantic queries
 16+ * and to serialise their results.
 17+ */
 18+class SMWNotifyProcessor {
 19+
 20+ static public function getNotifications() {
 21+ $sStore = NMStorage::getDatabase();
 22+ global $wgUser;
 23+ $user_id = $wgUser->getId();
 24+
 25+ $notifications = $sStore->getNotifications( $user_id );
 26+
 27+ return $notifications;
 28+ }
 29+
 30+ /**
 31+ * Enable a NotifyMe with specified id and querystring
 32+ *
 33+ * used for inline query only
 34+ */
 35+ static public function enableNotify( $notify_id, $querystring, &$msg = NULL ) {
 36+ wfProfileIn( 'SMWNotifyProcessor::enableNotify (SMW)' );
 37+
 38+ $sStore = NMStorage::getDatabase();
 39+ global $smwgQDefaultNamespaces;
 40+
 41+ SMWQueryProcessor::processFunctionParams( SMWNotifyProcessor::getQueryRawParams( $querystring ), $querystring, $params, $printouts );
 42+ $relatedArticles = array();
 43+ foreach ( $printouts as $po ) {
 44+ if ( $po == $params['sort'] ) $sorted = true;
 45+ $printoutArticles[] = array(
 46+ 'namespace' => SMW_NS_PROPERTY,
 47+ 'title' => Title::makeTitle( SMW_NS_PROPERTY, $po->getText() )->getDBkey() );
 48+ }
 49+ if ( !$sorted && isset( $params['sort'] ) ) {
 50+ $printoutArticles[] = array(
 51+ 'namespace' => SMW_NS_PROPERTY,
 52+ 'title' => Title::makeTitle( SMW_NS_PROPERTY, $params['sort'] )->getDBkey() );
 53+ }
 54+
 55+ $qp = new SMWNotifyParser( $notify_id, $printoutArticles );
 56+ $qp->setDefaultNamespaces( $smwgQDefaultNamespaces );
 57+ $desc = $qp->getQueryDescription( $querystring );
 58+
 59+ if ( !$qp->m_result ) {
 60+ $qp->m_errors[] = "The category / instance / property page in query may not exists.";
 61+ }
 62+
 63+ if ( isset( $msg ) && $qp->hasSubquery() ) {
 64+ $msg .= "\nThe query contains subquery, which may affect the precision of notifications.";
 65+ }
 66+
 67+ $query = new SMWQuery( $desc, true, false );
 68+ $query->setQueryString( $querystring );
 69+ $query->addErrors( $qp->getErrors() ); // keep parsing errors for later output
 70+
 71+ $res = $sStore->getNMQueryResult( $query );
 72+
 73+ if ( count( $query->getErrors() ) > 0 ) {
 74+ if ( isset( $msg ) ) {
 75+ $msg .= "\n\n" . implode( '\n', $query->getErrors() ) . "\n\nYou can enable the query in NotifyMe manager later.";
 76+ }
 77+ $sStore->disableNotifyState( $notify_id );
 78+ wfProfileOut( 'SMWNotifyProcessor::enableNotify (SMW)' );
 79+ return false;
 80+ }
 81+
 82+ $sStore->updateNMSql( $notify_id, $res['sql'], $res['tmp_hierarchy'] );
 83+ if ( count( $res['page_ids'] ) > 0 ) {
 84+ $add_monitor = array();
 85+ foreach ( $res['page_ids'] as $page_id ) {
 86+ $add_monitor[] = array( 'notify_id' => $notify_id, 'page_id' => $page_id );
 87+ }
 88+ $sStore->addNotifyMonitor( $add_monitor );
 89+ }
 90+ $sStore->updateNotifyState( $notify_id, 1 );
 91+ wfProfileOut( 'SMWNotifyProcessor::enableNotify (SMW)' );
 92+
 93+ return true;
 94+ }
 95+
 96+ static public function getQueryRawParams( $querystring ) {
 97+ // read query with printouts and (possibly) other parameters like sort, order, limit, etc...
 98+ $pos = strpos( $querystring, "|?" );
 99+ if ( $pos > 0 ) {
 100+ $rawparams[] = trim( substr( $querystring, 0, $pos ) );
 101+ $ps = explode( "|?", trim( substr( $querystring, $pos + 2 ) ) );
 102+ foreach ( $ps as $param ) {
 103+ $rawparams[] = "?" . trim( $param );
 104+ }
 105+ } else {
 106+ $ps = preg_split( '/[^\|]{1}\|{1}(?!\|)/s', $querystring );
 107+ if ( count( $ps ) > 1 ) {
 108+ // last char of query condition is missing (matched with [^\|]{1}) therefore copy from original
 109+ $rawparams[] = trim( substr( $querystring, 0, strlen( $ps[0] ) + 1 ) );
 110+ array_shift( $ps ); // remove the query condition
 111+ // add other params for formating etc.
 112+ foreach ( $ps as $param )
 113+ $rawparams[] = trim( $param );
 114+ } // no single pipe found, no params specified in query
 115+ else $rawparams[] = trim( $querystring );
 116+ }
 117+ $rawparams[] = "format=table";
 118+ $rawparams[] = "link=all";
 119+ return $rawparams;
 120+ }
 121+
 122+ static public function addNotify( $rawquery, $name, $rep_all, $show_all, $delegate ) {
 123+ global $wgTitle;
 124+ // Take care at least of some templates -- for better template support use #ask
 125+ $parser = new Parser();
 126+ $parserOptions = new ParserOptions();
 127+ $parser->startExternalParse( $wgTitle, $parserOptions, OT_HTML );
 128+ $rawquery = $parser->transformMsg( $rawquery, $parserOptions );
 129+
 130+ wfProfileIn( 'SMWNotifyProcessor::createNotify (SMW)' );
 131+ $sStore = NMStorage::getDatabase();
 132+ global $wgUser;
 133+ $user_id = $wgUser->getId();
 134+ if ( $user_id == 0 ) {
 135+ wfProfileOut( 'SMWNotifyProcessor::createNotify (SMW)' );
 136+ return "You have not logged in yet, please log in and retry again. Thanks.";
 137+ }
 138+
 139+ // check notify query first, use QueryParser from SMW
 140+ SMWQueryProcessor::processFunctionParams( SMWNotifyProcessor::getQueryRawParams( $rawquery ), $querystring, $params, $printouts );
 141+
 142+ $qp = new SMWQueryParser();
 143+ $qp->setDefaultNamespaces( $smwgQDefaultNamespaces );
 144+ $desc = $qp->getQueryDescription( $querystring );
 145+
 146+ if ( count( $qp->getErrors() ) > 0 ) {
 147+ wfProfileOut( 'SMWNotifyProcessor::createNotify (SMW)' );
 148+ return "Notify create failed!\n\n" . implode( '\n', $qp->getErrors() ) . "\n\nPlease check the query and retry again";
 149+ }
 150+
 151+ $notify_id = $sStore->addNotifyQuery( $user_id, $rawquery, $name, $rep_all, $show_all, $delegate );
 152+ if ( $notify_id == 0 ) {
 153+ wfProfileOut( 'SMWNotifyProcessor::createNotify (SMW)' );
 154+ return "Fail to save query. Please retry later...";
 155+ }
 156+ wfProfileOut( 'SMWNotifyProcessor::createNotify (SMW)' );
 157+
 158+ wfProfileIn( 'SMWNotifyProcessor::enableNotify (SMW)' );
 159+ $msg = '';
 160+ $result = SMWNotifyProcessor::enableNotify( $notify_id, $rawquery, $msg );
 161+ wfProfileOut( 'SMWNotifyProcessor::enableNotify (SMW)' );
 162+ return "1" . ( $result ? "1":"0" ) . "$notify_id,$msg";
 163+ }
 164+
 165+ static public function updateStates( $notify_ids ) {
 166+ wfProfileIn( 'SMWNotifyProcessor::updateStates (SMW)' );
 167+
 168+ $notifications = SMWNotifyProcessor::getNotifications();
 169+ if ( $notifications == null || !is_array( $notifications ) ) {
 170+ return "No notifications available.";
 171+ }
 172+ $result = true;
 173+ $idx = 0;
 174+ $count = count( $notify_ids ) - 1;
 175+ $msg = '';
 176+ $errs = '';
 177+ $sStore = NMStorage::getDatabase();
 178+ foreach ( $notifications as $row ) {
 179+ if ( ( $idx < $count ) && ( $notify_ids[$idx] == $row['notify_id'] ) ) {
 180+ if ( $row['enable'] == 0 ) {
 181+ $m = '';
 182+ $r = SMWNotifyProcessor::enableNotify( $row['notify_id'], $row['query'], $m );
 183+ if ( !$r ) {
 184+ $msg .= "NotifyMe : '" . $row['name'] . "'$m\n\n";
 185+ $errs .= $row['notify_id'] . ",";
 186+ $result = false;
 187+ }
 188+ }
 189+ $idx ++;
 190+ } else {
 191+ if ( $row['enable'] == 1 ) {
 192+ $result = $sStore->disableNotifyState( $row['notify_id'] );
 193+ }
 194+ }
 195+ }
 196+
 197+ wfProfileOut( 'SMWNotifyProcessor::updateStates (SMW)' );
 198+ return $result ? "States updated successfully!" : "0$errs|\n\n$msg";
 199+ }
 200+
 201+ static public function updateDelegates( $delegates ) {
 202+ wfProfileIn( 'SMWNotifyProcessor::updateDelegates (SMW)' );
 203+
 204+ $notifications = SMWNotifyProcessor::getNotifications();
 205+ if ( $notifications == null || !is_array( $notifications ) ) {
 206+ return "No notifications available.";
 207+ }
 208+ $result = true;
 209+ $idx = 0;
 210+ $s = explode( ':', $delegates[$idx], 2 );
 211+ $count = count( $delegates ) - 1;
 212+ $sStore = NMStorage::getDatabase();
 213+ foreach ( $notifications as $row ) {
 214+ if ( ( $idx < $count ) && ( $s[0] == $row['notify_id'] ) ) {
 215+ $result = $sStore->updateDelegate( $row['notify_id'], $s[1] );
 216+ $idx ++;
 217+ $s = explode( ':', $delegates[$idx], 2 );
 218+ } else {
 219+ $result = $sStore->updateDelegate( $row['notify_id'], '' );
 220+ }
 221+ if ( !$result ) break;
 222+ }
 223+
 224+ wfProfileOut( 'SMWNotifyProcessor::updateDelegates (SMW)' );
 225+ return $result ? "Delegates updated successfully!" : "Delegates updated error!";
 226+ }
 227+
 228+ static public function refreshNotifyMe() {
 229+ wfProfileIn( 'SMWNotifyProcessor::refreshNotifyMe (SMW)' );
 230+ $notifications = NMStorage::getDatabase()->getAllNotifications();
 231+ foreach ( $notifications as $row ) {
 232+ if ( $row['enable'] ) {
 233+ $result = SMWNotifyProcessor::enableNotify( $row['notify_id'], $row['query'] );
 234+ }
 235+ }
 236+ wfProfileOut( 'SMWNotifyProcessor::refreshNotifyMe (SMW)' );
 237+ }
 238+
 239+ static public function updateReportAll( $notify_ids ) {
 240+ wfProfileIn( 'SMWNotifyProcessor::updateStates (SMW)' );
 241+
 242+ $notifications = SMWNotifyProcessor::getNotifications();
 243+ if ( $notifications == null || !is_array( $notifications ) ) {
 244+ return "No notifications available.";
 245+ }
 246+ $result = true;
 247+ $idx = 0;
 248+ $count = count( $notify_ids ) - 1;
 249+ $sStore = NMStorage::getDatabase();
 250+ foreach ( $notifications as $row ) {
 251+ if ( ( $idx < $count ) && ( $notify_ids[$idx] == $row['notify_id'] ) ) {
 252+ if ( $row['rep_all'] == 0 ) {
 253+ $result = $sStore->updateNotifyReportAll( $row['notify_id'], 1 );
 254+ }
 255+ $idx ++;
 256+ } else {
 257+ if ( $row['rep_all'] == 1 ) {
 258+ $result = $sStore->updateNotifyReportAll( $row['notify_id'], 0 );
 259+ }
 260+ }
 261+ if ( !$result ) break;
 262+ }
 263+
 264+ wfProfileOut( 'SMWNotifyProcessor::updateStates (SMW)' );
 265+ return $result ? "States updated successfully!" : "States updated error!";
 266+ }
 267+
 268+ static public function updateShowAll( $notify_ids ) {
 269+ wfProfileIn( 'SMWNotifyProcessor::updateStates (SMW)' );
 270+
 271+ $notifications = SMWNotifyProcessor::getNotifications();
 272+ if ( $notifications == null || !is_array( $notifications ) ) {
 273+ return "No notifications available.";
 274+ }
 275+ $result = true;
 276+ $idx = 0;
 277+ $count = count( $notify_ids ) - 1;
 278+ $sStore = NMStorage::getDatabase();
 279+ foreach ( $notifications as $row ) {
 280+ if ( ( $idx < $count ) && ( $notify_ids[$idx] == $row['notify_id'] ) ) {
 281+ if ( $row['show_all'] == 0 ) {
 282+ $result = $sStore->updateNotifyShowAll( $row['notify_id'], 1 );
 283+ }
 284+ $idx ++;
 285+ } else {
 286+ if ( $row['show_all'] == 1 ) {
 287+ $result = $sStore->updateNotifyShowAll( $row['notify_id'], 0 );
 288+ }
 289+ }
 290+ if ( !$result ) break;
 291+ }
 292+
 293+ wfProfileOut( 'SMWNotifyProcessor::updateStates (SMW)' );
 294+ return $result ? "States updated successfully!" : "States updated error!";
 295+ }
 296+
 297+ static public function delNotify( $notify_ids ) {
 298+ wfProfileIn( 'SMWNotifyProcessor::delNotify (SMW)' );
 299+ $sStore = NMStorage::getDatabase();
 300+ $result = $sStore->removeNotifyQuery( $notify_ids );
 301+ wfProfileOut( 'SMWNotifyProcessor::delNotify (SMW)' );
 302+ return $result ? "Notification(s) deleted successfully!" : "Notification(s) deleted error!";
 303+ }
 304+
 305+ static protected $notifyJobs = array();
 306+ static public function prepareArticleSave( $title ) {
 307+ $page_id = $title->getArticleID();
 308+ if ( $page_id == 0 ) {
 309+ return;
 310+ }
 311+ $updates = SMWNotifyProcessor::$notifyJobs[$page_id];
 312+ if ( empty( $updates ) ) {
 313+ SMWNotifyProcessor::$notifyJobs[$page_id] = new SMWNotifyUpdate( $title );
 314+ }
 315+ }
 316+ static public function articleSavedComplete( $title ) {
 317+ $page_id = $title->getArticleID();
 318+ if ( $page_id == 0 ) {
 319+ return;
 320+ }
 321+ $updates = SMWNotifyProcessor::$notifyJobs[$page_id];
 322+ if ( empty( $updates ) ) {
 323+ SMWNotifyProcessor::$notifyJobs[$page_id] = new SMWNotifyUpdate( $title );
 324+ $updates = SMWNotifyProcessor::$notifyJobs[$page_id];
 325+ } else {
 326+ $updates->executeNotifyUpdate();
 327+ }
 328+ $updates->updateNotifyMonitor();
 329+ $updates->notifyUsers();
 330+ unset( SMWNotifyProcessor::$notifyJobs[$page_id] );
 331+ }
 332+ static public function articleDelete( $title, $reason ) {
 333+ $page_id = $title->getArticleID();
 334+ if ( $page_id == 0 ) {
 335+ return;
 336+ }
 337+ $updates = new SMWNotifyUpdate( $title );
 338+ $updates->executeNotifyDelete( $reason );
 339+ }
 340+ static public function toInfoId( $type, $subquery, $attr_id ) {
 341+ return base_convert( strval( ( $subquery << 8 ) | $type ), 10, 9 ) . '9' . $attr_id;
 342+ }
 343+ static public function getInfoFromId( $id ) {
 344+ $idx = strpos( $id, '9' );
 345+ $t = intval( base_convert( substr( $id, 0, $idx ), 9, 10 ) );
 346+ return array(
 347+ 'type' => $t&0xFF,
 348+ 'subquery' => $t >> 8,
 349+ 'attr_id' => intval( substr( $id, $idx + 1 ) )
 350+ );
 351+ }
 352+
 353+}
 354+
 355+// based on SMW_QueryProcessor.php (v 1.4.2)
 356+/**
 357+ * Objects of this class are in charge of parsing a query string in order
 358+ * to create an SMWDescription. The class and methods are not static in order
 359+ * to more cleanly store the intermediate state and progress of the parser.
 360+ */
 361+class SMWNotifyParser {
 362+
 363+ protected $m_sepstack; // list of open blocks ("parentheses") that need closing at current step
 364+ protected $m_curstring; // remaining string to be parsed (parsing eats query string from the front)
 365+ var $m_errors; // empty array if all went right, array of strings otherwise
 366+ protected $m_label; // label of the main query result
 367+ protected $m_defaultns; // description of the default namespace restriction, or NULL if not used
 368+
 369+ protected $m_categoryprefix; // cache label of category namespace . ':'
 370+ protected $m_conceptprefix; // cache label of concept namespace . ':'
 371+ protected $m_queryfeatures; // query features to be supported, format similar to $smwgQFeatures
 372+
 373+ // added by dch
 374+ protected $m_notify_id;
 375+ protected $m_subquery;
 376+ protected $m_printoutArticles;
 377+ public $m_result;
 378+
 379+ // modified by dch
 380+ public function SMWNotifyParser( $notify_id, $printoutArticles, $queryfeatures = false ) {
 381+ $this->m_notify_id = $notify_id;
 382+ $this->m_printoutArticles = $printoutArticles;
 383+ $this->m_result = true;
 384+
 385+ global $wgContLang, $smwgQFeatures;
 386+ $this->m_categoryprefix = $wgContLang->getNsText( NS_CATEGORY ) . ':';
 387+ $this->m_conceptprefix = $wgContLang->getNsText( SMW_NS_CONCEPT ) . ':';
 388+ $this->m_defaultns = NULL;
 389+ $this->m_queryfeatures = $queryfeatures === false ? $smwgQFeatures:$queryfeatures;
 390+ }
 391+
 392+ // added by dch
 393+ public function hasSubquery() {
 394+ return $this->m_subquery > 1;
 395+ }
 396+
 397+ /**
 398+ * Provide an array of namespace constants that are used as default restrictions.
 399+ * If NULL is given, no such default restrictions will be added (faster).
 400+ */
 401+ public function setDefaultNamespaces( $nsarray ) {
 402+ $this->m_defaultns = NULL;
 403+ if ( $nsarray !== NULL ) {
 404+ foreach ( $nsarray as $ns ) {
 405+ $this->m_defaultns = $this->addDescription( $this->m_defaultns, new SMWNamespaceDescription( $ns ), false );
 406+ }
 407+ }
 408+ }
 409+
 410+ /**
 411+ * Compute an SMWDescription from a query string. Returns whatever descriptions could be
 412+ * wrestled from the given string (the most general result being SMWThingDescription if
 413+ * no meaningful condition was extracted).
 414+ */
 415+ public function getQueryDescription( $querystring ) {
 416+ wfProfileIn( 'SMWNotifyParser::getQueryDescription (SMW)' );
 417+ $this->m_errors = array();
 418+ $this->m_label = '';
 419+ $this->m_curstring = $querystring;
 420+ $this->m_sepstack = array();
 421+ $setNS = false;
 422+
 423+ // added by dch
 424+ $this->m_subquery = 0;
 425+
 426+ $result = $this->getSubqueryDescription( $setNS, $this->m_label );
 427+ if ( !$setNS ) { // add default namespaces if applicable
 428+ $result = $this->addDescription( $this->m_defaultns, $result );
 429+ }
 430+ if ( $result === NULL ) { // parsing went wrong, no default namespaces
 431+ $result = new SMWThingDescription();
 432+ }
 433+ wfProfileOut( 'SMWNotifyParser::getQueryDescription (SMW)' );
 434+ return $result;
 435+ }
 436+
 437+ /**
 438+ * Return array of error messages (possibly empty).
 439+ */
 440+ public function getErrors() {
 441+ return $this->m_errors;
 442+ }
 443+
 444+ /**
 445+ * Return error message or empty string if no error occurred.
 446+ */
 447+ public function getErrorString() {
 448+ return smwfEncodeMessages( $this->m_errors );
 449+ }
 450+
 451+ /**
 452+ * Return label for the results of this query (which
 453+ * might be empty if no such information was passed).
 454+ */
 455+ public function getLabel() {
 456+ return $this->m_label;
 457+ }
 458+
 459+
 460+ /**
 461+ * Compute an SMWDescription for current part of a query, which should
 462+ * be a standalone query (the main query or a subquery enclosed within
 463+ * "\<q\>...\</q\>". Recursively calls similar methods and returns NULL upon error.
 464+ *
 465+ * The call-by-ref parameter $setNS is a boolean. Its input specifies whether
 466+ * the query should set the current default namespace if no namespace restrictions
 467+ * were given. If false, the calling super-query is happy to set the required
 468+ * NS-restrictions by itself if needed. Otherwise the subquery has to impose the defaults.
 469+ * This is so, since outermost queries and subqueries of disjunctions will have to set
 470+ * their own default restrictions.
 471+ *
 472+ * The return value of $setNS specifies whether or not the subquery has a namespace
 473+ * specification in place. This might happen automatically if the query string imposes
 474+ * such restrictions. The return value is important for those callers that otherwise
 475+ * set up their own restrictions.
 476+ *
 477+ * Note that $setNS is no means to switch on or off default namespaces in general,
 478+ * but just controls query generation. For general effect, the default namespaces
 479+ * should be set to NULL.
 480+ *
 481+ * The call-by-ref parameter $label is used to append any label strings found.
 482+ */
 483+ protected function getSubqueryDescription( &$setNS, &$label ) {
 484+ global $smwgQPrintoutLimit;
 485+ wfLoadExtensionMessages( 'SemanticMediaWiki' );
 486+ $conjunction = NULL; // used for the current inner conjunction
 487+ $disjuncts = array(); // (disjunctive) array of subquery conjunctions
 488+ $printrequests = array(); // the printrequests found for this query level
 489+ $hasNamespaces = false; // does the current $conjnuction have its own namespace restrictions?
 490+ $mustSetNS = $setNS; // must ns restrictions be set? (may become true even if $setNS is false)
 491+
 492+ // added by dch
 493+ $subquery = $this->m_subquery;
 494+ if ( $subquery == 0 ) {
 495+ $relatedArticles = $this->m_printoutArticles;
 496+ } else {
 497+ $relatedArticles = array();
 498+ }
 499+ $this->m_subquery ++;
 500+
 501+ $continue = ( $chunk = $this->readChunk() ) != ''; // skip empty subquery completely, thorwing an error
 502+ while ( $continue ) {
 503+ $setsubNS = false;
 504+ switch ( $chunk ) {
 505+ case '[[': // start new link block
 506+ // modified by dch
 507+ $ld = $this->getLinkDescription( $setsubNS, $label, $relatedArticles );
 508+
 509+ if ( $ld instanceof SMWPrintRequest ) {
 510+ $printrequests[] = $ld;
 511+ } elseif ( $ld instanceof SMWDescription ) {
 512+ $conjunction = $this->addDescription( $conjunction, $ld );
 513+ }
 514+ break;
 515+ case '<q>': // enter new subquery, currently irrelevant but possible
 516+ $this->pushDelimiter( '</q>' );
 517+ $conjunction = $this->addDescription( $conjunction, $this->getSubqueryDescription( $setsubNS, $label ) );
 518+ // / TODO: print requests from subqueries currently are ignored, should be moved down
 519+ break;
 520+ case 'OR': case '||': case '': case '</q>': // finish disjunction and maybe subquery
 521+ if ( $this->m_defaultns !== NULL ) { // possibly add namespace restrictions
 522+ if ( $hasNamespaces && !$mustSetNS ) {
 523+ // add ns restrictions to all earlier conjunctions (all of which did not have them yet)
 524+ $mustSetNS = true; // enforce NS restrictions from now on
 525+ $newdisjuncts = array();
 526+ foreach ( $disjuncts as $conj ) {
 527+ $newdisjuncts[] = $this->addDescription( $conj, $this->m_defaultns );
 528+ }
 529+ $disjuncts = $newdisjuncts;
 530+ } elseif ( !$hasNamespaces && $mustSetNS ) {
 531+ // add ns restriction to current result
 532+ $conjunction = $this->addDescription( $conjunction, $this->m_defaultns );
 533+ }
 534+ }
 535+ $disjuncts[] = $conjunction;
 536+ // start anew
 537+ $conjunction = NULL;
 538+ $hasNamespaces = false;
 539+ // finish subquery?
 540+ if ( $chunk == '</q>' ) {
 541+ if ( $this->popDelimiter( '</q>' ) ) {
 542+ $continue = false; // leave the loop
 543+ } else {
 544+ $this->m_errors[] = wfMsgForContent( 'smw_toomanyclosing', $chunk );
 545+ return NULL;
 546+ }
 547+ } elseif ( $chunk == '' ) {
 548+ $continue = false;
 549+ }
 550+ break;
 551+ case '+': // "... AND true" (ignore)
 552+ break;
 553+ default: // error: unexpected $chunk
 554+ $this->m_errors[] = wfMsgForContent( 'smw_unexpectedpart', $chunk );
 555+ // return NULL; // Try to go on, it can only get better ...
 556+ }
 557+ if ( $setsubNS ) { // namespace restrictions encountered in current conjunct
 558+ $hasNamespaces = true;
 559+ }
 560+ if ( $continue ) { // read on only if $continue remained true
 561+ $chunk = $this->readChunk();
 562+ }
 563+ }
 564+
 565+ if ( count( $disjuncts ) > 0 ) { // make disjunctive result
 566+ $result = NULL;
 567+ foreach ( $disjuncts as $d ) {
 568+ if ( $d === NULL ) {
 569+ $this->m_errors[] = wfMsgForContent( 'smw_emptysubquery' );
 570+ $setNS = false;
 571+ return NULL;
 572+ } else {
 573+ $result = $this->addDescription( $result, $d, false );
 574+ }
 575+ }
 576+ } else {
 577+ $this->m_errors[] = wfMsgForContent( 'smw_emptysubquery' );
 578+ $setNS = false;
 579+ return NULL;
 580+ }
 581+ $setNS = $mustSetNS; // NOTE: also false if namespaces were given but no default NS descs are available
 582+
 583+ $prcount = 0;
 584+ foreach ( $printrequests as $pr ) { // add printrequests
 585+ if ( $prcount < $smwgQPrintoutLimit ) {
 586+ $result->addPrintRequest( $pr );
 587+ $prcount++;
 588+ } else {
 589+ $this->m_errors[] = wfMsgForContent( 'smw_overprintoutlimit' );
 590+ break;
 591+ }
 592+ }
 593+
 594+ // added by dch
 595+ if ( $this->m_result ) {
 596+ $sStore = NMStorage::getDatabase();
 597+ $this->m_result = $sStore->addNotifyRelations( $this->m_notify_id, $relatedArticles, $subquery );
 598+ }
 599+
 600+ return $result;
 601+ }
 602+
 603+ /**
 604+ * Compute an SMWDescription for current part of a query, which should
 605+ * be the content of "[[ ... ]]". Alternatively, if the current syntax
 606+ * specifies a print request, return the print request object.
 607+ * Returns NULL upon error.
 608+ *
 609+ * Parameters $setNS and $label have the same use as in getSubqueryDescription().
 610+ */
 611+ // modified by dch, add $relatedArticles
 612+ protected function getLinkDescription( &$setNS, &$label, &$relatedArticles ) {
 613+ // This method is called when we encountered an opening '[['. The following
 614+ // block could be a Category-statement, fixed object, property statements,
 615+ // or according print statements.
 616+ $chunk = $this->readChunk( '', true, false ); // NOTE: untrimmed, initial " " escapes prop. chains
 617+ if ( ( smwfNormalTitleText( $chunk ) == $this->m_categoryprefix ) || // category statement or
 618+ ( smwfNormalTitleText( $chunk ) == $this->m_conceptprefix ) ) { // concept statement
 619+ return $this->getClassDescription( $setNS, $label, $relatedArticles,
 620+ ( smwfNormalTitleText( $chunk ) == $this->m_categoryprefix ) );
 621+ } else { // fixed subject, namespace restriction, property query, or subquery
 622+ $sep = $this->readChunk( '', false ); // do not consume hit, "look ahead"
 623+ if ( ( $sep == '::' ) || ( $sep == ':=' ) ) {
 624+ if ( $chunk { 0 } != ':' ) { // property statement
 625+ return $this->getPropertyDescription( $chunk, $setNS, $label, $relatedArticles );
 626+ } else { // escaped article description, read part after :: to get full contents
 627+ $chunk .= $this->readChunk( '\[\[|\]\]|\|\||\|' );
 628+ return $this->getArticleDescription( trim( $chunk ), $setNS, $label, $relatedArticles );
 629+ }
 630+ } else { // Fixed article/namespace restriction. $sep should be ]] or ||
 631+ return $this->getArticleDescription( trim( $chunk ), $setNS, $label, $relatedArticles );
 632+ }
 633+ }
 634+ }
 635+
 636+ /**
 637+ * Parse a category description (the part of an inline query that
 638+ * is in between "[[Category:" and the closing "]]" and create a
 639+ * suitable description.
 640+ */
 641+ // modified by dch ,add $relatedArticles
 642+ protected function getClassDescription( &$setNS, &$label, &$relatedArticles, $category = true ) {
 643+ global $smwgSMWBetaCompatible; // * printouts only for this old version
 644+ // note: no subqueries allowed here, inline disjunction allowed, wildcards allowed
 645+ $result = NULL;
 646+ $continue = true;
 647+ while ( $continue ) {
 648+ $chunk = $this->readChunk();
 649+ if ( $chunk == '+' ) {
 650+ // wildcard, ignore for categories (semantically meaningless, everything is in some class)
 651+ } elseif ( ( $chunk == '+' ) && $category && $smwgSMWBetaCompatible ) { // print statement
 652+ $chunk = $this->readChunk( '\]\]|\|' );
 653+ if ( $chunk == '|' ) {
 654+ $printlabel = $this->readChunk( '\]\]' );
 655+ if ( $printlabel != ']]' ) {
 656+ $chunk = $this->readChunk( '\]\]' );
 657+ } else {
 658+ $printlabel = '';
 659+ $chunk = ']]';
 660+ }
 661+ } else {
 662+ global $wgContLang;
 663+ $printlabel = $wgContLang->getNSText( NS_CATEGORY );
 664+ }
 665+ if ( $chunk == ']]' ) {
 666+ return new SMWPrintRequest( SMWPrintRequest::PRINT_CATS, $printlabel );
 667+ } else {
 668+ $this->m_errors[] = wfMsgForContent( 'smw_badprintout' );
 669+ return NULL;
 670+ }
 671+ } else { // assume category/concept title
 672+ // / NOTE: use m_c...prefix to prevent problems with, e.g., [[Category:Template:Test]]
 673+ $class = Title::newFromText( ( $category ? $this->m_categoryprefix:$this->m_conceptprefix ) . $chunk );
 674+ if ( $class !== NULL ) {
 675+ $desc = $category ? new SMWClassDescription( $class ):new SMWConceptDescription( $class );
 676+ $result = $this->addDescription( $result, $desc, false );
 677+ }
 678+
 679+ // added by dch
 680+ if ( $category ) {
 681+ $relatedArticles[] = array(
 682+ 'namespace' => NS_CATEGORY,
 683+ 'title' => $class->getDBkey() );
 684+ }
 685+
 686+ }
 687+ $chunk = $this->readChunk();
 688+ $continue = ( $chunk == '||' ) && $category; // disjunctions only for cateories
 689+ }
 690+
 691+ return $this->finishLinkDescription( $chunk, false, $result, $setNS, $label );
 692+ }
 693+
 694+ /**
 695+ * Parse a property description (the part of an inline query that
 696+ * is in between "[[Some property::" and the closing "]]" and create a
 697+ * suitable description. The "::" is the first chunk on the current
 698+ * string.
 699+ */
 700+ // modified by dch ,add $relatedArticles
 701+ protected function getPropertyDescription( $propertyname, &$setNS, &$label, &$relatedArticles ) {
 702+ global $smwgSMWBetaCompatible; // support for old * printouts of beta
 703+ wfLoadExtensionMessages( 'SemanticMediaWiki' );
 704+ $this->readChunk(); // consume separator ":=" or "::"
 705+ // first process property chain syntax (e.g. "property1.property2::value"):
 706+ if ( $propertyname { 0 } == ' ' ) { // escape
 707+ $propertynames = array( $propertyname );
 708+ } else {
 709+ $propertynames = explode( '.', $propertyname );
 710+ }
 711+ $properties = array();
 712+ $typeid = '_wpg';
 713+ foreach ( $propertynames as $name ) {
 714+ if ( $typeid != '_wpg' ) { // non-final property in chain was no wikipage: not allowed
 715+ $this->m_errors[] = wfMsgForContent( 'smw_valuesubquery', $prevname );
 716+ return NULL; // /TODO: read some more chunks and try to finish [[ ]]
 717+ }
 718+ $property = SMWPropertyValue::makeUserProperty( $name );
 719+ if ( !$property->isValid() ) { // illegal property identifier
 720+ $this->m_errors = array_merge( $this->m_errors, $property->getErrors() );
 721+ return NULL; // /TODO: read some more chunks and try to finish [[ ]]
 722+ }
 723+ $typeid = $property->getTypeID();
 724+ $prevname = $name;
 725+ $properties[] = $property;
 726+
 727+ // added by dch
 728+ $relatedArticles[] = array(
 729+ 'namespace' => SMW_NS_PROPERTY,
 730+ 'title' => $property->getDBkey() );
 731+
 732+ } // /NOTE: after iteration, $property and $typeid correspond to last value
 733+
 734+ $innerdesc = NULL;
 735+ $continue = true;
 736+ while ( $continue ) {
 737+ $chunk = $this->readChunk();
 738+ switch ( $chunk ) {
 739+ case '+': // wildcard, add namespaces for page-type properties
 740+ if ( ( $this->m_defaultns !== NULL ) && ( $typeid == '_wpg' ) ) {
 741+ $innerdesc = $this->addDescription( $innerdesc, $this->m_defaultns, false );
 742+ } else {
 743+ $innerdesc = $this->addDescription( $innerdesc, new SMWThingDescription(), false );
 744+ }
 745+ $chunk = $this->readChunk();
 746+ break;
 747+ case '<q>': // subquery, set default namespaces
 748+ if ( $typeid == '_wpg' ) {
 749+ $this->pushDelimiter( '</q>' );
 750+ $setsubNS = true;
 751+ $sublabel = '';
 752+ $innerdesc = $this->addDescription( $innerdesc, $this->getSubqueryDescription( $setsubNS, $sublabel ), false );
 753+ } else { // no subqueries allowed for non-pages
 754+ $this->m_errors[] = wfMsgForContent( 'smw_valuesubquery', end( $propertynames ) );
 755+ $innerdesc = $this->addDescription( $innerdesc, new SMWThingDescription(), false );
 756+ }
 757+ $chunk = $this->readChunk();
 758+ break;
 759+ default: // normal object value or print statement
 760+ // read value(s), possibly with inner [[...]]
 761+ $open = 1;
 762+ $value = $chunk;
 763+ $continue2 = true;
 764+ // read value with inner [[, ]], ||
 765+ while ( ( $open > 0 ) && ( $continue2 ) ) {
 766+ $chunk = $this->readChunk( '\[\[|\]\]|\|\||\|' );
 767+ switch ( $chunk ) {
 768+ case '[[': // open new [[ ]]
 769+ $open++;
 770+ break;
 771+ case ']]': // close [[ ]]
 772+ $open--;
 773+ break;
 774+ case '|': case '||': // terminates only outermost [[ ]]
 775+ if ( $open == 1 ) {
 776+ $open = 0;
 777+ }
 778+ break;
 779+ case '': // /TODO: report error; this is not good right now
 780+ $continue2 = false;
 781+ break;
 782+ }
 783+ if ( $open != 0 ) {
 784+ $value .= $chunk;
 785+ }
 786+ } // /NOTE: at this point, we normally already read one more chunk behind the value
 787+
 788+ if ( $typeid == '__nry' ) { // nary value
 789+ $dv = SMWDataValueFactory::newPropertyObjectValue( $property );
 790+ $dv->acceptQuerySyntax();
 791+ $dv->setUserValue( $value );
 792+ $vl = $dv->getValueList();
 793+ $pm = $dv->getPrintModifier();
 794+ if ( $vl !== NULL ) { // prefer conditions over print statements (only one possible right now)
 795+ $innerdesc = $this->addDescription( $innerdesc, $vl, false );
 796+ } elseif ( $pm !== false ) {
 797+ if ( $chunk == '|' ) {
 798+ $printlabel = $this->readChunk( '\]\]' );
 799+ if ( $printlabel != ']]' ) {
 800+ $chunk = $this->readChunk( '\]\]' );
 801+ } else {
 802+ $printlabel = '';
 803+ $chunk = ']]';
 804+ }
 805+ } else {
 806+ $printlabel = $property->getWikiValue();
 807+ }
 808+ if ( $chunk == ']]' ) {
 809+ return new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, $printlabel, $property, $pm );
 810+ } else {
 811+ $this->m_errors[] = wfMsgForContent( 'smw_badprintout' );
 812+ return NULL;
 813+ }
 814+ }
 815+ } else { // unary value
 816+ $comparator = SMW_CMP_EQ;
 817+ $printmodifier = '';
 818+ SMWNotifyParser::prepareValue( $value, $comparator, $printmodifier );
 819+ if ( ( $value == '*' ) && $smwgSMWBetaCompatible ) {
 820+ if ( $chunk == '|' ) {
 821+ $printlabel = $this->readChunk( '\]\]' );
 822+ if ( $printlabel != ']]' ) {
 823+ $chunk = $this->readChunk( '\]\]' );
 824+ } else {
 825+ $printlabel = '';
 826+ $chunk = ']]';
 827+ }
 828+ } else {
 829+ $printlabel = $property->getWikiValue();
 830+ }
 831+ if ( $chunk == ']]' ) {
 832+ return new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, $printlabel, $property, $printmodifier );
 833+ } else {
 834+ $this->m_errors[] = wfMsgForContent( 'smw_badprintout' );
 835+ return NULL;
 836+ }
 837+ } else {
 838+ $dv = SMWDataValueFactory::newPropertyObjectValue( $property, $value );
 839+ if ( !$dv->isValid() ) {
 840+ $this->m_errors = $this->m_errors + $dv->getErrors();
 841+ $vd = new SMWThingDescription();
 842+ } else {
 843+ $vd = new SMWValueDescription( $dv, $comparator );
 844+ }
 845+ $innerdesc = $this->addDescription( $innerdesc, $vd, false );
 846+ }
 847+ }
 848+ }
 849+ $continue = ( $chunk == '||' );
 850+ }
 851+
 852+ if ( $innerdesc === NULL ) { // make a wildcard search
 853+ if ( ( $this->m_defaultns !== NULL ) && ( $typeid == '_wpg' ) ) {
 854+ $innerdesc = $this->addDescription( $innerdesc, $this->m_defaultns, false );
 855+ } else {
 856+ $innerdesc = $this->addDescription( $innerdesc, new SMWThingDescription(), false );
 857+ }
 858+ $this->m_errors[] = wfMsgForContent( 'smw_propvalueproblem', $property->getWikiValue() );
 859+ }
 860+ $properties = array_reverse( $properties );
 861+ foreach ( $properties as $property ) {
 862+ $innerdesc = new SMWSomeProperty( $property, $innerdesc );
 863+ }
 864+ $result = $innerdesc;
 865+ return $this->finishLinkDescription( $chunk, false, $result, $setNS, $label );
 866+ }
 867+
 868+
 869+ /**
 870+ * Prepare a single value string, possibly extracting comparators and
 871+ * printmodifier. $value is changed to consist only of the remaining
 872+ * effective value string, or of "*" for print statements.
 873+ */
 874+ static public function prepareValue( &$value, &$comparator, &$printmodifier ) {
 875+ global $smwgQComparators, $smwgSMWBetaCompatible; // support for old * printouts of beta
 876+ // get print modifier behind *
 877+ if ( $smwgSMWBetaCompatible ) {
 878+ $list = preg_split( '/^\*/', $value, 2 );
 879+ if ( count( $list ) == 2 ) { // hit
 880+ $value = '*';
 881+ $printmodifier = $list[1];
 882+ } else {
 883+ $printmodifier = '';
 884+ }
 885+ if ( $value == '*' ) { // printout statement
 886+ return;
 887+ }
 888+ }
 889+ $list = preg_split( '/^(' . $smwgQComparators . ')/u', $value, 2, PREG_SPLIT_DELIM_CAPTURE );
 890+ $comparator = SMW_CMP_EQ;
 891+ if ( count( $list ) == 3 ) { // initial comparator found ($list[1] should be empty)
 892+ switch ( $list[1] ) {
 893+ case '<':
 894+ $comparator = SMW_CMP_LEQ;
 895+ $value = $list[2];
 896+ break;
 897+ case '>':
 898+ $comparator = SMW_CMP_GEQ;
 899+ $value = $list[2];
 900+ break;
 901+ case '!':
 902+ $comparator = SMW_CMP_NEQ;
 903+ $value = $list[2];
 904+ break;
 905+ case '~':
 906+ $comparator = SMW_CMP_LIKE;
 907+ $value = $list[2];
 908+ break;
 909+ // default: not possible
 910+ }
 911+ }
 912+ }
 913+
 914+ /**
 915+ * Parse an article description (the part of an inline query that
 916+ * is in between "[[" and the closing "]]" assuming it is not specifying
 917+ * a category or property) and create a suitable description.
 918+ * The first chunk behind the "[[" has already been read and is
 919+ * passed as a parameter.
 920+ */
 921+ // modified by dch ,add $relatedArticles
 922+ protected function getArticleDescription( $firstchunk, &$setNS, &$label, &$relatedArticles ) {
 923+ wfLoadExtensionMessages( 'SemanticMediaWiki' );
 924+ $chunk = $firstchunk;
 925+ $result = NULL;
 926+ $continue = true;
 927+ // $innerdesc = NULL;
 928+ while ( $continue ) {
 929+ if ( $chunk == '<q>' ) { // no subqueries of the form [[<q>...</q>]] (not needed)
 930+ $this->m_errors[] = wfMsgForContent( 'smw_misplacedsubquery' );
 931+ return NULL;
 932+ }
 933+ $list = preg_split( '/:/', $chunk, 3 ); // ":Category:Foo" "User:bar" ":baz" ":+"
 934+ if ( ( $list[0] == '' ) && ( count( $list ) == 3 ) ) {
 935+ $list = array_slice( $list, 1 );
 936+ }
 937+ if ( ( count( $list ) == 2 ) && ( $list[1] == '+' ) ) { // try namespace restriction
 938+ global $wgContLang;
 939+ $idx = $wgContLang->getNsIndex( $list[0] );
 940+ if ( $idx !== false ) {
 941+ $result = $this->addDescription( $result, new SMWNamespaceDescription( $idx ), false );
 942+ }
 943+ } else {
 944+ $value = SMWDataValueFactory::newTypeIDValue( '_wpg', $chunk );
 945+ if ( $value->isValid() ) {
 946+ $result = $this->addDescription( $result, new SMWValueDescription( $value ), false );
 947+ // added by dch
 948+ $relatedArticles[] = array(
 949+ 'namespace' => NS_MAIN,
 950+ 'title' => Title::makeTitle( NS_MAIN, $chunk )->getDBkey() );
 951+ }
 952+ }
 953+
 954+ $chunk = $this->readChunk( '\[\[|\]\]|\|\||\|' );
 955+ if ( $chunk == '||' ) {
 956+ $chunk = $this->readChunk( '\[\[|\]\]|\|\||\|' );
 957+ $continue = true;
 958+ } else {
 959+ $continue = false;
 960+ }
 961+ }
 962+
 963+ return $this->finishLinkDescription( $chunk, true, $result, $setNS, $label );
 964+ }
 965+
 966+ protected function finishLinkDescription( $chunk, $hasNamespaces, $result, &$setNS, &$label ) {
 967+ wfLoadExtensionMessages( 'SemanticMediaWiki' );
 968+ if ( $result === NULL ) { // no useful information or concrete error found
 969+ $this->m_errors[] = wfMsgForContent( 'smw_badqueryatom' );
 970+ } elseif ( !$hasNamespaces && $setNS && ( $this->m_defaultns !== NULL ) ) {
 971+ $result = $this->addDescription( $result, $this->m_defaultns );
 972+ $hasNamespaces = true;
 973+ }
 974+ $setNS = $hasNamespaces;
 975+
 976+ // terminate link (assuming that next chunk was read already)
 977+ if ( $chunk == '|' ) {
 978+ $chunk = $this->readChunk( '\]\]' );
 979+ if ( $chunk != ']]' ) {
 980+ $label .= $chunk;
 981+ $chunk = $this->readChunk( '\]\]' );
 982+ } else { // empty label does not add to overall label
 983+ $chunk = ']]';
 984+ }
 985+ }
 986+ if ( $chunk != ']]' ) {
 987+ // What happended? We found some chunk that could not be processed as
 988+ // link content (as in [[Category:Test<q>]]) and there was no label to
 989+ // eat it. Or the closing ]] are just missing entirely.
 990+ if ( $chunk != '' ) {
 991+ $this->m_errors[] = wfMsgForContent( 'smw_misplacedsymbol', htmlspecialchars( $chunk ) );
 992+ // try to find a later closing ]] to finish this misshaped subpart
 993+ $chunk = $this->readChunk( '\]\]' );
 994+ if ( $chunk != ']]' ) {
 995+ $chunk = $this->readChunk( '\]\]' );
 996+ }
 997+ }
 998+ if ( $chunk == '' ) {
 999+ $this->m_errors[] = wfMsgForContent( 'smw_noclosingbrackets' );
 1000+ }
 1001+ }
 1002+ return $result;
 1003+ }
 1004+
 1005+ /**
 1006+ * Get the next unstructured string chunk from the query string.
 1007+ * Chunks are delimited by any of the special strings used in inline queries
 1008+ * (such as [[, ]], <q>, ...). If the string starts with such a delimiter,
 1009+ * this delimiter is returned. Otherwise the first string in front of such a
 1010+ * delimiter is returned.
 1011+ * Trailing and initial spaces are ignored if $trim is true, and chunks
 1012+ * consisting only of spaces are not returned.
 1013+ * If there is no more qurey string left to process, the empty string is
 1014+ * returned (and in no other case).
 1015+ *
 1016+ * The stoppattern can be used to customise the matching, especially in order to
 1017+ * overread certain special symbols.
 1018+ *
 1019+ * $consume specifies whether the returned chunk should be removed from the
 1020+ * query string.
 1021+ */
 1022+ protected function readChunk( $stoppattern = '', $consume = true, $trim = true ) {
 1023+ if ( $stoppattern == '' ) {
 1024+ $stoppattern = '\[\[|\]\]|::|:=|<q>|<\/q>|^' . $this->m_categoryprefix .
 1025+ '|^' . $this->m_conceptprefix . '|\|\||\|';
 1026+ }
 1027+ $chunks = preg_split( '/[\s]*(' . $stoppattern . ')/u', $this->m_curstring, 2, PREG_SPLIT_DELIM_CAPTURE );
 1028+ if ( count( $chunks ) == 1 ) { // no matches anymore, strip spaces and finish
 1029+ if ( $consume ) {
 1030+ $this->m_curstring = '';
 1031+ }
 1032+ return $trim ? trim( $chunks[0] ):$chunks[0];
 1033+ } elseif ( count( $chunks ) == 3 ) { // this should generally happen if count is not 1
 1034+ if ( $chunks[0] == '' ) { // string started with delimiter
 1035+ if ( $consume ) {
 1036+ $this->m_curstring = $chunks[2];
 1037+ }
 1038+ return $trim ? trim( $chunks[1] ):$chunks[1];
 1039+ } else {
 1040+ if ( $consume ) {
 1041+ $this->m_curstring = $chunks[1] . $chunks[2];
 1042+ }
 1043+ return $trim ? trim( $chunks[0] ):$chunks[0];
 1044+ }
 1045+ } else { return false; } // should never happen
 1046+ }
 1047+
 1048+ /**
 1049+ * Enter a new subblock in the query, which must at some time be terminated by the
 1050+ * given $endstring delimiter calling popDelimiter();
 1051+ */
 1052+ protected function pushDelimiter( $endstring ) {
 1053+ array_push( $this->m_sepstack, $endstring );
 1054+ }
 1055+
 1056+ /**
 1057+ * Exit a subblock in the query ending with the given delimiter.
 1058+ * If the delimiter does not match the top-most open block, false
 1059+ * will be returned. Otherwise return true.
 1060+ */
 1061+ protected function popDelimiter( $endstring ) {
 1062+ $topdelim = array_pop( $this->m_sepstack );
 1063+ return ( $topdelim == $endstring );
 1064+ }
 1065+
 1066+ /**
 1067+ * Extend a given description by a new one, either by adding the new description
 1068+ * (if the old one is a container description) or by creating a new container.
 1069+ * The parameter $conjunction determines whether the combination of both descriptions
 1070+ * should be a disjunction or conjunction.
 1071+ *
 1072+ * In the special case that the current description is NULL, the new one will just
 1073+ * replace the current one.
 1074+ *
 1075+ * The return value is the expected combined description. The object $curdesc will
 1076+ * also be changed (if it was non-NULL).
 1077+ */
 1078+ protected function addDescription( $curdesc, $newdesc, $conjunction = true ) {
 1079+ wfLoadExtensionMessages( 'SemanticMediaWiki' );
 1080+ $notallowedmessage = 'smw_noqueryfeature';
 1081+ if ( $newdesc instanceof SMWSomeProperty ) {
 1082+ $allowed = $this->m_queryfeatures & SMW_PROPERTY_QUERY;
 1083+ } elseif ( $newdesc instanceof SMWClassDescription ) {
 1084+ $allowed = $this->m_queryfeatures & SMW_CATEGORY_QUERY;
 1085+ } elseif ( $newdesc instanceof SMWConceptDescription ) {
 1086+ $allowed = $this->m_queryfeatures & SMW_CONCEPT_QUERY;
 1087+ } elseif ( $newdesc instanceof SMWConjunction ) {
 1088+ $allowed = $this->m_queryfeatures & SMW_CONJUNCTION_QUERY;
 1089+ $notallowedmessage = 'smw_noconjunctions';
 1090+ } elseif ( $newdesc instanceof SMWDisjunction ) {
 1091+ $allowed = $this->m_queryfeatures & SMW_DISJUNCTION_QUERY;
 1092+ $notallowedmessage = 'smw_nodisjunctions';
 1093+ } else {
 1094+ $allowed = true;
 1095+ }
 1096+ if ( !$allowed ) {
 1097+ $this->m_errors[] = wfMsgForContent( $notallowedmessage, str_replace( '[', '&#x005B;', $newdesc->getQueryString() ) );
 1098+ return $curdesc;
 1099+ }
 1100+ if ( $newdesc === NULL ) {
 1101+ return $curdesc;
 1102+ } elseif ( $curdesc === NULL ) {
 1103+ return $newdesc;
 1104+ } else { // we already found descriptions
 1105+ if ( ( ( $conjunction ) && ( $curdesc instanceof SMWConjunction ) ) ||
 1106+ ( ( !$conjunction ) && ( $curdesc instanceof SMWDisjunction ) ) ) { // use existing container
 1107+ $curdesc->addDescription( $newdesc );
 1108+ return $curdesc;
 1109+ } elseif ( $conjunction ) { // make new conjunction
 1110+ if ( $this->m_queryfeatures & SMW_CONJUNCTION_QUERY ) {
 1111+ return new SMWConjunction( array( $curdesc, $newdesc ) );
 1112+ } else {
 1113+ $this->m_errors[] = wfMsgForContent( 'smw_noconjunctions', str_replace( '[', '&#x005B;', $newdesc->getQueryString() ) );
 1114+ return $curdesc;
 1115+ }
 1116+ } else { // make new disjunction
 1117+ if ( $this->m_queryfeatures & SMW_DISJUNCTION_QUERY ) {
 1118+ return new SMWDisjunction( array( $curdesc, $newdesc ) );
 1119+ } else {
 1120+ $this->m_errors[] = wfMsgForContent( 'smw_nodisjunctions', str_replace( '[', '&#x005B;', $newdesc->getQueryString() ) );
 1121+ return $curdesc;
 1122+ }
 1123+ }
 1124+ }
 1125+ }
 1126+}
 1127+
 1128+class SMWNotifyUpdate {
 1129+ protected $m_info;
 1130+ protected $m_title;
 1131+ protected $m_userMsgs;
 1132+ protected $m_userHtmlPropMsgs;
 1133+ protected $m_userHtmlNMMsgs;
 1134+ protected $m_userNMs;
 1135+ protected $m_notifyHtmlPropMsgs;
 1136+ protected $m_notifyHtmlMsgs;
 1137+ protected $m_newMonitor;
 1138+ protected $m_removeMonitored;
 1139+ protected $m_subQueryNotify;
 1140+
 1141+ protected $m_linker;
 1142+
 1143+ protected function getSemanticInfo( $title ) {
 1144+ $result = array();
 1145+ $sStore = NMStorage::getDatabase();
 1146+ $semdata = smwfGetStore()->getSemanticData( $title );
 1147+ foreach ( $semdata->getProperties() as $property ) {
 1148+ if ( !$property->isShown() && $property->getWikiValue() != '' ) { // showing this is not desired, hide
 1149+ continue;
 1150+ } elseif ( $property->isUserDefined() ) { // user defined property
 1151+ $property->setCaption( preg_replace( '/[ ]/u', '&nbsp;', $property->getWikiValue(), 2 ) );
 1152+ }
 1153+
 1154+ $propvalues = $semdata->getPropertyValues( $property );
 1155+ if ( $property->getWikiValue() != '' ) {
 1156+ foreach ( $propvalues as $propvalue ) {
 1157+ if ( $propvalue->getXSDValue() != '' ) {
 1158+ $result[SMWNotifyProcessor::toInfoId( 2, 0, $sStore->lookupSmwId( SMW_NS_PROPERTY, $property->getXSDValue() ) )][] = array( 'name' => $property, 'value' => $propvalue );
 1159+ }
 1160+ }
 1161+ } else {
 1162+ foreach ( $propvalues as $propvalue ) {
 1163+ if ( ( $propvalue instanceof SMWWikiPageValue ) && ( $propvalue->getNamespace() == NS_CATEGORY ) ) {
 1164+ $result[SMWNotifyProcessor::toInfoId( 0, 0, $sStore->lookupSmwId( NS_CATEGORY, $propvalue->getXSDValue() ) )][] = array( 'name' => $propvalue, 'value' => null );
 1165+ }
 1166+ }
 1167+ }
 1168+ }
 1169+ return $result;
 1170+ }
 1171+
 1172+ public function SMWNotifyUpdate( $title ) {
 1173+ $this->m_title = $title;
 1174+ $this->m_userMsgs = array();
 1175+ $this->m_userHtmlPropMsgs = array();
 1176+ $this->m_userHtmlNMMsgs = array();
 1177+ $this->m_userNMs = array();
 1178+ $this->m_notifyHtmlPropMsgs = array();
 1179+ $this->m_notifyHtmlMsgs = array();
 1180+ $this->m_newMonitor = array();
 1181+ $this->m_removeMonitored = array();
 1182+ $this->m_subQueryNotify = array();
 1183+ $this->m_linker = new Linker();
 1184+
 1185+ $page_id = $title->getArticleID();
 1186+ if ( ( $page_id == 0 ) || ( $this->m_title->getNamespace() != NS_MAIN ) ) {
 1187+ return;
 1188+ }
 1189+ $this->m_info = $this->getSemanticInfo( $this->m_title );
 1190+ }
 1191+ public function executeNotifyDelete( $reason ) {
 1192+ $page_id = $this->m_title->getArticleID();
 1193+ if ( ( $page_id == 0 ) || ( $this->m_title->getNamespace() != NS_MAIN ) ) {
 1194+ return;
 1195+ }
 1196+ $page_name = $this->m_title->getText() . ' (' . $this->m_title->getFullUrl() . ')';
 1197+ $page_html_name = '<a href="' . $this->m_title->getFullUrl() . '">' . htmlspecialchars( $this->m_title->getText() ) . '</a>';
 1198+
 1199+ $msg .= "\r\nPage $page_name has been deleted.\r\nReason : $reason";
 1200+ $sStore = NMStorage::getDatabase();
 1201+ $notifications = $sStore->getMonitoredNotifications( $page_id );
 1202+
 1203+ foreach ( $notifications as $user_id => $notifies ) {
 1204+ $this->m_userMsgs[$user_id] .= $msg . '\r\n( NM: ';
 1205+ $hint = "<P>Page $page_html_name has been deleted.<br/>Reason : <font color='red'>" . htmlspecialchars( $reason ) . "</font></P>";
 1206+ $this->m_userHtmlNMMsgs[$user_id] .= "$hint<P>Notify Me: ";
 1207+ $idx = 0;
 1208+ foreach ( $notifies as $notify_id => $notify_detail ) {
 1209+ if ( $idx > 0 ) {
 1210+ $this->m_userMsgs[$user_id] .= ', ';
 1211+ $this->m_userHtmlNMMsgs[$user_id] .= ', ';
 1212+ }
 1213+ $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
 1214+
 1215+ $this->m_userMsgs[$user_id] .= $notify_detail['name'];
 1216+ $this->m_userHtmlNMMsgs[$user_id] .= '<b>' . htmlspecialchars( $notify_detail['name'] ) . '</b>';
 1217+ $idx++;
 1218+ $this->m_removeMonitored[] = array( 'notify_id' => $notify_id, 'page_id' => $page_id );
 1219+
 1220+ $this->m_userNMs[$user_id][] = $notify_id;
 1221+ }
 1222+
 1223+ $this->m_userMsgs[$user_id] .= " ).";
 1224+ $this->m_userHtmlNMMsgs[$user_id] .= " does not match this page now.</P>";
 1225+ }
 1226+
 1227+ $this->notifyUsers();
 1228+ $sStore->removeNotifyMonitor( $this->m_removeMonitored );
 1229+ }
 1230+ function isEqual( $v1, $v2 ) {
 1231+ return ( strval( $v1[value]->getXSDValue() ) == strval( $v2[value]->getXSDValue() ) );
 1232+ }
 1233+ function getNotifyPlain( $info, $key ) {
 1234+ $i = SMWNotifyProcessor::getInfoFromId( $key );
 1235+ if ( $i[type] == 0 ) {
 1236+ return "\r\n'" . $info[name]->getWikiValue() . "' has been " . ( $info[sem_act] == 0 ? "deleted":"added" ) . ".";
 1237+ } else {
 1238+ $tmp = "\r\nProperty '" . $info[name]->getWikiValue() . "' has been " . ( $info[sem_act] == 0 ? "deleted.":( $info[sem_act] == 1 ? "modified":"added" ) ) . ".";
 1239+ $first = true;
 1240+ foreach ( $info[del_vals] as $val ) {
 1241+ if ( $first ) {
 1242+ $tmp .= "\r\nValue '";
 1243+ $first = false;
 1244+ } else {
 1245+ $tmp .= "', '";
 1246+ }
 1247+ $tmp .= $val[plain];
 1248+ }
 1249+ if ( !$first ) {
 1250+ $tmp .= "' deleted.";
 1251+ }
 1252+ $first = true;
 1253+ foreach ( $info[new_vals] as $val ) {
 1254+ if ( $first ) {
 1255+ $tmp .= "\r\nValue '";
 1256+ $first = false;
 1257+ } else {
 1258+ $tmp .= "', '";
 1259+ }
 1260+ $tmp .= $val[plain];
 1261+ }
 1262+ if ( !$first ) {
 1263+ $tmp .= "' added.";
 1264+ }
 1265+ return $tmp . "\r\n";
 1266+ }
 1267+ }
 1268+ function getNotifyHtml( $info, $key ) {
 1269+ $i = SMWNotifyProcessor::getInfoFromId( $key );
 1270+ if ( $i[type] == 0 ) {
 1271+ return "<td>Category</td>
 1272+ <td>" . $info[name]->getShortHTMLText( $this->m_linker ) . "</td>
 1273+ <td>" . ( $info[sem_act] == 0 ? "<font color='green'>remove</font>":"<font color='red'>cite</font>" ) . "</td>
 1274+ <td colspan='2'>N/A</td>";
 1275+ } else {
 1276+ $rows = max( count( $info[del_vals] ), count( $info[new_vals] ) );
 1277+ $tmp = "<tr><td rowspan='$rows'>Property</td>
 1278+ <td rowspan='$rows'>" . $info[name]->getShortHTMLText( $this->m_linker ) . "</td>
 1279+ <td rowspan='$rows'>" . ( $info[sem_act] == 0 ? "<font color='green'>remove</font>":( $info[sem_act] == 1 ? "<font color='blue'>modify</font>":"<font color='red'>cite</font>" ) ) . "</td>";
 1280+ for ( $idx = 0; $idx < $rows; ++$idx ) {
 1281+ if ( $idx > 0 ) {
 1282+ $tmp .= "<tr>";
 1283+ }
 1284+ $tmp .= "<td>" . ( isset( $info[del_vals][$idx] ) ? $info[del_vals][$idx][html]:"&nbsp;" ) . "</td>
 1285+ <td>" . ( isset( $info[new_vals][$idx] ) ? $info[new_vals][$idx][html]:"&nbsp;" ) . "</td>
 1286+ </tr>";
 1287+ }
 1288+ return $tmp;
 1289+ }
 1290+ }
 1291+ public function executeNotifyUpdate() {
 1292+ $page_id = $this->m_title->getArticleID();
 1293+ if ( ( $page_id == 0 ) || ( $this->m_title->getNamespace() != NS_MAIN ) ) {
 1294+ return;
 1295+ }
 1296+ $sStore = NMStorage::getDatabase();
 1297+
 1298+ $info = $this->getSemanticInfo( $this->m_title );
 1299+ // get different
 1300+ $tmp_info = array(); // type : category 0, property 2; name; sem action : del 0, modify 1, add 2; val action : del 0, add 1
 1301+ foreach ( $this->m_info as $key => $value ) {
 1302+ $i = SMWNotifyProcessor::getInfoFromId( $key );
 1303+ $updated = false;
 1304+ if ( !isset( $info[$key] ) ) {
 1305+ if ( $i[type] == 0 ) {
 1306+ $tmp_info[$key] = array( 'sem_act' => 0, 'name' => $value[0][name] );
 1307+ } else {
 1308+ $tmp_info[$key] = array( 'sem_act' => 0, 'name' => $value[0][name], 'del_vals' => array(), 'new_vals' => array() );
 1309+ foreach ( $value as $v ) {
 1310+ $tmp_info[$key][del_vals][] = array( 'plain' => $v[value]->getWikiValue(), 'html' => $v[value]->getShortHTMLText( $this->m_linker ) );
 1311+ }
 1312+ }
 1313+ } else if ( $i[type] == 2 ) {
 1314+ $mvalue = $info[$key];
 1315+ foreach ( $value as $v1 ) {
 1316+ $found = false;
 1317+ foreach ( $mvalue as $v2 ) {
 1318+ if ( $this->isEqual( $v1, $v2 ) ) {
 1319+ $found = true;
 1320+ break;
 1321+ }
 1322+ }
 1323+ if ( !$found ) {
 1324+ if ( !$updated ) {
 1325+ $updated = true;
 1326+ $tmp_info[$key] = array( 'sem_act' => 1, 'name' => $value[0][name], 'del_vals' => array(), 'new_vals' => array() );
 1327+ }
 1328+ $tmp_info[$key][del_vals][] = array( 'plain' => $v1[value]->getWikiValue(), 'html' => $v1[value]->getShortHTMLText( $this->m_linker ) );
 1329+ }
 1330+ }
 1331+ foreach ( $mvalue as $v1 ) {
 1332+ $found = false;
 1333+ foreach ( $value as $v2 ) {
 1334+ if ( $this->isEqual( $v1, $v2 ) ) {
 1335+ $found = true;
 1336+ break;
 1337+ }
 1338+ }
 1339+ if ( !$found ) {
 1340+ if ( !$updated ) {
 1341+ $updated = true;
 1342+ $tmp_info[$key] = array( 'sem_act' => 1, 'name' => $value[0][name], 'del_vals' => array(), 'new_vals' => array() );
 1343+ }
 1344+ $tmp_info[$key][new_vals][] = array( 'plain' => $v1[value]->getWikiValue(), 'html' => $v1[value]->getShortHTMLText( $this->m_linker ) );
 1345+ }
 1346+ }
 1347+ }
 1348+ }
 1349+ foreach ( $info as $key => $value ) {
 1350+ $i = SMWNotifyProcessor::getInfoFromId( $key );
 1351+ if ( !isset( $this->m_info[$key] ) ) {
 1352+ if ( $i[type] == 0 ) {
 1353+ $tmp_info[$key] = array( 'sem_act' => 2, 'name' => $value[0][name] );
 1354+ } else {
 1355+ $tmp_info[$key] = array( 'sem_act' => 2, 'name' => $value[0][name], 'del_vals' => array(), 'new_vals' => array() );
 1356+ foreach ( $value as $v ) {
 1357+ $tmp_info[$key][new_vals][] = array( 'plain' => $v[value]->getWikiValue(), 'html' => $v[value]->getShortHTMLText( $this->m_linker ) );
 1358+ }
 1359+ }
 1360+ }
 1361+ }
 1362+
 1363+ $notifications = $sStore->getMonitoredNotificationsDetail( $page_id );
 1364+ // add semantic info to report all NM
 1365+ foreach ( $notifications as $user_id => $notifies ) {
 1366+ foreach ( $notifies['rep_all'] as $notify_id => $notify_name ) {
 1367+ foreach ( array_keys( $tmp_info ) as $key ) {
 1368+ $notifications[$user_id]['semantic'][$key][$notify_id] = $notify_name;
 1369+ }
 1370+ }
 1371+ }
 1372+ $page_name = $this->m_title->getText() . ' (' . $this->m_title->getFullUrl() . ')';
 1373+
 1374+ foreach ( $notifications as $user_id => $notifies ) {
 1375+ foreach ( $notifies['semantic'] as $key => $notify ) {
 1376+ if ( isset( $tmp_info[$key] ) ) {
 1377+ $hint = "";
 1378+ if ( !isset( $this->m_userMsgs[$user_id] ) ) {
 1379+ $this->m_userMsgs[$user_id] = "\r\nSemantic attributes are changed in page $page_name.";
 1380+ $hint = "Semantic attributes are changed in page <a href='" . $this->m_title->getFullUrl() . "'>" . htmlspecialchars( $this->m_title->getText() ) . "</a>.<br/>";
 1381+ $this->m_userHtmlNMMsgs[$user_id] .= $hint;
 1382+ }
 1383+
 1384+ $this->m_userMsgs[$user_id] .= $this->getNotifyPlain( $tmp_info[$key], $key ) . ' ( NM: ';
 1385+ $propHint = $this->getNotifyHtml( $tmp_info[$key], $key );
 1386+ $this->m_userHtmlPropMsgs[$user_id] .= $propHint . "<tr><td colspan='5'>Notify Me: ";
 1387+ $idx = 0;
 1388+ foreach ( $notify as $notify_id => $notify_name ) {
 1389+ if ( $idx > 0 ) {
 1390+ $this->m_userMsgs[$user_id] .= ', ';
 1391+ $this->m_userHtmlPropMsgs[$user_id] .= ', ';
 1392+ }
 1393+ $this->m_userMsgs[$user_id] .= $notify_name;
 1394+ $this->m_userHtmlPropMsgs[$user_id] .= '<b>' . htmlspecialchars( $notify_name ) . '</b>';
 1395+ $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
 1396+ $this->m_notifyHtmlPropMsgs[$notify_id] .= $propHint;
 1397+ $idx++;
 1398+
 1399+ $this->m_userNMs[$user_id][] = $notify_id;
 1400+ }
 1401+ $this->m_userMsgs[$user_id] .= ' ).';
 1402+ $this->m_userHtmlPropMsgs[$user_id] .= "</td></tr>";
 1403+ }
 1404+ }
 1405+ }
 1406+ // get possible subquery
 1407+ $this->m_subQueryNotify = array();
 1408+ $queries = $sStore->getPossibleQuery( $this->m_info );
 1409+ if ( is_array( $queries ) ) {
 1410+ foreach ( $queries[1] as $notify_id => $notify ) {
 1411+ $this->m_subQueryNotify[$notify_id] = $notify;
 1412+ }
 1413+ }
 1414+
 1415+ $this->m_info = $info;
 1416+ }
 1417+
 1418+ // this will cost time, think we can update monitor in a single thread, like Job
 1419+ public function updateNotifyMonitor() {
 1420+ $page_id = $this->m_title->getArticleID();
 1421+ if ( ( $page_id == 0 ) || ( $this->m_title->getNamespace() != NS_MAIN ) ) {
 1422+ return;
 1423+ }
 1424+ $sStore = NMStorage::getDatabase();
 1425+ $queries = $sStore->getPossibleQuery( $this->m_info );
 1426+ if ( !is_array( $queries ) ) {
 1427+ return;
 1428+ }
 1429+ // get monitored query
 1430+ $main_queries = $sStore->getMonitoredQuery( $page_id );
 1431+ foreach ( $queries[0] as $notify_id => $notify ) {
 1432+ $main_queries[$notify_id] = $notify;
 1433+ }
 1434+
 1435+ // begin notify query on main query
 1436+ $page_name = $this->m_title->getText() . ' (' . $this->m_title->getFullUrl() . ')';
 1437+ $page_html_name = '<a href="' . $this->m_title->getFullUrl() . '">' . htmlspecialchars( $this->m_title->getText() ) . '</a>';
 1438+
 1439+ foreach ( $main_queries as $notify_id => $notify ) {
 1440+ $sStore->getNotifyInMainQuery( $page_id, $notify_id, $notify['sql'], $notify['hierarchy'], $match, $monitoring );
 1441+ if ( ( !$monitoring ) && $match ) {
 1442+ $this->m_userMsgs[$notify['user_id']] .= "\r\nPage $page_name matches NotifyMe '$notify[name]' now.";
 1443+ $hint = "Page $page_html_name matches \"<b>" . htmlspecialchars( $notify[name] ) . "</b>\" now.<br/>";
 1444+ $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
 1445+ $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
 1446+ $this->m_newMonitor[] = array( 'notify_id' => $notify_id, 'page_id' => $page_id );
 1447+ } else if ( ( !$match ) && $monitoring ) {
 1448+ $this->m_userMsgs[$notify['user_id']] .= "\r\nPage $page_name does not match NotifyMe '$notify[name]' now.";
 1449+ $hint = "Page $page_html_name does not match \"<b>" . htmlspecialchars( $notify[name] ) . "</b>\" now.<br/>";
 1450+ $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
 1451+ $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
 1452+ $this->m_removeMonitored[] = array( 'notify_id' => $notify_id, 'page_id' => $page_id );
 1453+ }
 1454+ $this->m_userNMs[$notify['user_id']][] = $notify_id;
 1455+ }
 1456+ // begin notify query on sub query, should go through all pages
 1457+ foreach ( $queries[1] as $notify_id => $notify ) {
 1458+ $this->m_subQueryNotify[$notify_id] = $notify;
 1459+ }
 1460+ foreach ( $this->m_subQueryNotify as $notify_id => $notify ) {
 1461+ $res = $sStore->getNotifyInSubquery( $notify_id, $notify['sql'], $notify['hierarchy'] );
 1462+
 1463+ $no_matches = array_diff( $res['monitoring'], $res['match'] );
 1464+ $matches = array_diff( $res['match'], $res['monitoring'] );
 1465+ foreach ( $matches as $pid ) {
 1466+ $pt = $sStore->getPageTitle( $pid );
 1467+ if ( !$pt ) {
 1468+ continue;
 1469+ }
 1470+ $t = Title::makeTitle( NS_MAIN, $pt->page_title );
 1471+ $p_name = $t->getText() . ' (' . $t->getFullUrl() . ')';
 1472+ $p_html_name = '<a href="' . $t->getFullUrl() . '">' . htmlspecialchars( $t->getText() ) . '</a>';
 1473+
 1474+ $this->m_userMsgs[$notify['user_id']] .= "\r\nSub page $page_name changed, $p_name matches NotifyMe '$notify[name]' now.";
 1475+ $hint = "Sub page $page_html_name changed, $p_html_name matches \"<b>" . htmlspecialchars( $notify[name] ) . "</b>\" now.<br/>";
 1476+ $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
 1477+ $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
 1478+ $this->m_newMonitor[] = array( 'notify_id' => $notify_id, 'page_id' => $pid );
 1479+
 1480+ $this->m_userNMs[$notify['user_id']][] = $notify_id;
 1481+ }
 1482+ foreach ( $no_matches as $pid ) {
 1483+ $pt = $sStore->getPageTitle( $pid );
 1484+ if ( !$pt ) {
 1485+ continue;
 1486+ }
 1487+ $t = Title::makeTitle( NS_MAIN, $pt->page_title );
 1488+ $p_name = $t->getText() . ' (' . $t->getFullUrl() . ')';
 1489+ $p_html_name = '<a href="' . $t->getFullUrl() . '">' . htmlspecialchars( $t->getText() ) . '</a>';
 1490+
 1491+ $this->m_userMsgs[$notify['user_id']] .= "\r\nSub page $page_name changed, page $p_name does not match NotifyMe '$notify[name]' now.";
 1492+ $hint = "Sub page $page_html_name changed, $p_html_name does not match \"<b>" . htmlspecialchars( $notify[name] ) . "</b>\" now.<br/>";
 1493+ $this->m_userHtmlNMMsgs[$notify['user_id']] .= $hint;
 1494+ $this->m_notifyHtmlMsgs[$notify_id] .= $hint;
 1495+ $this->m_removeMonitored[] = array( 'notify_id' => $notify_id, 'page_id' => $pid );
 1496+
 1497+ $this->m_userNMs[$notify['user_id']][] = $notify_id;
 1498+ }
 1499+ }
 1500+
 1501+ $sStore->removeNotifyMonitor( $this->m_removeMonitored );
 1502+ $sStore->addNotifyMonitor( $this->m_newMonitor );
 1503+ }
 1504+ private function applyStyle( $html ) {
 1505+ $html = str_replace( "class=\"smwtable\"", "style=\"background-color: #EEEEFF;\"", $html );
 1506+ $html = str_replace( "<th", "<th style=\"background-color: #EEEEFF;text-align: left;\"", $html );
 1507+ $html = str_replace( "<td", "<td style=\"background-color: #FFFFFF;padding: 1px;padding-left: 5px;padding-right: 5px;text-align: left;vertical-align: top;\"", $html );
 1508+ return $html;
 1509+ }
 1510+ public function notifyUsers() {
 1511+ global $wgSitename, $wgSMTP, $wgEmergencyContact, $wgEnotifyMeJob;
 1512+ $sStore = NMStorage::getDatabase();
 1513+
 1514+ $nm_send_jobs = array();
 1515+ $id = 0;
 1516+
 1517+ if ( count( $this->m_notifyHtmlMsgs ) > 0 ) {
 1518+ $notifications = $sStore->getNotifyMe( array_keys( $this->m_notifyHtmlMsgs ) );
 1519+ }
 1520+ $html_style = '';
 1521+// <style>
 1522+// table.smwtable{background-color: #EEEEFF;}
 1523+// table.smwtable th{background-color: #EEEEFF;text-align: left;}
 1524+// table.smwtable td{background-color: #FFFFFF;padding: 1px;padding-left: 5px;padding-right: 5px;text-align: left;vertical-align: top;}
 1525+// table.smwtable tr.smwfooter td{font-size: 90%;line-height: 1;background-color: #EEEEFF;padding: 0px;padding-left: 5px;padding-right: 5px;text-align: right;vertical-align: top;}
 1526+// </style>';
 1527+ $html_showall = array();
 1528+ foreach ( $this->m_notifyHtmlMsgs as $notify_id => $msg ) {
 1529+ $html_msg = $html_style;
 1530+ $showing_all = false;
 1531+ if ( isset( $notifications[$notify_id] ) && $notifications[$notify_id]['show_all'] ) {
 1532+ SMWQueryProcessor::processFunctionParams( explode( "\n", $notifications[$notify_id]['query'] ), $querystring, $params, $printouts );
 1533+
 1534+ $format = 'auto';
 1535+ if ( array_key_exists( 'format', $params ) ) {
 1536+ $format = strtolower( trim( $params['format'] ) );
 1537+ global $smwgResultFormats;
 1538+ if ( !array_key_exists( $format, $smwgResultFormats ) ) {
 1539+ $format = 'auto';
 1540+ }
 1541+ }
 1542+ $query = SMWQueryProcessor::createQuery( $querystring, $params, SMWQueryProcessor::INLINE_QUERY, $format, $printouts );
 1543+ $res = smwfGetStore()->getQueryResult( $query );
 1544+ $printer = SMWQueryProcessor::getResultPrinter( $format, SMWQueryProcessor::INLINE_QUERY, $res );
 1545+ $result = $printer->getResult( $res, $params, SMW_OUTPUT_HTML );
 1546+ $html_msg .= $result . '<br/>';
 1547+ $html_showall[$notify_id] = array ( 'name' => $notifications[$notify_id]['name'], 'html' => $result );
 1548+
 1549+ $showing_all = true;
 1550+ $link = $res->getQueryLink()->getURL();
 1551+ }
 1552+ global $smwgNMHideDiffWhenShowAll;
 1553+ if ( !( $smwgNMHideDiffWhenShowAll && $showing_all ) ) {
 1554+ $html_msg .= '<p><b>Semantic changes from last revision:</b><br/><span style="font-size: 8pt;">' . $this->m_notifyHtmlMsgs[$notify_id] . '</span></P>';
 1555+ if ( isset( $this->m_notifyHtmlPropMsgs[$notify_id] ) ) {
 1556+ $html_msg .= "<P><table class=\"smwtable\"><tr><th>Semantic type</th><th>Name</th><th>Action</th><th>Deleted</th><th>Added</th></tr>";
 1557+ $html_msg .= $this->m_notifyHtmlPropMsgs[$notify_id];
 1558+ $html_msg .= "</table></P>";
 1559+ }
 1560+ }
 1561+ if ( $showing_all ) {
 1562+ $id = $sStore->addNotifyRSS( 'nid', $notify_id, "All current items, " . date( 'Y-m-d H:i:s', time() ), $this->applyStyle( $html_msg ), $link );
 1563+ } else {
 1564+ $id = $sStore->addNotifyRSS( 'nid', $notify_id, $this->m_title->getText(), $this->applyStyle( $html_msg ) );
 1565+ }
 1566+ }
 1567+ foreach ( $this->m_userMsgs as $user_id => $msg ) {
 1568+ // generate RSS items
 1569+ $html_msg = $html_style;
 1570+ foreach ( array_unique( $this->m_userNMs[$user_id] ) as $showall_nid ) {
 1571+ if ( isset( $html_showall[$showall_nid] ) ) {
 1572+ $html_msg .= "<br/>All current items for \"<b>" . $html_showall[$showall_nid]['name'] . "</b>\":<br/>";
 1573+ $html_msg .= $html_showall[$showall_nid]['html'] . '<br/>';
 1574+ }
 1575+ }
 1576+
 1577+ $html_msg .= '<p><b>Semantic changes from last revision:</b><br/><span style="font-size: 8pt;">' . $this->m_userHtmlNMMsgs[$user_id] . '</span></P>';
 1578+ if ( isset( $this->m_userHtmlPropMsgs[$user_id] ) ) {
 1579+ $html_msg .= "<P><table class=\"smwtable\"><tr><th>Semantic type</th><th>Name</th><th>Action</th><th>Deleted</th><th>Added</th></tr>";
 1580+ $html_msg .= $this->m_userHtmlPropMsgs[$user_id];
 1581+ $html_msg .= "</table></P>";
 1582+ }
 1583+
 1584+ $id = $sStore->addNotifyRSS( 'uid', $user_id, $this->m_title->getText(), $this->applyStyle( $html_msg ) );
 1585+
 1586+ if ( $wgEnotifyMeJob ) {
 1587+ // send notifications by mail
 1588+ $user_info = $sStore->getUserInfo( $user_id );
 1589+ if ( ( $user_info->user_email != '' ) && $this->getUserNMOption( $user_info->user_options ) ) {
 1590+ $name = ( ( $user_info->user_real_name == '' ) ? $user_info->user_name:$user_info->user_real_name );
 1591+ $body = "Dear Mr./Mrs. $name,\r\n$msg" .
 1592+ "\r\n\r\nSincerely yours,\r\nSMW NotifyMe Bot";
 1593+
 1594+ $params = array( 'to' => new MailAddress( $user_info->user_email, $name ),
 1595+ 'from' => new MailAddress( $wgEmergencyContact, 'Admin' ),
 1596+ 'subj' => 'New SMW Notification comes, from ' . $wgSitename,
 1597+ 'body' => $body,
 1598+ 'replyto' => new MailAddress( $wgEmergencyContact, 'Admin' ) );
 1599+
 1600+ $nm_send_jobs[] = new SMW_NMSendMailJob( $this->m_title, $params );
 1601+ }
 1602+ }
 1603+ }
 1604+
 1605+ if ( $wgEnotifyMeJob ) {
 1606+ if ( count( $nm_send_jobs ) ) {
 1607+ Job :: batchInsert( $nm_send_jobs );
 1608+ }
 1609+ } else {
 1610+ global $phpInterpreter;
 1611+ if ( !isset( $phpInterpreter ) ) {
 1612+ // if $phpInterpreter is not set, assume it is in search path
 1613+ // if not, starting of bot will FAIL!
 1614+ $phpInterpreter = "php";
 1615+ }
 1616+ // copy from SMW_GardeningBot.php
 1617+ ob_start();
 1618+ phpinfo();
 1619+ $info = ob_get_contents();
 1620+ ob_end_clean();
 1621+ // Get Systemstring
 1622+ preg_match( '!\nSystem(.*?)\n!is', strip_tags( $info ), $ma );
 1623+ // Check if it consists 'windows' as string
 1624+ preg_match( '/[Ww]indows/', $ma[1], $os );
 1625+ global $smwgNMIP ;
 1626+ if ( $os[0] == '' && $os[0] == null ) {
 1627+
 1628+ // FIXME: $runCommand must allow whitespaces in paths too
 1629+ $runCommand = "$phpInterpreter -q $smwgNMIP/specials/SMWNotifyMe/SMW_NMSendMailAsync.php";
 1630+ // TODO: test async code for linux.
 1631+ // low prio
 1632+ $nullResult = `$runCommand > /dev/null &`;
 1633+ }
 1634+ else // windowze
 1635+ {
 1636+ $runCommand = "\"\"$phpInterpreter\" -q \"$smwgNMIP/specials/SMWNotifyMe/SMW_NMSendMailAsync.php\"\"";
 1637+ $wshShell = new COM( "WScript.Shell" );
 1638+ $runCommand = "cmd /C " . $runCommand;
 1639+
 1640+ $oExec = $wshShell->Run( $runCommand, 7, false );
 1641+ }
 1642+ }
 1643+ }
 1644+ // copy from user class
 1645+ function getUserNMOption( $str ) {
 1646+ $options = array();
 1647+ $a = explode( "\n", $str );
 1648+ foreach ( $a as $s ) {
 1649+ $m = array();
 1650+ if ( preg_match( "/^(.[^=]*)=(.*)$/", $s, $m ) ) {
 1651+ $options[$m[1]] = $m[2];
 1652+ }
 1653+ }
 1654+ return $options['enotifyme'];
 1655+ }
 1656+}
Property changes on: trunk/extensions/SemanticNotifyMe/includes/SMW_NotifyProcessor.php
___________________________________________________________________
Name: svn:eol-style
16571657 + native
Index: trunk/extensions/SemanticNotifyMe/includes/SNM_Initialize.php
@@ -1,294 +1,293 @@
2 -<?php
3 -/*
4 - * Created on 24.6.2009
5 - *
6 - * Author: dch
7 - */
8 -if ( !defined( 'MEDIAWIKI' ) ) die;
9 -
10 -define('SMW_NM_VERSION', '0.5');
11 -
12 -$smwgNMIP = $IP . '/extensions/SemanticNotifyMe';
13 -$smwgNMScriptPath = $wgScriptPath . '/extensions/SemanticNotifyMe';
14 -
15 -global $wgExtensionFunctions;
16 -$wgExtensionFunctions[] = 'smwgNMSetupExtension';
17 -
18 -global $wgDefaultUserOptions;
19 -$wgDefaultUserOptions['enotifyme'] = 1;
20 -
21 -function smwfNMInitMessages() {
22 - global $smwgNMMessagesInitialized;
23 - if (isset($smwgNMMessagesInitialized)) return; // prevent double init
24 -
25 - smwfNMInitUserMessages(); // lazy init for ajax calls
26 -
27 - $smwgNMMessagesInitialized = true;
28 -}
29 -function smwfNMInitUserMessages() {
30 - global $wgMessageCache, $smwgNMContLang, $wgLanguageCode;
31 - smwfNMInitContentLanguage($wgLanguageCode);
32 -
33 - global $smwgNMIP, $smwgNMLang;
34 - if (!empty($smwgNMLang)) { return; }
35 - global $wgMessageCache, $wgLang;
36 - $smwLangClass = 'SMW_NMLanguage' . str_replace( '-', '_', ucfirst( $wgLang->getCode() ) );
37 -
38 - if (file_exists($smwgNMIP . '/languages/'. $smwLangClass . '.php')) {
39 - include_once( $smwgNMIP . '/languages/'. $smwLangClass . '.php' );
40 - }
41 - // fallback if language not supported
42 - if ( !class_exists($smwLangClass)) {
43 - global $smwgNMContLang;
44 - $smwgNMLang = $smwgNMContLang;
45 - } else {
46 - $smwgNMLang = new $smwLangClass();
47 - }
48 -
49 - $wgMessageCache->addMessages($smwgNMLang->getUserMsgArray(), $wgLang->getCode());
50 -}
51 -function smwfNMInitContentLanguage($langcode) {
52 - global $smwgNMIP, $smwgNMContLang;
53 - if (!empty($smwgNMContLang)) { return; }
54 -
55 - $smwContLangClass = 'SMW_NMLanguage' . str_replace( '-', '_', ucfirst( $langcode ) );
56 -
57 - if (file_exists($smwgNMIP . '/languages/'. $smwContLangClass . '.php')) {
58 - include_once( $smwgNMIP . '/languages/'. $smwContLangClass . '.php' );
59 - }
60 -
61 - // fallback if language not supported
62 - if ( !class_exists($smwContLangClass)) {
63 - include_once($smwgNMIP . '/languages/SMW_NMLanguageEn.php');
64 - $smwContLangClass = 'SMW_NMLanguageEn';
65 - }
66 - $smwgNMContLang = new $smwContLangClass();
67 -}
68 -
69 -function smwfNMInitializeTables() {
70 - global $smwgNMIP;
71 - require_once( $smwgNMIP . '/includes/SMW_NMStorage.php' );
72 - NMStorage::getDatabase()->setup(true);
73 -
74 - return true;
75 -}
76 -
77 -function smwfNMGetAjaxMethodPrefix() {
78 - $func_name = isset( $_POST["rs"] ) ? $_POST["rs"] : (isset( $_GET["rs"] ) ? $_GET["rs"] : NULL);
79 - if ($func_name == NULL) return NULL;
80 - return substr($func_name, 4, 4); // return _xx_ of smwf_xx_methodname, may return FALSE
81 -}
82 -
83 -/**
84 - * Intializes Semantic NotifyMe Extension.
85 - * Called from SNM during initialization.
86 - */
87 -function smwgNMSetupExtension() {
88 - global $smwgNMIP, $wgHooks, $wgJobClasses, $wgExtensionCredits;
89 - global $wgAutoloadClasses, $wgSpecialPages, $wgSpecialPageGroups;
90 -
91 - smwfNMInitMessages();
92 -
93 -
94 - // register SMW hooks
95 - $wgHooks['smwInitializeTables'][] = 'smwfNMInitializeTables';
96 -
97 - $wgHooks['ArticleSaveComplete'][] = 'smwfNMSaveHook';
98 - $wgHooks['ArticleUndelete'][] = 'smwfNMUndeleteHook';
99 - $wgHooks['ArticleSave'][] = 'smwfNMPreSaveHook';
100 - $wgHooks['ArticleDelete'][] = 'smwfNMPreDeleteHook';
101 -
102 - // queryinterface hook
103 - $wgHooks['QI_AddButtons'][] = 'smwfNMAddQIButton';
104 -
105 - global $wgRequest, $wgContLang;
106 -
107 - $spns_text = $wgContLang->getNsText(NS_SPECIAL);
108 -
109 - // register AddHTMLHeader functions for special pages
110 - // to include javascript and css files (only on special page requests).
111 - if (stripos($wgRequest->getRequestURL(), $spns_text.":") !== false
112 - || stripos($wgRequest->getRequestURL(), $spns_text."%3A") !== false) {
113 -
114 - if ( defined( 'SMW_HALO_VERSION' ) ){
115 - // insert NM header hook before add halo header
116 - foreach($wgHooks['BeforePageDisplay'] as $k=>$hookVal) {
117 - if($hookVal=='smwfHaloAddHTMLHeader') {
118 - $wgHooks['BeforePageDisplay'][$k] = 'smwNMAddHTMLHeader';
119 - break;
120 - }
121 - }
122 - $wgHooks['BeforePageDisplay'][]='smwfHaloAddHTMLHeader';
123 - } else {
124 - $wgHooks['BeforePageDisplay'][]='smwNMAddHTMLHeader';
125 - }
126 -
127 - }
128 -
129 - $wgJobClasses['SMW_NMSendMailJob'] = 'SMW_NMSendMailJob';
130 - require_once($smwgNMIP . '/includes/jobs/SMW_NMSendMailJob.php');
131 - $wgJobClasses['SMWNMRefreshJob'] = 'SMWNMRefreshJob';
132 - require_once($smwgNMIP . '/includes/jobs/SMW_NMRefreshJob.php');
133 -
134 - $wgAutoloadClasses['SMWNotifyProcessor'] = $smwgNMIP . '/includes/SMW_NotifyProcessor.php';
135 -
136 - $action = $wgRequest->getVal('action');
137 - // add some AJAX calls
138 - if ($action == 'ajax') {
139 - $method_prefix = smwfNMGetAjaxMethodPrefix();
140 -
141 - // decide according to ajax method prefix which script(s) to import
142 - switch($method_prefix) {
143 - case '_nm_' :
144 - require_once($smwgNMIP . '/specials/SMWNotifyMe/SMW_NotAjaxAccess.php');
145 - break;
146 - }
147 - } else { // otherwise register special pages
148 - $wgAutoloadClasses['SMWNotifyMe'] = $smwgNMIP . '/specials/SMWNotifyMe/SMWNotifyMe.php';
149 - $wgSpecialPages['NotifyMe'] = array('SMWNotifyMe');
150 - $wgSpecialPageGroups['NotifyMe'] = 'smwplus_group';
151 - }
152 -
153 - // Register Credits
154 - $wgExtensionCredits['parserhook'][]= array(
155 - 'name'=>'Semantic&nbsp;NotifyMe&nbsp;Extension', 'version'=>SMW_NM_VERSION,
156 - 'author'=>"Ning Hu, Justin Zhang, [http://smwforum.ontoprise.com/smwforum/index.php/Jesse_Wang Jesse Wang], sponsored by [http://projecthalo.com Project Halo], [http://www.vulcan.com Vulcan Inc.]",
157 - 'url'=>'http://wiking.vulcan.com/dev',
158 - 'description' => 'Notify wiki user with specified queries.');
159 -
160 - return true;
161 -}
162 -
163 -function smwfNMGetJSLanguageScripts(&$pathlng, &$userpathlng) {
164 - global $smwgNMIP, $wgLanguageCode, $smwgNMScriptPath, $wgUser;
165 -
166 - // content language file
167 - $lng = '/scripts/Language/SMW_NMLanguage';
168 - if (!empty($wgLanguageCode)) {
169 - $lng .= ucfirst($wgLanguageCode).'.js';
170 - if (file_exists($smwgNMIP . $lng)) {
171 - $pathlng = $smwgNMScriptPath . $lng;
172 - } else {
173 - $pathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageEn.js';
174 - }
175 - } else {
176 - $pathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageEn.js';
177 - }
178 -
179 - // user language file
180 - $lng = '/scripts/Language/SMW_NMLanguage';
181 - if (isset($wgUser)) {
182 - $lng .= "User".ucfirst($wgUser->getOption('language')).'.js';
183 - if (file_exists($smwgNMIP . $lng)) {
184 - $userpathlng = $smwgNMScriptPath . $lng;
185 - } else {
186 - $userpathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageUserEn.js';
187 - }
188 - } else {
189 - $userpathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageUserEn.js';
190 - }
191 -}
192 -
193 -// NotifyMe scripts callback
194 -// includes necessary script and css files.
195 -function smwNMAddHTMLHeader(&$out){
196 - global $wgTitle;
197 - if ($wgTitle->getNamespace() != NS_SPECIAL) return true;
198 -
199 - global $smwgNMScriptPath, $smwgScriptPath;
200 - smwfNMGetJSLanguageScripts($pathlng, $userpathlng);
201 -
202 - if ( defined( 'SMW_HALO_VERSION' ) ){
203 - global $smwgHaloScriptPath, $smwgDeployVersion;
204 -
205 - $jsm = SMWResourceManager::SINGLETON();
206 -
207 - $jsm->addScriptIf($smwgHaloScriptPath . '/scripts/prototype.js', "all", -1, NS_SPECIAL.":NotifyMe");
208 - $jsm->addScriptIf($smwgHaloScriptPath . '/scripts/Logger/smw_logger.js', "all", -1, NS_SPECIAL.":NotifyMe");
209 - $jsm->addScriptIf($smwgScriptPath . '/skins/SMW_tooltip.js', "all", -1, NS_SPECIAL.":NotifyMe");
210 -
211 - $jsm->addScriptIf($smwgNMScriptPath . '/scripts/Language/SMW_NMLanguage.js', "all", -1, NS_SPECIAL.":NotifyMe");
212 - $jsm->addScriptIf($pathlng, "all", -1, NS_SPECIAL.":NotifyMe");
213 - $jsm->addScriptIf($userpathlng, "all", -1, NS_SPECIAL.":NotifyMe");
214 - $jsm->addScriptIf($smwgNMScriptPath . '/scripts/NotifyMe/NotifyHelper.js', "all", -1, NS_SPECIAL.":NotifyMe");
215 -
216 - $jsm->addScriptIf($smwgNMScriptPath . '/scripts/Language/SMW_NMLanguage.js', "all", -1, NS_SPECIAL.":QueryInterface");
217 - $jsm->addScriptIf($pathlng, "all", -1, NS_SPECIAL.":QueryInterface");
218 - $jsm->addScriptIf($userpathlng, "all", -1, NS_SPECIAL.":QueryInterface");
219 - $jsm->addScriptIf($smwgNMScriptPath . '/scripts/NotifyMe/NotifyHelper.js', "all", -1, NS_SPECIAL.":QueryInterface");
220 -
221 - $jsm->addCSSIf($smwgScriptPath . '/skins/SMW_custom.css', "all", -1, NS_SPECIAL.":NotifyMe");
222 - $jsm->addCSSIf($smwgNMScriptPath . '/skins/nm.css', "all", -1, NS_SPECIAL.":NotifyMe");
223 - } else {
224 - global $wgRequest;
225 - $scripts = array();
226 - $$css = array();
227 -
228 - // read state
229 - if ($wgRequest != NULL && $wgTitle != NULL) {
230 - $action = $wgRequest->getVal("action");
231 - // $action of NULL or '' means view mode
232 - $action = $action == NULL || $action == '' ? "view" : $action;
233 - $namespace = $wgTitle->getNamespace();
234 - $page = $wgTitle->getNamespace().":".$wgTitle->getText();
235 -
236 - } else { // if no state could be read, set default -> load all!
237 - $action = "all";
238 - $namespace = -1;
239 - $page = array();
240 - }
241 - if(($namespace == NS_SPECIAL || $namespace == -1) && ($page == NS_SPECIAL.":NotifyMe")) {
242 - $out->addScript('<script type="text/javascript" src="'. $smwgNMScriptPath . '/scripts/prototype.js"></script>');
243 - $out->addScript('<script type="text/javascript" src="'. $smwgScriptPath . '/skins/SMW_tooltip.js"></script>');
244 - $out->addScript('<script type="text/javascript" src="'. $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguage.js"></script>');
245 - $out->addScript('<script type="text/javascript" src="'. $pathlng .'"></script>');
246 - $out->addScript('<script type="text/javascript" src="'. $userpathlng .'"></script>');
247 - $out->addScript('<script type="text/javascript" src="'. $smwgNMScriptPath . '/scripts/NotifyMe/NotifyHelper.js"></script>');
248 -
249 - $out->addLink(array(
250 - 'rel' => 'stylesheet',
251 - 'type' => 'text/css',
252 - 'media' => 'screen, projection',
253 - 'href' => $smwgScriptPath . '/skins/SMW_custom.css'
254 - ));
255 - $out->addLink(array(
256 - 'rel' => 'stylesheet',
257 - 'type' => 'text/css',
258 - 'media' => 'screen, projection',
259 - 'href' => $smwgNMScriptPath . '/skins/nm.css'
260 - ));
261 - }
262 - }
263 - return true; // do not load other scripts or CSS
264 -}
265 -
266 -
267 -function smwfNMPreSaveHook(&$article, &$user, &$text, &$summary, $minor, $watch, $sectionanchor, &$flags) {
268 - SMWNotifyProcessor::prepareArticleSave($article->getTitle());
269 -
270 - return true;
271 -}
272 -function smwfNMPreDeleteHook(&$article, &$user, &$reason) {
273 - SMWNotifyProcessor::articleDelete($article->getTitle(), $reason);
274 -
275 - return true;
276 -}
277 -function smwfNMSaveHook(&$article, &$user, &$text) {
278 - SMWNotifyProcessor::articleSavedComplete($article->getTitle());
279 -
280 - return true; // always return true, in order not to stop MW's hook processing!
281 -}
282 -function smwfNMUndeleteHook(&$title, $create) {
283 - SMWNotifyProcessor::articleSavedComplete($title);
284 - return true; // always return true, in order not to stop MW's hook processing!
285 -}
286 -function smwfNMAddQIButton(&$buttons) {
287 - global $wgUser;
288 - $user_id = $wgUser->getId();
289 - $buttons = '';
290 - if($user_id != 0) {
291 - $buttons = '<button class="btn" onclick="notifyhelper.saveQueryToNotify()" onmouseover="this.className=\'btn btnhov\'; Tip(\'' . wfMsg('smw_qi_tt_addNotify') . '\')" onmouseout="this.className=\'btn\'">' . wfMsg('smw_qi_addNotify') . '</button>';
292 - }
293 - return true;
294 -}
295 -?>
\ No newline at end of file
 2+<?php
 3+/*
 4+ * Created on 24.6.2009
 5+ *
 6+ * Author: dch
 7+ */
 8+if ( !defined( 'MEDIAWIKI' ) ) die;
 9+
 10+define( 'SMW_NM_VERSION', '0.5' );
 11+
 12+$smwgNMIP = $IP . '/extensions/SemanticNotifyMe';
 13+$smwgNMScriptPath = $wgScriptPath . '/extensions/SemanticNotifyMe';
 14+
 15+global $wgExtensionFunctions;
 16+$wgExtensionFunctions[] = 'smwgNMSetupExtension';
 17+
 18+global $wgDefaultUserOptions;
 19+$wgDefaultUserOptions['enotifyme'] = 1;
 20+
 21+function smwfNMInitMessages() {
 22+ global $smwgNMMessagesInitialized;
 23+ if ( isset( $smwgNMMessagesInitialized ) ) return; // prevent double init
 24+
 25+ smwfNMInitUserMessages(); // lazy init for ajax calls
 26+
 27+ $smwgNMMessagesInitialized = true;
 28+}
 29+function smwfNMInitUserMessages() {
 30+ global $wgMessageCache, $smwgNMContLang, $wgLanguageCode;
 31+ smwfNMInitContentLanguage( $wgLanguageCode );
 32+
 33+ global $smwgNMIP, $smwgNMLang;
 34+ if ( !empty( $smwgNMLang ) ) { return; }
 35+ global $wgMessageCache, $wgLang;
 36+ $smwLangClass = 'SMW_NMLanguage' . str_replace( '-', '_', ucfirst( $wgLang->getCode() ) );
 37+
 38+ if ( file_exists( $smwgNMIP . '/languages/' . $smwLangClass . '.php' ) ) {
 39+ include_once( $smwgNMIP . '/languages/' . $smwLangClass . '.php' );
 40+ }
 41+ // fallback if language not supported
 42+ if ( !class_exists( $smwLangClass ) ) {
 43+ global $smwgNMContLang;
 44+ $smwgNMLang = $smwgNMContLang;
 45+ } else {
 46+ $smwgNMLang = new $smwLangClass();
 47+ }
 48+
 49+ $wgMessageCache->addMessages( $smwgNMLang->getUserMsgArray(), $wgLang->getCode() );
 50+}
 51+function smwfNMInitContentLanguage( $langcode ) {
 52+ global $smwgNMIP, $smwgNMContLang;
 53+ if ( !empty( $smwgNMContLang ) ) { return; }
 54+
 55+ $smwContLangClass = 'SMW_NMLanguage' . str_replace( '-', '_', ucfirst( $langcode ) );
 56+
 57+ if ( file_exists( $smwgNMIP . '/languages/' . $smwContLangClass . '.php' ) ) {
 58+ include_once( $smwgNMIP . '/languages/' . $smwContLangClass . '.php' );
 59+ }
 60+
 61+ // fallback if language not supported
 62+ if ( !class_exists( $smwContLangClass ) ) {
 63+ include_once( $smwgNMIP . '/languages/SMW_NMLanguageEn.php' );
 64+ $smwContLangClass = 'SMW_NMLanguageEn';
 65+ }
 66+ $smwgNMContLang = new $smwContLangClass();
 67+}
 68+
 69+function smwfNMInitializeTables() {
 70+ global $smwgNMIP;
 71+ require_once( $smwgNMIP . '/includes/SMW_NMStorage.php' );
 72+ NMStorage::getDatabase()->setup( true );
 73+
 74+ return true;
 75+}
 76+
 77+function smwfNMGetAjaxMethodPrefix() {
 78+ $func_name = isset( $_POST["rs"] ) ? $_POST["rs"] : ( isset( $_GET["rs"] ) ? $_GET["rs"] : NULL );
 79+ if ( $func_name == NULL ) return NULL;
 80+ return substr( $func_name, 4, 4 ); // return _xx_ of smwf_xx_methodname, may return FALSE
 81+}
 82+
 83+/**
 84+ * Intializes Semantic NotifyMe Extension.
 85+ * Called from SNM during initialization.
 86+ */
 87+function smwgNMSetupExtension() {
 88+ global $smwgNMIP, $wgHooks, $wgJobClasses, $wgExtensionCredits;
 89+ global $wgAutoloadClasses, $wgSpecialPages, $wgSpecialPageGroups;
 90+
 91+ smwfNMInitMessages();
 92+
 93+
 94+ // register SMW hooks
 95+ $wgHooks['smwInitializeTables'][] = 'smwfNMInitializeTables';
 96+
 97+ $wgHooks['ArticleSaveComplete'][] = 'smwfNMSaveHook';
 98+ $wgHooks['ArticleUndelete'][] = 'smwfNMUndeleteHook';
 99+ $wgHooks['ArticleSave'][] = 'smwfNMPreSaveHook';
 100+ $wgHooks['ArticleDelete'][] = 'smwfNMPreDeleteHook';
 101+
 102+ // queryinterface hook
 103+ $wgHooks['QI_AddButtons'][] = 'smwfNMAddQIButton';
 104+
 105+ global $wgRequest, $wgContLang;
 106+
 107+ $spns_text = $wgContLang->getNsText( NS_SPECIAL );
 108+
 109+ // register AddHTMLHeader functions for special pages
 110+ // to include javascript and css files (only on special page requests).
 111+ if ( stripos( $wgRequest->getRequestURL(), $spns_text . ":" ) !== false
 112+ || stripos( $wgRequest->getRequestURL(), $spns_text . "%3A" ) !== false ) {
 113+
 114+ if ( defined( 'SMW_HALO_VERSION' ) ) {
 115+ // insert NM header hook before add halo header
 116+ foreach ( $wgHooks['BeforePageDisplay'] as $k => $hookVal ) {
 117+ if ( $hookVal == 'smwfHaloAddHTMLHeader' ) {
 118+ $wgHooks['BeforePageDisplay'][$k] = 'smwNMAddHTMLHeader';
 119+ break;
 120+ }
 121+ }
 122+ $wgHooks['BeforePageDisplay'][] = 'smwfHaloAddHTMLHeader';
 123+ } else {
 124+ $wgHooks['BeforePageDisplay'][] = 'smwNMAddHTMLHeader';
 125+ }
 126+
 127+ }
 128+
 129+ $wgJobClasses['SMW_NMSendMailJob'] = 'SMW_NMSendMailJob';
 130+ require_once( $smwgNMIP . '/includes/jobs/SMW_NMSendMailJob.php' );
 131+ $wgJobClasses['SMWNMRefreshJob'] = 'SMWNMRefreshJob';
 132+ require_once( $smwgNMIP . '/includes/jobs/SMW_NMRefreshJob.php' );
 133+
 134+ $wgAutoloadClasses['SMWNotifyProcessor'] = $smwgNMIP . '/includes/SMW_NotifyProcessor.php';
 135+
 136+ $action = $wgRequest->getVal( 'action' );
 137+ // add some AJAX calls
 138+ if ( $action == 'ajax' ) {
 139+ $method_prefix = smwfNMGetAjaxMethodPrefix();
 140+
 141+ // decide according to ajax method prefix which script(s) to import
 142+ switch( $method_prefix ) {
 143+ case '_nm_' :
 144+ require_once( $smwgNMIP . '/specials/SMWNotifyMe/SMW_NotAjaxAccess.php' );
 145+ break;
 146+ }
 147+ } else { // otherwise register special pages
 148+ $wgAutoloadClasses['SMWNotifyMe'] = $smwgNMIP . '/specials/SMWNotifyMe/SMWNotifyMe.php';
 149+ $wgSpecialPages['NotifyMe'] = array( 'SMWNotifyMe' );
 150+ $wgSpecialPageGroups['NotifyMe'] = 'smwplus_group';
 151+ }
 152+
 153+ // Register Credits
 154+ $wgExtensionCredits['parserhook'][] = array(
 155+ 'name' => 'Semantic&nbsp;NotifyMe&nbsp;Extension', 'version' => SMW_NM_VERSION,
 156+ 'author' => "Ning Hu, Justin Zhang, [http://smwforum.ontoprise.com/smwforum/index.php/Jesse_Wang Jesse Wang], sponsored by [http://projecthalo.com Project Halo], [http://www.vulcan.com Vulcan Inc.]",
 157+ 'url' => 'http://wiking.vulcan.com/dev',
 158+ 'description' => 'Notify wiki user with specified queries.' );
 159+
 160+ return true;
 161+}
 162+
 163+function smwfNMGetJSLanguageScripts( &$pathlng, &$userpathlng ) {
 164+ global $smwgNMIP, $wgLanguageCode, $smwgNMScriptPath, $wgUser;
 165+
 166+ // content language file
 167+ $lng = '/scripts/Language/SMW_NMLanguage';
 168+ if ( !empty( $wgLanguageCode ) ) {
 169+ $lng .= ucfirst( $wgLanguageCode ) . '.js';
 170+ if ( file_exists( $smwgNMIP . $lng ) ) {
 171+ $pathlng = $smwgNMScriptPath . $lng;
 172+ } else {
 173+ $pathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageEn.js';
 174+ }
 175+ } else {
 176+ $pathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageEn.js';
 177+ }
 178+
 179+ // user language file
 180+ $lng = '/scripts/Language/SMW_NMLanguage';
 181+ if ( isset( $wgUser ) ) {
 182+ $lng .= "User" . ucfirst( $wgUser->getOption( 'language' ) ) . '.js';
 183+ if ( file_exists( $smwgNMIP . $lng ) ) {
 184+ $userpathlng = $smwgNMScriptPath . $lng;
 185+ } else {
 186+ $userpathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageUserEn.js';
 187+ }
 188+ } else {
 189+ $userpathlng = $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguageUserEn.js';
 190+ }
 191+}
 192+
 193+// NotifyMe scripts callback
 194+// includes necessary script and css files.
 195+function smwNMAddHTMLHeader( &$out ) {
 196+ global $wgTitle;
 197+ if ( $wgTitle->getNamespace() != NS_SPECIAL ) return true;
 198+
 199+ global $smwgNMScriptPath, $smwgScriptPath;
 200+ smwfNMGetJSLanguageScripts( $pathlng, $userpathlng );
 201+
 202+ if ( defined( 'SMW_HALO_VERSION' ) ) {
 203+ global $smwgHaloScriptPath, $smwgDeployVersion;
 204+
 205+ $jsm = SMWResourceManager::SINGLETON();
 206+
 207+ $jsm->addScriptIf( $smwgHaloScriptPath . '/scripts/prototype.js', "all", - 1, NS_SPECIAL . ":NotifyMe" );
 208+ $jsm->addScriptIf( $smwgHaloScriptPath . '/scripts/Logger/smw_logger.js', "all", - 1, NS_SPECIAL . ":NotifyMe" );
 209+ $jsm->addScriptIf( $smwgScriptPath . '/skins/SMW_tooltip.js', "all", - 1, NS_SPECIAL . ":NotifyMe" );
 210+
 211+ $jsm->addScriptIf( $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguage.js', "all", - 1, NS_SPECIAL . ":NotifyMe" );
 212+ $jsm->addScriptIf( $pathlng, "all", - 1, NS_SPECIAL . ":NotifyMe" );
 213+ $jsm->addScriptIf( $userpathlng, "all", - 1, NS_SPECIAL . ":NotifyMe" );
 214+ $jsm->addScriptIf( $smwgNMScriptPath . '/scripts/NotifyMe/NotifyHelper.js', "all", - 1, NS_SPECIAL . ":NotifyMe" );
 215+
 216+ $jsm->addScriptIf( $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguage.js', "all", - 1, NS_SPECIAL . ":QueryInterface" );
 217+ $jsm->addScriptIf( $pathlng, "all", - 1, NS_SPECIAL . ":QueryInterface" );
 218+ $jsm->addScriptIf( $userpathlng, "all", - 1, NS_SPECIAL . ":QueryInterface" );
 219+ $jsm->addScriptIf( $smwgNMScriptPath . '/scripts/NotifyMe/NotifyHelper.js', "all", - 1, NS_SPECIAL . ":QueryInterface" );
 220+
 221+ $jsm->addCSSIf( $smwgScriptPath . '/skins/SMW_custom.css', "all", - 1, NS_SPECIAL . ":NotifyMe" );
 222+ $jsm->addCSSIf( $smwgNMScriptPath . '/skins/nm.css', "all", - 1, NS_SPECIAL . ":NotifyMe" );
 223+ } else {
 224+ global $wgRequest;
 225+ $scripts = array();
 226+ $$css = array();
 227+
 228+ // read state
 229+ if ( $wgRequest != NULL && $wgTitle != NULL ) {
 230+ $action = $wgRequest->getVal( "action" );
 231+ // $action of NULL or '' means view mode
 232+ $action = $action == NULL || $action == '' ? "view" : $action;
 233+ $namespace = $wgTitle->getNamespace();
 234+ $page = $wgTitle->getNamespace() . ":" . $wgTitle->getText();
 235+
 236+ } else { // if no state could be read, set default -> load all!
 237+ $action = "all";
 238+ $namespace = - 1;
 239+ $page = array();
 240+ }
 241+ if ( ( $namespace == NS_SPECIAL || $namespace == - 1 ) && ( $page == NS_SPECIAL . ":NotifyMe" ) ) {
 242+ $out->addScript( '<script type="text/javascript" src="' . $smwgNMScriptPath . '/scripts/prototype.js"></script>' );
 243+ $out->addScript( '<script type="text/javascript" src="' . $smwgScriptPath . '/skins/SMW_tooltip.js"></script>' );
 244+ $out->addScript( '<script type="text/javascript" src="' . $smwgNMScriptPath . '/scripts/Language/SMW_NMLanguage.js"></script>' );
 245+ $out->addScript( '<script type="text/javascript" src="' . $pathlng . '"></script>' );
 246+ $out->addScript( '<script type="text/javascript" src="' . $userpathlng . '"></script>' );
 247+ $out->addScript( '<script type="text/javascript" src="' . $smwgNMScriptPath . '/scripts/NotifyMe/NotifyHelper.js"></script>' );
 248+
 249+ $out->addLink( array(
 250+ 'rel' => 'stylesheet',
 251+ 'type' => 'text/css',
 252+ 'media' => 'screen, projection',
 253+ 'href' => $smwgScriptPath . '/skins/SMW_custom.css'
 254+ ) );
 255+ $out->addLink( array(
 256+ 'rel' => 'stylesheet',
 257+ 'type' => 'text/css',
 258+ 'media' => 'screen, projection',
 259+ 'href' => $smwgNMScriptPath . '/skins/nm.css'
 260+ ) );
 261+ }
 262+ }
 263+ return true; // do not load other scripts or CSS
 264+}
 265+
 266+
 267+function smwfNMPreSaveHook( &$article, &$user, &$text, &$summary, $minor, $watch, $sectionanchor, &$flags ) {
 268+ SMWNotifyProcessor::prepareArticleSave( $article->getTitle() );
 269+
 270+ return true;
 271+}
 272+function smwfNMPreDeleteHook( &$article, &$user, &$reason ) {
 273+ SMWNotifyProcessor::articleDelete( $article->getTitle(), $reason );
 274+
 275+ return true;
 276+}
 277+function smwfNMSaveHook( &$article, &$user, &$text ) {
 278+ SMWNotifyProcessor::articleSavedComplete( $article->getTitle() );
 279+
 280+ return true; // always return true, in order not to stop MW's hook processing!
 281+}
 282+function smwfNMUndeleteHook( &$title, $create ) {
 283+ SMWNotifyProcessor::articleSavedComplete( $title );
 284+ return true; // always return true, in order not to stop MW's hook processing!
 285+}
 286+function smwfNMAddQIButton( &$buttons ) {
 287+ global $wgUser;
 288+ $user_id = $wgUser->getId();
 289+ $buttons = '';
 290+ if ( $user_id != 0 ) {
 291+ $buttons = '<button class="btn" onclick="notifyhelper.saveQueryToNotify()" onmouseover="this.className=\'btn btnhov\'; Tip(\'' . wfMsg( 'smw_qi_tt_addNotify' ) . '\')" onmouseout="this.className=\'btn\'">' . wfMsg( 'smw_qi_addNotify' ) . '</button>';
 292+ }
 293+ return true;
 294+}
Property changes on: trunk/extensions/SemanticNotifyMe/includes/SNM_Initialize.php
___________________________________________________________________
Name: svn:eol-style
296295 + native
Index: trunk/extensions/SemanticNotifyMe/includes/storage/SMW_SQLStore2_QueriesNM.php
@@ -1,30 +1,30 @@
22 <?php
33 /**
44 * Query answering functions for SMWSQLStore2. Separated frmo main code for readability and
5 - * for avoiding twice the amount of code being required on every use of a simple storage function.
6 - *
 5+ * for avoiding twice the amount of code being required on every use of a simple storage function.
 6+ *
77 * based on SMW, SMW_SQLStore2_Queries.php, apply query parser to NotifyMe
88 *
99 * @author dch
1010 */
11 -
12 -global $smwgIP;
13 -include_once("$smwgIP/includes/storage/SMW_SQLStore2_Queries.php");
1411
 12+global $smwgIP;
 13+include_once( "$smwgIP/includes/storage/SMW_SQLStore2_Queries.php" );
 14+
1515 /**
1616 * Class that implements query answering for SMWSQLStore2.
1717 */
1818 class SMWSQLStore2QueryEngineNM {
1919
20 - /// Database slave to be used
21 - protected $m_dbs; /// TODO: should temporary tables be created on the master DB?
22 - /// Parent SMWSQLStore2
 20+ // / Database slave to be used
 21+ protected $m_dbs; // / TODO: should temporary tables be created on the master DB?
 22+ // / Parent SMWSQLStore2
2323 protected $m_store;
24 - /// Query mode copied from given query, some submethods act differently when in SMWQuery::MODE_DEBUG
 24+ // / Query mode copied from given query, some submethods act differently when in SMWQuery::MODE_DEBUG
2525 protected $m_qmode;
26 - /// Array of generated query descriptions
 26+ // / Array of generated query descriptions
2727 protected $m_queries = array();
28 - /// Array of arrays of executed queries, indexed by the temporary table names results were fed into
 28+ // / Array of arrays of executed queries, indexed by the temporary table names results were fed into
2929 protected $m_querylog = array();
3030 /**
3131 * Array of sorting requests ("Property_name" => "ASC"/"DESC". Used during query
@@ -32,12 +32,12 @@
3333 * conditions).
3434 */
3535 protected $m_sortkeys;
36 - /// Cache of computed hierarchy queries for reuse, cat/prop-value string => tablename
 36+ // / Cache of computed hierarchy queries for reuse, cat/prop-value string => tablename
3737 protected $m_hierarchies = array();
38 - /// Local collection of error strings, passed on to callers if possible.
 38+ // / Local collection of error strings, passed on to callers if possible.
3939 protected $m_errors = array();
4040
41 - public function __construct(&$parentstore, &$dbslave) {
 41+ public function __construct( &$parentstore, &$dbslave ) {
4242 $this->m_store = $parentstore;
4343 $this->m_dbs = $dbslave;
4444 }
@@ -47,18 +47,18 @@
4848 *
4949 * @param $concept Title
5050 */
51 - public function refreshConceptCache($concept) {
 51+ public function refreshConceptCache( $concept ) {
5252 global $smwgQMaxLimit, $smwgQConceptFeatures;
53 - $cid = $this->m_store->getSMWPageID($concept->getDBKey(), SMW_NS_CONCEPT, '');
54 - $cid_c = $this->m_store->getSMWPageID($concept->getDBKey(), SMW_NS_CONCEPT, '', false);
55 - if ($cid != $cid_c) {
 53+ $cid = $this->m_store->getSMWPageID( $concept->getDBKey(), SMW_NS_CONCEPT, '' );
 54+ $cid_c = $this->m_store->getSMWPageID( $concept->getDBKey(), SMW_NS_CONCEPT, '', false );
 55+ if ( $cid != $cid_c ) {
5656 $this->m_errors[] = "Skipping redirect concept.";
5757 return $this->m_errors;
5858 }
59 - $dv = end($this->m_store->getPropertyValues($concept, SMWPropertyValue::makeProperty('_CONC')));
60 - $desctxt = ($dv!==false)?$dv->getWikiValue():false;
 59+ $dv = end( $this->m_store->getPropertyValues( $concept, SMWPropertyValue::makeProperty( '_CONC' ) ) );
 60+ $desctxt = ( $dv !== false ) ? $dv->getWikiValue():false;
6161 $this->m_errors = array();
62 - if ($desctxt) { // concept found
 62+ if ( $desctxt ) { // concept found
6363 $this->m_qmode = SMWQuery::MODE_INSTANCES;
6464 $this->m_queries = array();
6565 $this->m_hierarchies = array();
@@ -67,25 +67,25 @@
6868 SMWSQLStore2Query::$qnum = 0;
6969
7070 // Pre-process query:
71 - $qp = new SMWQueryParser($smwgQConceptFeatures);
72 - $desc = $qp->getQueryDescription($desctxt);
73 - $qid = $this->compileQueries($desc);
74 - $this->executeQueries($this->m_queries[$qid]); // execute query tree, resolve all dependencies
 71+ $qp = new SMWQueryParser( $smwgQConceptFeatures );
 72+ $desc = $qp->getQueryDescription( $desctxt );
 73+ $qid = $this->compileQueries( $desc );
 74+ $this->executeQueries( $this->m_queries[$qid] ); // execute query tree, resolve all dependencies
7575 $qobj = $this->m_queries[$qid];
76 - if ($qobj->joinfield === '') {
 76+ if ( $qobj->joinfield === '' ) {
7777 return;
7878 }
7979 // Update database:
80 - $this->m_dbs->delete('smw_conccache', array('o_id' => $cid), 'SMW::refreshConceptCache');
81 - $this->m_dbs->query("INSERT IGNORE INTO " . $this->m_dbs->tableName('smw_conccache') .
 80+ $this->m_dbs->delete( 'smw_conccache', array( 'o_id' => $cid ), 'SMW::refreshConceptCache' );
 81+ $this->m_dbs->query( "INSERT IGNORE INTO " . $this->m_dbs->tableName( 'smw_conccache' ) .
8282 " SELECT DISTINCT $qobj->joinfield AS s_id, $cid AS o_id FROM " .
83 - $this->m_dbs->tableName($qobj->jointable) . " AS $qobj->alias" . $qobj->from .
84 - ($qobj->where?" WHERE ":'') . $qobj->where . " LIMIT $smwgQMaxLimit",
85 - 'SMW::refreshConceptCache');
86 - $this->m_dbs->update('smw_conc2', array('cache_date' => strtotime("now"), 'cache_count' => $this->m_dbs->affectedRows()), array('s_id' => $cid), 'SMW::refreshConceptCache');
 83+ $this->m_dbs->tableName( $qobj->jointable ) . " AS $qobj->alias" . $qobj->from .
 84+ ( $qobj->where ? " WHERE ":'' ) . $qobj->where . " LIMIT $smwgQMaxLimit",
 85+ 'SMW::refreshConceptCache' );
 86+ $this->m_dbs->update( 'smw_conc2', array( 'cache_date' => strtotime( "now" ), 'cache_count' => $this->m_dbs->affectedRows() ), array( 's_id' => $cid ), 'SMW::refreshConceptCache' );
8787 } else { // just delete old data if there is any
88 - $this->m_dbs->delete('smw_conccache', array('o_id' => $cid), 'SMW::refreshConceptCache');
89 - $this->m_dbs->update('smw_conc2', array('cache_date' => NULL, 'cache_count' => NULL), array('s_id' => $cid), 'SMW::refreshConceptCache');
 88+ $this->m_dbs->delete( 'smw_conccache', array( 'o_id' => $cid ), 'SMW::refreshConceptCache' );
 89+ $this->m_dbs->update( 'smw_conc2', array( 'cache_date' => NULL, 'cache_count' => NULL ), array( 's_id' => $cid ), 'SMW::refreshConceptCache' );
9090 $this->m_errors[] = "No concept description found.";
9191 }
9292 $this->cleanUp();
@@ -97,18 +97,18 @@
9898 *
9999 * @param $concept Title
100100 */
101 - public function deleteConceptCache($concept) {
102 - $cid = $this->m_store->getSMWPageID($concept->getDBKey(), SMW_NS_CONCEPT, '', false);
103 - $this->m_dbs->delete('smw_conccache', array('o_id' => $cid), 'SMW::refreshConceptCache');
104 - $this->m_dbs->update('smw_conc2', array('cache_date' => NULL, 'cache_count' => NULL), array('s_id' => $cid), 'SMW::refreshConceptCache');
 101+ public function deleteConceptCache( $concept ) {
 102+ $cid = $this->m_store->getSMWPageID( $concept->getDBKey(), SMW_NS_CONCEPT, '', false );
 103+ $this->m_dbs->delete( 'smw_conccache', array( 'o_id' => $cid ), 'SMW::refreshConceptCache' );
 104+ $this->m_dbs->update( 'smw_conc2', array( 'cache_date' => NULL, 'cache_count' => NULL ), array( 's_id' => $cid ), 'SMW::refreshConceptCache' );
105105 }
106106
107107 /**
108108 * The new SQL store's implementation of query answering.
109109 */
110 - public function getQueryResult(SMWQuery $query) {
111 - if ($query->querymode == SMWQuery::MODE_NONE) { // don't query, but return something to printer
112 - $result = new SMWQueryResult($query->getDescription()->getPrintrequests(), $query, true);
 110+ public function getQueryResult( SMWQuery $query ) {
 111+ if ( $query->querymode == SMWQuery::MODE_NONE ) { // don't query, but return something to printer
 112+ $result = new SMWQueryResult( $query->getDescription()->getPrintrequests(), $query, true );
113113 return $result;
114114 }
115115 $this->m_qmode = $query->querymode;
@@ -124,102 +124,102 @@
125125 $qobj->jointable = 'smw_ids';
126126 $qobj->joinfield = "$qobj->alias.smw_id";
127127 // build query dependency tree:
128 - wfProfileIn('SMWSQLStore2Queries::compileMainQuery (SMW)');
129 - $qid = $this->compileQueries($query->getDescription()); // compile query, build query "plan"
130 - wfProfileOut('SMWSQLStore2Queries::compileMainQuery (SMW)');
131 - if ($qid < 0) { // no valid/supported condition; ensure that at least only proper pages are delivered
 128+ wfProfileIn( 'SMWSQLStore2Queries::compileMainQuery (SMW)' );
 129+ $qid = $this->compileQueries( $query->getDescription() ); // compile query, build query "plan"
 130+ wfProfileOut( 'SMWSQLStore2Queries::compileMainQuery (SMW)' );
 131+ if ( $qid < 0 ) { // no valid/supported condition; ensure that at least only proper pages are delivered
132132 $qid = SMWSQLStore2Query::$qnum;
133133 $q = new SMWSQLStore2Query();
134134 $q->jointable = 'smw_ids';
135135 $q->joinfield = "$q->alias.smw_id";
136 - $q->where = "$q->alias.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWIW) . " AND $q->alias.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWREDIIW) . " AND $q->alias.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWBORDERIW) . " AND $q->alias.smw_iw!=" . $this->m_dbs->addQuotes(SMW_SQL2_SMWINTDEFIW);
 136+ $q->where = "$q->alias.smw_iw!=" . $this->m_dbs->addQuotes( SMW_SQL2_SMWIW ) . " AND $q->alias.smw_iw!=" . $this->m_dbs->addQuotes( SMW_SQL2_SMWREDIIW ) . " AND $q->alias.smw_iw!=" . $this->m_dbs->addQuotes( SMW_SQL2_SMWBORDERIW ) . " AND $q->alias.smw_iw!=" . $this->m_dbs->addQuotes( SMW_SQL2_SMWINTDEFIW );
137137 $this->m_queries[$qid] = $q;
138138 }
139139 // append query to root:
140 - $qobj->components = array($qid => "$qobj->alias.smw_id");
 140+ $qobj->components = array( $qid => "$qobj->alias.smw_id" );
141141 $qobj->sortfields = $this->m_queries[$qid]->sortfields;
142142 $this->m_queries[$rootid] = $qobj;
143143
144 - $this->applyOrderConditions($query,$rootid); // may extend query if needed for sorting
145 - wfProfileIn('SMWSQLStore2Queries::executeMainQuery (SMW)');
146 - $this->executeQueries($this->m_queries[$rootid]); // execute query tree, resolve all dependencies
147 - wfProfileOut('SMWSQLStore2Queries::executeMainQuery (SMW)');
148 - $result = $this->getNMQueryResult($query,$rootid);
149 -
 144+ $this->applyOrderConditions( $query, $rootid ); // may extend query if needed for sorting
 145+ wfProfileIn( 'SMWSQLStore2Queries::executeMainQuery (SMW)' );
 146+ $this->executeQueries( $this->m_queries[$rootid] ); // execute query tree, resolve all dependencies
 147+ wfProfileOut( 'SMWSQLStore2Queries::executeMainQuery (SMW)' );
 148+ $result = $this->getNMQueryResult( $query, $rootid );
 149+
150150 $this->cleanUp();
151 - $query->addErrors($this->m_errors);
 151+ $query->addErrors( $this->m_errors );
152152 return $result;
153153 }
154 -
155 - // added by dch
156 - protected function getNMQueryResult($query,$rootid) {
157 - wfProfileIn('SMWSQLStore2Queries::getNMQueryResult (SMW)');
158 - $qobj = $this->m_queries[$rootid];
159 - if ($qobj->joinfield !== '') {
160 - $sql = "SELECT DISTINCT $qobj->alias.smw_title AS t,$qobj->alias.smw_namespace AS ns FROM " .
161 - $this->m_dbs->tableName($qobj->jointable) . " AS $qobj->alias" . $qobj->from .
162 - (($qobj->where=='')?'':' WHERE ') . $qobj->where;
163 - } else { // empty result, no query needed
164 - wfProfileOut('SMWSQLStore2Queries::getNMQueryResult (SMW)');
165 - return false;
166 - }
167 - $tmp = '';
168 - foreach ($this->m_querylog as $table => $log) {
169 - foreach ($log as $l => $v) {
170 - $tmp .= ($tmp!=''?';':'')."$table:$l";
171 - }
172 - }
173 - $result = array('sql'=>$sql, 'tmp_hierarchy'=>$tmp, 'page_ids'=>array());
174 -
175 - $res = $this->m_dbs->select($this->m_dbs->tableName($qobj->jointable) . " AS $qobj->alias" . $qobj->from, "DISTINCT $qobj->alias.smw_title AS t,$qobj->alias.smw_namespace AS ns", $qobj->where, 'SMW::getQueryResult');
176 - while ( $row = $this->m_dbs->fetchObject($res) ) {
177 - if($row->ns != NS_MAIN) continue;
178 -
179 - $title = Title::makeTitle($row->ns, $row->t);
180 - $result['page_ids'][] = $title->getArticleID();
181 - }
182 - $this->m_dbs->freeResult($res);
183 -
184 - wfProfileOut('SMWSQLStore2Queries::getNMQueryResult (SMW)');
185 - return $result;
186 - }
187154
 155+ // added by dch
 156+ protected function getNMQueryResult( $query, $rootid ) {
 157+ wfProfileIn( 'SMWSQLStore2Queries::getNMQueryResult (SMW)' );
 158+ $qobj = $this->m_queries[$rootid];
 159+ if ( $qobj->joinfield !== '' ) {
 160+ $sql = "SELECT DISTINCT $qobj->alias.smw_title AS t,$qobj->alias.smw_namespace AS ns FROM " .
 161+ $this->m_dbs->tableName( $qobj->jointable ) . " AS $qobj->alias" . $qobj->from .
 162+ ( ( $qobj->where == '' ) ? '':' WHERE ' ) . $qobj->where;
 163+ } else { // empty result, no query needed
 164+ wfProfileOut( 'SMWSQLStore2Queries::getNMQueryResult (SMW)' );
 165+ return false;
 166+ }
 167+ $tmp = '';
 168+ foreach ( $this->m_querylog as $table => $log ) {
 169+ foreach ( $log as $l => $v ) {
 170+ $tmp .= ( $tmp != '' ? ';':'' ) . "$table:$l";
 171+ }
 172+ }
 173+ $result = array( 'sql' => $sql, 'tmp_hierarchy' => $tmp, 'page_ids' => array() );
 174+
 175+ $res = $this->m_dbs->select( $this->m_dbs->tableName( $qobj->jointable ) . " AS $qobj->alias" . $qobj->from, "DISTINCT $qobj->alias.smw_title AS t,$qobj->alias.smw_namespace AS ns", $qobj->where, 'SMW::getQueryResult' );
 176+ while ( $row = $this->m_dbs->fetchObject( $res ) ) {
 177+ if ( $row->ns != NS_MAIN ) continue;
 178+
 179+ $title = Title::makeTitle( $row->ns, $row->t );
 180+ $result['page_ids'][] = $title->getArticleID();
 181+ }
 182+ $this->m_dbs->freeResult( $res );
 183+
 184+ wfProfileOut( 'SMWSQLStore2Queries::getNMQueryResult (SMW)' );
 185+ return $result;
 186+ }
 187+
188188 /**
189189 * Create a new SMWSQLStore2Query object that can be used to obtain results for
190190 * the given description. The result is stored in $this->m_queries using a numeric
191191 * key that is returned as a result of the function. Returns -1 if no query was
192192 * created.
193193 */
194 - protected function compileQueries(SMWDescription $description) {
 194+ protected function compileQueries( SMWDescription $description ) {
195195 $qid = SMWSQLStore2Query::$qnum;
196196 $query = new SMWSQLStore2Query();
197 - if ($description instanceof SMWSomeProperty) {
198 - $this->compilePropertyCondition($query, $description->getProperty(), $description->getDescription());
199 - if ($query->type == SMW_SQL2_NOQUERY) $qid = -1; // drop that right away
200 - } elseif ($description instanceof SMWNamespaceDescription) { /// TODO: One instance of smw_ids on s_id always suffices (swm_id is KEY)! Doable in execution ... (PERFORMANCE)
 197+ if ( $description instanceof SMWSomeProperty ) {
 198+ $this->compilePropertyCondition( $query, $description->getProperty(), $description->getDescription() );
 199+ if ( $query->type == SMW_SQL2_NOQUERY ) $qid = - 1; // drop that right away
 200+ } elseif ( $description instanceof SMWNamespaceDescription ) { // / TODO: One instance of smw_ids on s_id always suffices (swm_id is KEY)! Doable in execution ... (PERFORMANCE)
201201 $query->jointable = 'smw_ids';
202202 $query->joinfield = "$query->alias.smw_id";
203 - $query->where = "$query->alias.smw_namespace=" . $this->m_dbs->addQuotes($description->getNamespace());
204 - } elseif ( ($description instanceof SMWConjunction) || ($description instanceof SMWDisjunction) ) {
205 - $query->type = ($description instanceof SMWConjunction)?SMW_SQL2_CONJUNCTION:SMW_SQL2_DISJUNCTION;
206 - foreach ($description->getDescriptions() as $subdesc) {
207 - $sub = $this->compileQueries($subdesc);
208 - if ($sub >= 0) {
 203+ $query->where = "$query->alias.smw_namespace=" . $this->m_dbs->addQuotes( $description->getNamespace() );
 204+ } elseif ( ( $description instanceof SMWConjunction ) || ( $description instanceof SMWDisjunction ) ) {
 205+ $query->type = ( $description instanceof SMWConjunction ) ? SMW_SQL2_CONJUNCTION:SMW_SQL2_DISJUNCTION;
 206+ foreach ( $description->getDescriptions() as $subdesc ) {
 207+ $sub = $this->compileQueries( $subdesc );
 208+ if ( $sub >= 0 ) {
209209 $query->components[$sub] = true;
210210 }
211211 }
212 - } elseif ($description instanceof SMWClassDescription) {
 212+ } elseif ( $description instanceof SMWClassDescription ) {
213213 $cqid = SMWSQLStore2Query::$qnum;
214214 $cquery = new SMWSQLStore2Query();
215215 $cquery->type = SMW_SQL2_CLASS_HIERARCHY;
216216 $cquery->joinfield = array();
217 - foreach ($description->getCategories() as $cat) {
218 - $cid = $this->m_store->getSMWPageID($cat->getDBkey(), NS_CATEGORY, $cat->getInterwiki());
219 - if ($cid != 0) {
 217+ foreach ( $description->getCategories() as $cat ) {
 218+ $cid = $this->m_store->getSMWPageID( $cat->getDBkey(), NS_CATEGORY, $cat->getInterwiki() );
 219+ if ( $cid != 0 ) {
220220 $cquery->joinfield[] = $cid;
221221 }
222222 }
223 - if (count($cquery->joinfield) == 0) { // empty result
 223+ if ( count( $cquery->joinfield ) == 0 ) { // empty result
224224 $query->type = SMW_SQL2_VALUE;
225225 $query->jointable = '';
226226 $query->joinfield = '';
@@ -229,70 +229,70 @@
230230 $query->components[$cqid] = "$query->alias.o_id";
231231 $this->m_queries[$cqid] = $cquery;
232232 }
233 - } elseif ($description instanceof SMWValueDescription) { // only type '_wpg' objects can appear on query level (essentially as nominal classes)
234 - if ($description->getDatavalue()->getTypeID() == '_wpg') {
235 - if ($description->getComparator() == SMW_CMP_EQ) {
 233+ } elseif ( $description instanceof SMWValueDescription ) { // only type '_wpg' objects can appear on query level (essentially as nominal classes)
 234+ if ( $description->getDatavalue()->getTypeID() == '_wpg' ) {
 235+ if ( $description->getComparator() == SMW_CMP_EQ ) {
236236 $query->type = SMW_SQL2_VALUE;
237 - $oid = $this->m_store->getSMWPageID($description->getDatavalue()->getDBkey(), $description->getDatavalue()->getNamespace(),$description->getDatavalue()->getInterwiki());
238 - $query->joinfield = array($oid);
 237+ $oid = $this->m_store->getSMWPageID( $description->getDatavalue()->getDBkey(), $description->getDatavalue()->getNamespace(), $description->getDatavalue()->getInterwiki() );
 238+ $query->joinfield = array( $oid );
239239 } else { // join with smw_ids needed for other comparators (apply to title string)
240240 $query->jointable = 'smw_ids';
241241 $query->joinfield = "$query->alias.smw_id";
242242 $value = $description->getDatavalue()->getSortkey();
243 - switch ($description->getComparator()) {
 243+ switch ( $description->getComparator() ) {
244244 case SMW_CMP_LEQ: $comp = '<='; break;
245245 case SMW_CMP_GEQ: $comp = '>='; break;
246246 case SMW_CMP_NEQ: $comp = '!='; break;
247247 case SMW_CMP_LIKE:
248248 $comp = ' LIKE ';
249 - $value = str_replace(array('%', '_', '*', '?'), array('\%', '\_', '%', '_'), $value);
 249+ $value = str_replace( array( '%', '_', '*', '?' ), array( '\%', '\_', '%', '_' ), $value );
250250 break;
251251 }
252 - $query->where = "$query->alias.smw_sortkey$comp" . $this->m_dbs->addQuotes($value);
 252+ $query->where = "$query->alias.smw_sortkey$comp" . $this->m_dbs->addQuotes( $value );
253253 }
254254 }
255 - } elseif ($description instanceof SMWConceptDescription) { // fetch concept definition and insert it here
256 - $cid = $this->m_store->getSMWPageID($description->getConcept()->getDBKey(), SMW_NS_CONCEPT, '');
257 - $row = $this->m_dbs->selectRow('smw_conc2',
258 - array('concept_txt','concept_features','concept_size','concept_depth','cache_date'),
259 - array('s_id'=>$cid), 'SMWSQLStore2Queries::compileQueries');
 255+ } elseif ( $description instanceof SMWConceptDescription ) { // fetch concept definition and insert it here
 256+ $cid = $this->m_store->getSMWPageID( $description->getConcept()->getDBKey(), SMW_NS_CONCEPT, '' );
 257+ $row = $this->m_dbs->selectRow( 'smw_conc2',
 258+ array( 'concept_txt', 'concept_features', 'concept_size', 'concept_depth', 'cache_date' ),
 259+ array( 's_id' => $cid ), 'SMWSQLStore2Queries::compileQueries' );
260260 if ( $row === false ) { // no description found, concept does not exist
261261 // keep the above query object, it yields an empty result
262 - ///TODO: announce an error here? (maybe not, since the query processor can check for
263 - ///non-existing concept pages which is probably the main reason for finding nothing here
 262+ // /TODO: announce an error here? (maybe not, since the query processor can check for
 263+ // /non-existing concept pages which is probably the main reason for finding nothing here
264264 } else {
265265 global $smwgQConceptCaching, $smwgQMaxSize, $smwgQMaxDepth, $smwgQFeatures, $smwgQConceptCacheLifetime;
266 - $may_be_computed = ($smwgQConceptCaching == CONCEPT_CACHE_NONE) ||
267 - ( ($smwgQConceptCaching == CONCEPT_CACHE_HARD) && ( (~(~($row->concept_features+0) | $smwgQFeatures)) == 0) &&
268 - ($smwgQMaxSize >= $row->concept_size) && ($smwgQMaxDepth >= $row->concept_depth));
269 - if ($row->cache_date &&
270 - ($row->cache_date > (strtotime("now") - $smwgQConceptCacheLifetime*60) ||
271 - !$may_be_computed)) { // cached concept, use cache unless it is dead and can be revived
 266+ $may_be_computed = ( $smwgQConceptCaching == CONCEPT_CACHE_NONE ) ||
 267+ ( ( $smwgQConceptCaching == CONCEPT_CACHE_HARD ) && ( ( ~( ~( $row->concept_features + 0 ) | $smwgQFeatures ) ) == 0 ) &&
 268+ ( $smwgQMaxSize >= $row->concept_size ) && ( $smwgQMaxDepth >= $row->concept_depth ) );
 269+ if ( $row->cache_date &&
 270+ ( $row->cache_date > ( strtotime( "now" ) - $smwgQConceptCacheLifetime * 60 ) ||
 271+ !$may_be_computed ) ) { // cached concept, use cache unless it is dead and can be revived
272272 $query->jointable = 'smw_conccache';
273273 $query->joinfield = "$query->alias.s_id";
274 - $query->where = "$query->alias.o_id=" . $this->m_dbs->addQuotes($cid);
275 - } elseif ($row->concept_txt) { // parse description and process it recursively
276 - if ($may_be_computed) {
 274+ $query->where = "$query->alias.o_id=" . $this->m_dbs->addQuotes( $cid );
 275+ } elseif ( $row->concept_txt ) { // parse description and process it recursively
 276+ if ( $may_be_computed ) {
277277 $qp = new SMWQueryParser();
278278 // no defaultnamespaces here; if any, these are already in the concept
279 - $desc = $qp->getQueryDescription($row->concept_txt);
280 - $qid = $this->compileQueries($desc);
 279+ $desc = $qp->getQueryDescription( $row->concept_txt );
 280+ $qid = $this->compileQueries( $desc );
281281 $query = $this->m_queries[$qid];
282282 } else {
283 - wfLoadExtensionMessages('SemanticMediaWiki');
284 - $this->m_errors[] = wfMsg('smw_concept_cache_miss',$description->getConcept()->getText());
 283+ wfLoadExtensionMessages( 'SemanticMediaWiki' );
 284+ $this->m_errors[] = wfMsg( 'smw_concept_cache_miss', $description->getConcept()->getText() );
285285 }
286286 } // else: no cache, no description (this may happen); treat like empty concept
287287 }
288288 } else { // (e.g. SMWThingDescription, SMWValueList is also treated elswhere)
289 - $qid = -1; // no condition
 289+ $qid = - 1; // no condition
290290 }
291 - if ($qid >= 0) {
 291+ if ( $qid >= 0 ) {
292292 $this->m_queries[$qid] = $query;
293293 }
294 - if ($query->type != SMW_SQL2_DISJUNCTION) { // sortkeys are killed by disjunctions (not all parts may have them), preprocessing might try to push disjunctions downwards to safe sortkey
295 - foreach ($query->components as $cid => $field) {
296 - $query->sortfields = array_merge($this->m_queries[$cid]->sortfields,$query->sortfields);
 294+ if ( $query->type != SMW_SQL2_DISJUNCTION ) { // sortkeys are killed by disjunctions (not all parts may have them), preprocessing might try to push disjunctions downwards to safe sortkey
 295+ foreach ( $query->components as $cid => $field ) {
 296+ $query->sortfields = array_merge( $this->m_queries[$cid]->sortfields, $query->sortfields );
297297 }
298298 }
299299 return $qid;
@@ -306,68 +306,68 @@
307307 * Some properties cannot be queried for; in this case, the query type is changed to SMW_SQL2_NOQUERY.
308308 * Callers need to check for this.
309309 */
310 - protected function compilePropertyCondition(&$query, $property, SMWDescription $valuedesc, $typeid=false) {
 310+ protected function compilePropertyCondition( &$query, $property, SMWDescription $valuedesc, $typeid = false ) {
311311 $query->joinfield = "$query->alias.s_id";
312 - if ($property instanceof SMWPropertyValue) {
 312+ if ( $property instanceof SMWPropertyValue ) {
313313 $typeid = $property->getTypeID();
314 - $mode = SMWSQLStore2::getStorageMode($typeid);
315 - $pid = $this->m_store->getSMWPropertyID($property);
 314+ $mode = SMWSQLStore2::getStorageMode( $typeid );
 315+ $pid = $this->m_store->getSMWPropertyID( $property );
316316 $sortkey = $property->getXSDValue();
317 - if ($mode != SMW_SQL2_SUBS2) { // also make property hierarchy (though not for all properties)
 317+ if ( $mode != SMW_SQL2_SUBS2 ) { // also make property hierarchy (though not for all properties)
318318 $pqid = SMWSQLStore2Query::$qnum;
319319 $pquery = new SMWSQLStore2Query();
320320 $pquery->type = SMW_SQL2_PROP_HIERARCHY;
321 - $pquery->joinfield = array($pid);
 321+ $pquery->joinfield = array( $pid );
322322 $query->components[$pqid] = "$query->alias.p_id";
323323 $this->m_queries[$pqid] = $pquery;
324324 }
325325 } else {
326326 $pid = $property;
327327 $sortkey = false;
328 - $mode = SMWSQLStore2::getStorageMode($typeid);
329 - if ($mode != SMW_SQL2_SUBS2) { // no property hierarchy, but normal query (not for all properties)
330 - $query->where = "$query->alias.p_id=" . $this->m_dbs->addQuotes($pid);
 328+ $mode = SMWSQLStore2::getStorageMode( $typeid );
 329+ if ( $mode != SMW_SQL2_SUBS2 ) { // no property hierarchy, but normal query (not for all properties)
 330+ $query->where = "$query->alias.p_id=" . $this->m_dbs->addQuotes( $pid );
331331 }
332332 }
333 - $mode = SMWSQLStore2::getStorageMode($typeid);
 333+ $mode = SMWSQLStore2::getStorageMode( $typeid );
334334 $sortfield = ''; // used if we should sort by this property
335 - switch ($mode) {
 335+ switch ( $mode ) {
336336 case SMW_SQL2_RELS2: case SMW_SQL2_SUBS2: // subconditions as subqueries (compiled)
337 - $query->jointable = ($mode==SMW_SQL2_RELS2)?'smw_rels2':'smw_subs2';
338 - $sub = $this->compileQueries($valuedesc);
339 - if ($sub >= 0) {
 337+ $query->jointable = ( $mode == SMW_SQL2_RELS2 ) ? 'smw_rels2':'smw_subs2';
 338+ $sub = $this->compileQueries( $valuedesc );
 339+ if ( $sub >= 0 ) {
340340 $query->components[$sub] = "$query->alias.o_id";
341341 }
342 - if ( $sortkey && array_key_exists($sortkey, $this->m_sortkeys) ) {
343 - $query->from = ' INNER JOIN ' . $this->m_dbs->tableName('smw_ids') . " AS ids$query->alias ON ids$query->alias.smw_id=$query->alias.o_id";
344 - $sortfield = "ids$query->alias.smw_title"; /// TODO: as below, smw_ids here is possibly duplicated! Can we prevent that? (PERFORMANCE)
 342+ if ( $sortkey && array_key_exists( $sortkey, $this->m_sortkeys ) ) {
 343+ $query->from = ' INNER JOIN ' . $this->m_dbs->tableName( 'smw_ids' ) . " AS ids$query->alias ON ids$query->alias.smw_id=$query->alias.o_id";
 344+ $sortfield = "ids$query->alias.smw_title"; // / TODO: as below, smw_ids here is possibly duplicated! Can we prevent that? (PERFORMANCE)
345345 }
346346 break;
347347 case SMW_SQL2_NARY2:
348348 $query->jointable = 'smw_rels2';
349 - if ($valuedesc instanceof SMWValueList) { // anything else is ignored!
 349+ if ( $valuedesc instanceof SMWValueList ) { // anything else is ignored!
350350 $typevalue = $property->getTypesValue();
351351 $typelabels = $typevalue->getTypeLabels();
352 - reset($typelabels);
 352+ reset( $typelabels );
353353 $subqid = SMWSQLStore2Query::$qnum;
354354 $subquery = new SMWSQLStore2Query();
355355 $subquery->type = SMW_SQL2_CONJUNCTION;
356356 $query->components[$subqid] = "$query->alias.o_id";
357357 $this->m_queries[$subqid] = $subquery;
358 - for ($i=0; $i<$valuedesc->getCount(); $i++) {
359 - $desc = $valuedesc->getDescription($i);
360 - if ($desc !== NULL) {
361 - $stypeid = SMWDataValueFactory::findTypeID(current($typelabels));
362 - $valpid = $this->m_store->getSMWPageID(strval($i),SMW_NS_PROPERTY,SMW_SQL2_SMWIW);
 358+ for ( $i = 0; $i < $valuedesc->getCount(); $i++ ) {
 359+ $desc = $valuedesc->getDescription( $i );
 360+ if ( $desc !== NULL ) {
 361+ $stypeid = SMWDataValueFactory::findTypeID( current( $typelabels ) );
 362+ $valpid = $this->m_store->getSMWPageID( strval( $i ), SMW_NS_PROPERTY, SMW_SQL2_SMWIW );
363363 $valqid = SMWSQLStore2Query::$qnum;
364364 $valquery = new SMWSQLStore2Query();
365 - $this->compilePropertyCondition($valquery, $valpid, $desc, $stypeid);
366 - if ($valquery->type != SMW_SQL2_NOQUERY) {
 365+ $this->compilePropertyCondition( $valquery, $valpid, $desc, $stypeid );
 366+ if ( $valquery->type != SMW_SQL2_NOQUERY ) {
367367 $subquery->components[$valqid] = true;
368368 $this->m_queries[$valqid] = $valquery;
369369 }
370370 }
371 - next($typelabels);
 371+ next( $typelabels );
372372 }
373373 }
374374 break;
@@ -375,14 +375,14 @@
376376 $query->jointable = 'smw_text2';
377377 break;
378378 case SMW_SQL2_ATTS2: case SMW_SQL2_SPEC2: // subquery only conj/disj of values, compile to single "where"
379 - $query->jointable = ($mode==SMW_SQL2_ATTS2)?'smw_atts2':'smw_spec2';
380 - $aw = $this->compileAttributeWhere($valuedesc,"$query->alias");
381 - if ($aw != '') {
382 - $query->where .= ($query->where?' AND ':'') . $aw;
 379+ $query->jointable = ( $mode == SMW_SQL2_ATTS2 ) ? 'smw_atts2':'smw_spec2';
 380+ $aw = $this->compileAttributeWhere( $valuedesc, "$query->alias" );
 381+ if ( $aw != '' ) {
 382+ $query->where .= ( $query->where ? ' AND ':'' ) . $aw;
383383 }
384 - if ( $sortkey && array_key_exists($sortkey, $this->m_sortkeys) ) {
385 - if ($mode==SMW_SQL2_ATTS2) {
386 - $sortfield = "$query->alias." . (SMWDataValueFactory::newTypeIDValue($typeid)->isNumeric()?'value_num':'value_xsd');
 384+ if ( $sortkey && array_key_exists( $sortkey, $this->m_sortkeys ) ) {
 385+ if ( $mode == SMW_SQL2_ATTS2 ) {
 386+ $sortfield = "$query->alias." . ( SMWDataValueFactory::newTypeIDValue( $typeid )->isNumeric() ? 'value_num':'value_xsd' );
387387 } else {
388388 $sortfield = "$query->alias.value_string";
389389 }
@@ -392,7 +392,7 @@
393393 $query->type = SMW_SQL2_NOQUERY;
394394 $sortfield = false;
395395 }
396 - if ($sortfield) {
 396+ if ( $sortfield ) {
397397 $query->sortfields[$sortkey] = $sortfield;
398398 }
399399 }
@@ -401,36 +401,36 @@
402402 * Given an SMWDescription that is just a conjunction or disjunction of
403403 * SMWValueDescription objects, create a plain WHERE condition string for it.
404404 */
405 - protected function compileAttributeWhere(SMWDescription $description, $jointable) {
406 - if ($description instanceof SMWValueDescription) {
 405+ protected function compileAttributeWhere( SMWDescription $description, $jointable ) {
 406+ if ( $description instanceof SMWValueDescription ) {
407407 $dv = $description->getDatavalue();
408 - if (SMWSQLStore2::getStorageMode($dv->getTypeID()) == SMW_SQL2_SPEC2) {
 408+ if ( SMWSQLStore2::getStorageMode( $dv->getTypeID() ) == SMW_SQL2_SPEC2 ) {
409409 $value = $dv->getXSDValue();
410410 $field = "$jointable.value_string";
411 - } else { //should be SMW_SQL2_ATTS2
 411+ } else { // should be SMW_SQL2_ATTS2
412412 $value = $dv->isNumeric() ? $dv->getNumericValue() : $dv->getXSDValue();
413413 $field = $dv->isNumeric() ? "$jointable.value_num" : "$jointable.value_xsd";
414414 }
415 - switch ($description->getComparator()) {
 415+ switch ( $description->getComparator() ) {
416416 case SMW_CMP_LEQ: $comp = '<='; break;
417417 case SMW_CMP_GEQ: $comp = '>='; break;
418418 case SMW_CMP_NEQ: $comp = '!='; break;
419419 case SMW_CMP_LIKE:
420 - if ($dv->getTypeID() == '_str') {
 420+ if ( $dv->getTypeID() == '_str' ) {
421421 $comp = ' LIKE ';
422 - $value = str_replace(array('%', '_', '*', '?'), array('\%', '\_', '%', '_'), $value);
 422+ $value = str_replace( array( '%', '_', '*', '?' ), array( '\%', '\_', '%', '_' ), $value );
423423 } else { // LIKE only supported for strings
424424 $comp = '=';
425425 }
426426 break;
427427 case SMW_CMP_EQ: default: $comp = '='; break;
428428 }
429 - $result = "$field$comp" . $this->m_dbs->addQuotes($value);
430 - } elseif ( ($description instanceof SMWConjunction) || ($description instanceof SMWDisjunction) ) {
431 - $op = ($description instanceof SMWConjunction) ? ' AND ' : ' OR ';
 429+ $result = "$field$comp" . $this->m_dbs->addQuotes( $value );
 430+ } elseif ( ( $description instanceof SMWConjunction ) || ( $description instanceof SMWDisjunction ) ) {
 431+ $op = ( $description instanceof SMWConjunction ) ? ' AND ' : ' OR ';
432432 $result = '';
433 - foreach ($description->getDescriptions() as $subdesc) {
434 - $result= $result . ( $result!=''?$op:'' ) . $this->compileAttributeWhere($subdesc,$jointable);
 433+ foreach ( $description->getDescriptions() as $subdesc ) {
 434+ $result = $result . ( $result != '' ? $op:'' ) . $this->compileAttributeWhere( $subdesc, $jointable );
435435 }
436436 $result = "($result)";
437437 } else {
@@ -444,23 +444,23 @@
445445 * so that it contains non-recursive description of a select to execute for getting
446446 * the actual result.
447447 */
448 - protected function executeQueries(SMWSQLStore2Query &$query) {
449 - switch ($query->type) {
 448+ protected function executeQueries( SMWSQLStore2Query &$query ) {
 449+ switch ( $query->type ) {
450450 case SMW_SQL2_TABLE: // normal query with conjunctive subcondition
451 - foreach ($query->components as $qid => $joinfield) {
 451+ foreach ( $query->components as $qid => $joinfield ) {
452452 $subquery = $this->m_queries[$qid];
453 - $this->executeQueries($subquery);
454 - if ($subquery->jointable != '') { // join with jointable.joinfield
455 - $query->from .= ' INNER JOIN ' . $this->m_dbs->tableName($subquery->jointable) . " AS $subquery->alias ON $joinfield=" . $subquery->joinfield;
456 - } elseif ($subquery->joinfield !== '') { // require joinfield as "value" via WHERE
 453+ $this->executeQueries( $subquery );
 454+ if ( $subquery->jointable != '' ) { // join with jointable.joinfield
 455+ $query->from .= ' INNER JOIN ' . $this->m_dbs->tableName( $subquery->jointable ) . " AS $subquery->alias ON $joinfield=" . $subquery->joinfield;
 456+ } elseif ( $subquery->joinfield !== '' ) { // require joinfield as "value" via WHERE
457457 $condition = '';
458 - foreach ($subquery->joinfield as $value) {
459 - $condition .= ($condition?' OR ':'') . "$joinfield=" . $this->m_dbs->addQuotes($value);
 458+ foreach ( $subquery->joinfield as $value ) {
 459+ $condition .= ( $condition ? ' OR ':'' ) . "$joinfield=" . $this->m_dbs->addQuotes( $value );
460460 }
461 - if (count($subquery->joinfield) > 1) {
 461+ if ( count( $subquery->joinfield ) > 1 ) {
462462 $condition = "($condition)";
463463 }
464 - $query->where .= (($query->where == '')?'':' AND ') . $condition;
 464+ $query->where .= ( ( $query->where == '' ) ? '':' AND ' ) . $condition;
465465 } else { // interpret empty joinfields as impossible condition (empty result)
466466 $query->joinfield = ''; // make whole query false
467467 $query->jointable = '';
@@ -468,8 +468,8 @@
469469 $query->from = '';
470470 break;
471471 }
472 - if ($subquery->where != '') {
473 - $query->where .= (($query->where == '')?'':' AND ') . $subquery->where;
 472+ if ( $subquery->where != '' ) {
 473+ $query->where .= ( ( $query->where == '' ) ? '':' AND ' ) . $subquery->where;
474474 }
475475 $query->from .= $subquery->from;
476476 }
@@ -477,29 +477,29 @@
478478 break;
479479 case SMW_SQL2_CONJUNCTION:
480480 // pick one subquery with jointable as anchor point ...
481 - reset($query->components);
 481+ reset( $query->components );
482482 $key = false;
483 - foreach ($query->components as $qkey => $qid) {
484 - if ($this->m_queries[$qkey]->jointable != '') {
 483+ foreach ( $query->components as $qkey => $qid ) {
 484+ if ( $this->m_queries[$qkey]->jointable != '' ) {
485485 $key = $qkey;
486486 break;
487487 }
488488 }
489 - if ($key !== false) {
 489+ if ( $key !== false ) {
490490 $result = $this->m_queries[$key];
491 - unset($query->components[$key]);
492 - $this->executeQueries($result); // execute it first (may change jointable and joinfield, e.g. when making temporary tables)
 491+ unset( $query->components[$key] );
 492+ $this->executeQueries( $result ); // execute it first (may change jointable and joinfield, e.g. when making temporary tables)
493493 // ... and append to this query the remaining queries
494 - foreach ($query->components as $qid => $joinfield) {
 494+ foreach ( $query->components as $qid => $joinfield ) {
495495 $result->components[$qid] = $result->joinfield;
496496 }
497 - $this->executeQueries($result); // second execute, now incorporating remaining conditions
 497+ $this->executeQueries( $result ); // second execute, now incorporating remaining conditions
498498 } else { // only fixed values in conjunction, make a new value without joining
499499 $key = $qkey;
500500 $result = $this->m_queries[$key];
501 - unset($query->components[$key]);
502 - foreach ($query->components as $qid => $joinfield) {
503 - if ($result->joinfield != $this->m_queries[$qid]->joinfield) {
 501+ unset( $query->components[$key] );
 502+ foreach ( $query->components as $qid => $joinfield ) {
 503+ if ( $result->joinfield != $this->m_queries[$qid]->joinfield ) {
504504 $result->joinfield = ''; // all other values should already be ''
505505 break;
506506 }
@@ -507,31 +507,31 @@
508508 }
509509 $query = $result;
510510 break;
511 - case SMW_SQL2_DISJUNCTION:
512 - // modified by dch, disable TEMPORARY tables
 511+ case SMW_SQL2_DISJUNCTION:
 512+ // modified by dch, disable TEMPORARY tables
513513 // if ($this->m_qmode !== SMWQuery::MODE_DEBUG) {
514514 // $this->m_dbs->query( "CREATE TEMPORARY TABLE " . $this->m_dbs->tableName($query->alias) .
515515 // ' ( id INT UNSIGNED KEY ) TYPE=MEMORY', 'SMW::executeQueries' );
516516 // }
517517 // $this->m_querylog[$query->alias] = array();
518 - foreach ($query->components as $qid => $joinfield) {
 518+ foreach ( $query->components as $qid => $joinfield ) {
519519 $subquery = $this->m_queries[$qid];
520 - $this->executeQueries($subquery);
 520+ $this->executeQueries( $subquery );
521521 $sql = '';
522 - if ($subquery->jointable != '') {
 522+ if ( $subquery->jointable != '' ) {
523523 // $sql = "INSERT IGNORE INTO " . $this->m_dbs->tableName($query->alias) . " SELECT $subquery->joinfield FROM " .
524524 // $this->m_dbs->tableName($subquery->jointable) . " AS $subquery->alias $subquery->from" . ($subquery->where?" WHERE $subquery->where":'');
525 - $sql = ($sql != ''?'UNION':''). "SELECT $subquery->joinfield AS id FROM " .
526 - $this->m_dbs->tableName($subquery->jointable) . " AS $subquery->alias $subquery->from" . ($subquery->where?" WHERE $subquery->where":'');
527 - } elseif ($subquery->joinfield !== '') {
528 - /// NOTE: this works only for single "unconditional" values without further
529 - /// WHERE or FROM. The execution must take care of not creating any others.
 525+ $sql = ( $sql != '' ? 'UNION':'' ) . "SELECT $subquery->joinfield AS id FROM " .
 526+ $this->m_dbs->tableName( $subquery->jointable ) . " AS $subquery->alias $subquery->from" . ( $subquery->where ? " WHERE $subquery->where":'' );
 527+ } elseif ( $subquery->joinfield !== '' ) {
 528+ // / NOTE: this works only for single "unconditional" values without further
 529+ // / WHERE or FROM. The execution must take care of not creating any others.
530530 $values = '';
531 - foreach ($subquery->joinfield as $value) {
532 - $values .= ($values?',':'') . '(' . $this->m_dbs->addQuotes($value) . ')';
 531+ foreach ( $subquery->joinfield as $value ) {
 532+ $values .= ( $values ? ',':'' ) . '(' . $this->m_dbs->addQuotes( $value ) . ')';
533533 }
534534 // $sql = "INSERT IGNORE INTO " . $this->m_dbs->tableName($query->alias) . " (id) VALUES $values";
535 - $sql = ($sql != ''?'UNION':''). "SELECT smw_id AS id FROM ".$this->m_dbs->tableName('smw_ids')." WHERE smw_id IN ($values)";
 535+ $sql = ( $sql != '' ? 'UNION':'' ) . "SELECT smw_id AS id FROM " . $this->m_dbs->tableName( 'smw_ids' ) . " WHERE smw_id IN ($values)";
536536 } // else: // interpret empty joinfields as impossible condition (empty result), ignore
537537 // if ($sql) {
538538 // $this->m_querylog[$query->alias][] = $sql;
@@ -541,74 +541,74 @@
542542 // }
543543 }
544544 // $query->jointable = $query->alias;
545 - $query->jointable = "($sql)";
 545+ $query->jointable = "($sql)";
546546 $query->joinfield = "$query->alias.id";
547547 $query->sortfields = array(); // make sure we got no sortfields
548 - /// TODO: currently this eliminates sortkeys, possibly keep them (needs different temp table format though, maybe not such a good thing to do)
 548+ // / TODO: currently this eliminates sortkeys, possibly keep them (needs different temp table format though, maybe not such a good thing to do)
549549 break;
550550 case SMW_SQL2_PROP_HIERARCHY: case SMW_SQL2_CLASS_HIERARCHY: // make a saturated hierarchy
551 - $this->executeHierarchyQuery($query);
 551+ $this->executeHierarchyQuery( $query );
552552 break;
553553 case SMW_SQL2_VALUE: break; // nothing to do
554554 }
555555 }
556 -
 556+
557557 /**
558558 * Find subproperties or subcategories. This may require iterative computation,
559559 * and temporary tables are used in many cases.
560560 */
561 - protected function executeHierarchyQuery(&$query) {
 561+ protected function executeHierarchyQuery( &$query ) {
562562 $fname = "SMWSQLStore2Queries::executeQueries-hierarchy-$query->type (SMW)";
563 - wfProfileIn($fname);
 563+ wfProfileIn( $fname );
564564 global $smwgQSubpropertyDepth, $smwgQSubcategoryDepth;
565 - $depth = ($query->type == SMW_SQL2_PROP_HIERARCHY)?$smwgQSubpropertyDepth:$smwgQSubcategoryDepth;
566 - if ($depth <= 0) { // treat as value, no recursion
 565+ $depth = ( $query->type == SMW_SQL2_PROP_HIERARCHY ) ? $smwgQSubpropertyDepth:$smwgQSubcategoryDepth;
 566+ if ( $depth <= 0 ) { // treat as value, no recursion
567567 $query->type = SMW_SQL2_VALUE;
568 - wfProfileOut($fname);
 568+ wfProfileOut( $fname );
569569 return;
570570 }
571571 $values = '';
572572 $valuecond = '';
573 - foreach ($query->joinfield as $value) {
574 - $values .= ($values?',':'') . '(' . $this->m_dbs->addQuotes($value) . ')';
575 - $valuecond .= ($valuecond?' OR ':'') . 'o_id=' . $this->m_dbs->addQuotes($value);
 573+ foreach ( $query->joinfield as $value ) {
 574+ $values .= ( $values ? ',':'' ) . '(' . $this->m_dbs->addQuotes( $value ) . ')';
 575+ $valuecond .= ( $valuecond ? ' OR ':'' ) . 'o_id=' . $this->m_dbs->addQuotes( $value );
576576 }
577 - $smw_subs2 = $this->m_dbs->tableName('smw_subs2');
 577+ $smw_subs2 = $this->m_dbs->tableName( 'smw_subs2' );
578578 // try to safe time (SELECT is cheaper than creating/dropping 3 temp tables):
579 - $res = $this->m_dbs->select($smw_subs2,'s_id',$valuecond, array('LIMIT'=>1));
580 - if (!$this->m_dbs->fetchObject($res)) { // no subobjects, we are done!
581 - $this->m_dbs->freeResult($res);
 579+ $res = $this->m_dbs->select( $smw_subs2, 's_id', $valuecond, array( 'LIMIT' => 1 ) );
 580+ if ( !$this->m_dbs->fetchObject( $res ) ) { // no subobjects, we are done!
 581+ $this->m_dbs->freeResult( $res );
582582 $query->type = SMW_SQL2_VALUE;
583 - wfProfileOut($fname);
 583+ wfProfileOut( $fname );
584584 return;
585585 }
586 - $this->m_dbs->freeResult($res);
587 - $tablename = $this->m_dbs->tableName($query->alias);
588 - // modified by dch
589 -// $this->m_querylog[$query->alias] = array("Recursively computed hierarchy for element(s) $values.");
590 - $this->m_querylog[$query->alias]["$depth:$values"] = "Recursively computed hierarchy for element(s) $values.";
591 -
592 - $query->jointable = $query->alias;
 586+ $this->m_dbs->freeResult( $res );
 587+ $tablename = $this->m_dbs->tableName( $query->alias );
 588+ // modified by dch
 589+// $this->m_querylog[$query->alias] = array("Recursively computed hierarchy for element(s) $values.");
 590+ $this->m_querylog[$query->alias]["$depth:$values"] = "Recursively computed hierarchy for element(s) $values.";
 591+
 592+ $query->jointable = $query->alias;
593593 $query->joinfield = "$query->alias.id";
594 - if ($this->m_qmode == SMWQuery::MODE_DEBUG) {
595 - wfProfileOut($fname);
 594+ if ( $this->m_qmode == SMWQuery::MODE_DEBUG ) {
 595+ wfProfileOut( $fname );
596596 return; // no real queries in debug mode
597 - }
598 -
 597+ }
 598+
599599 $this->m_dbs->query( "CREATE TEMPORARY TABLE $tablename " .
600600 '( id INT UNSIGNED NOT NULL KEY) TYPE=MEMORY', 'SMW::executeQueries' );
601 - if (array_key_exists($values, $this->m_hierarchies)) { // just copy known result
602 - $this->m_dbs->query("INSERT INTO $tablename (id) SELECT id" .
603 - ' FROM ' . $this->m_hierarchies[$values],
604 - 'SMW::executeQueries');
605 - wfProfileOut($fname);
 601+ if ( array_key_exists( $values, $this->m_hierarchies ) ) { // just copy known result
 602+ $this->m_dbs->query( "INSERT INTO $tablename (id) SELECT id" .
 603+ ' FROM ' . $this->m_hierarchies[$values],
 604+ 'SMW::executeQueries' );
 605+ wfProfileOut( $fname );
606606 return;
607607 }
608608
609 - /// NOTE: we use two helper tables. One holds the results of each new iteration, one holds the
610 - /// results of the previous iteration. One could of course do with only the above result table,
611 - /// but then every iteration would use all elements of this table, while only the new ones
612 - /// obtained in the previous step are relevant. So this is a performance measure.
 609+ // / NOTE: we use two helper tables. One holds the results of each new iteration, one holds the
 610+ // / results of the previous iteration. One could of course do with only the above result table,
 611+ // / but then every iteration would use all elements of this table, while only the new ones
 612+ // / obtained in the previous step are relevant. So this is a performance measure.
613613 $tmpnew = 'smw_new';
614614 $tmpres = 'smw_res';
615615 $this->m_dbs->query( "CREATE TEMPORARY TABLE $tmpnew " .
@@ -616,39 +616,39 @@
617617 $this->m_dbs->query( "CREATE TEMPORARY TABLE $tmpres " .
618618 '( id INT UNSIGNED ) TYPE=MEMORY', 'SMW::executeQueries' );
619619
620 - $this->m_dbs->query("INSERT IGNORE INTO $tablename (id) VALUES $values", 'SMW::executeQueries');
621 - $this->m_dbs->query("INSERT IGNORE INTO $tmpnew (id) VALUES $values", 'SMW::executeQueries');
 620+ $this->m_dbs->query( "INSERT IGNORE INTO $tablename (id) VALUES $values", 'SMW::executeQueries' );
 621+ $this->m_dbs->query( "INSERT IGNORE INTO $tmpnew (id) VALUES $values", 'SMW::executeQueries' );
622622
623 - for ($i=0; $i<$depth; $i++) {
624 - $this->m_dbs->query("INSERT INTO $tmpres (id) SELECT s_id FROM $smw_subs2, $tmpnew WHERE o_id=id",
625 - 'SMW::executeQueries');
626 - if ($this->m_dbs->affectedRows() == 0) { // no change, exit loop
 623+ for ( $i = 0; $i < $depth; $i++ ) {
 624+ $this->m_dbs->query( "INSERT INTO $tmpres (id) SELECT s_id FROM $smw_subs2, $tmpnew WHERE o_id=id",
 625+ 'SMW::executeQueries' );
 626+ if ( $this->m_dbs->affectedRows() == 0 ) { // no change, exit loop
627627 break;
628628 }
629 - $this->m_dbs->query("INSERT IGNORE INTO $tablename (id) SELECT $tmpres.id FROM $tmpres",
630 - 'SMW::executeQueries');
631 - if ($this->m_dbs->affectedRows() == 0) { // no change, exit loop
 629+ $this->m_dbs->query( "INSERT IGNORE INTO $tablename (id) SELECT $tmpres.id FROM $tmpres",
 630+ 'SMW::executeQueries' );
 631+ if ( $this->m_dbs->affectedRows() == 0 ) { // no change, exit loop
632632 break;
633 - }
634 -
635 - $this->m_dbs->query('TRUNCATE TABLE ' . $tmpnew, 'SMW::executeQueries'); // empty "new" table
 633+ }
 634+
 635+ $this->m_dbs->query( 'TRUNCATE TABLE ' . $tmpnew, 'SMW::executeQueries' ); // empty "new" table
636636 $tmpname = $tmpnew;
637637 $tmpnew = $tmpres;
638638 $tmpres = $tmpname;
639 - }
640 -
 639+ }
 640+
641641 $this->m_hierarchies[$values] = $tablename;
642 - $this->m_dbs->query('DROP TEMPORARY TABLE smw_new', 'SMW::executeQueries');
643 - $this->m_dbs->query('DROP TEMPORARY TABLE smw_res', 'SMW::executeQueries');
644 - wfProfileOut($fname);
 642+ $this->m_dbs->query( 'DROP TEMPORARY TABLE smw_new', 'SMW::executeQueries' );
 643+ $this->m_dbs->query( 'DROP TEMPORARY TABLE smw_res', 'SMW::executeQueries' );
 644+ wfProfileOut( $fname );
645645 }
646646
647647 /**
648 - * This function modifies the given query object at $qid to account for all ordering conditions
649 - * in the SMWQuery $query. It is always required that $qid is the id of a query that joins with
 648+ * This function modifies the given query object at $qid to account for all ordering conditions
 649+ * in the SMWQuery $query. It is always required that $qid is the id of a query that joins with
650650 * smw_ids so that the field alias.smw_title is $available for default sorting.
651651 */
652 - protected function applyOrderConditions($query, $qid) {
 652+ protected function applyOrderConditions( $query, $qid ) {
653653 global $smwgQSortingSupport;
654654 if ( !$smwgQSortingSupport ) {
655655 return;
@@ -656,27 +656,27 @@
657657 $qobj = $this->m_queries[$qid];
658658 // (1) collect required extra property descriptions:
659659 $extraproperties = array();
660 - foreach ($this->m_sortkeys as $propkey => $order) {
661 - if (!array_key_exists($propkey,$qobj->sortfields)) { // find missing property to sort by
662 - if ($propkey == '') { // sort by first result column (page titles)
 660+ foreach ( $this->m_sortkeys as $propkey => $order ) {
 661+ if ( !array_key_exists( $propkey, $qobj->sortfields ) ) { // find missing property to sort by
 662+ if ( $propkey == '' ) { // sort by first result column (page titles)
663663 $qobj->sortfields[$propkey] = "$qobj->alias.smw_sortkey";
664664 } else { // try to extend query
665665 $extrawhere = '';
666 - $sortprop = SMWPropertyValue::makeUserProperty($propkey);
667 - if ($sortprop->isValid()) {
668 - $extraproperties[] = new SMWSomeProperty($sortprop, new SMWThingDescription());
 666+ $sortprop = SMWPropertyValue::makeUserProperty( $propkey );
 667+ if ( $sortprop->isValid() ) {
 668+ $extraproperties[] = new SMWSomeProperty( $sortprop, new SMWThingDescription() );
669669 }
670670 }
671671 }
672672 }
673673 // (2) compile according conditions and hack them into $qobj:
674 - if (count($extraproperties) > 0) {
675 - $desc = new SMWConjunction($extraproperties);
676 - $newqid = $this->compileQueries($desc);
 674+ if ( count( $extraproperties ) > 0 ) {
 675+ $desc = new SMWConjunction( $extraproperties );
 676+ $newqid = $this->compileQueries( $desc );
677677 $newqobj = $this->m_queries[$newqid]; // this is always an SMW_SQL2_CONJUNCTION ...
678 - foreach ($newqobj->components as $cid => $field) { // ... so just re-wire its dependencies
 678+ foreach ( $newqobj->components as $cid => $field ) { // ... so just re-wire its dependencies
679679 $qobj->components[$cid] = $qobj->joinfield;
680 - $qobj->sortfields = array_merge($qobj->sortfields, $this->m_queries[$cid]->sortfields);
 680+ $qobj->sortfields = array_merge( $qobj->sortfields, $this->m_queries[$cid]->sortfields );
681681 }
682682 $this->m_queries[$qid] = $qobj;
683683 }
@@ -685,20 +685,20 @@
686686 /**
687687 * Get a SQL option array for the given query and preprocessed query object at given id.
688688 */
689 - protected function getSQLOptions($query,$rootid) {
 689+ protected function getSQLOptions( $query, $rootid ) {
690690 global $smwgQSortingSupport, $smwgQRandSortingSupport;
691691 $result = array( 'LIMIT' => $query->getLimit() + 1, 'OFFSET' => $query->getOffset() );
692692 // build ORDER BY options using discovered sorting fields:
693 - if ($smwgQSortingSupport) {
 693+ if ( $smwgQSortingSupport ) {
694694 $qobj = $this->m_queries[$rootid];
695 - foreach ($this->m_sortkeys as $propkey => $order) {
696 - if (array_key_exists($propkey,$qobj->sortfields)) { // field successfully added
697 - if (!array_key_exists('ORDER BY', $result)) {
 695+ foreach ( $this->m_sortkeys as $propkey => $order ) {
 696+ if ( array_key_exists( $propkey, $qobj->sortfields ) ) { // field successfully added
 697+ if ( !array_key_exists( 'ORDER BY', $result ) ) {
698698 $result['ORDER BY'] = '';
699699 } else {
700700 $result['ORDER BY'] .= ', ';
701701 }
702 - if ('RAND()' == $order){
 702+ if ( 'RAND()' == $order ) {
703703 $result['ORDER BY'] .= " $order ";
704704 } else {
705705 $result['ORDER BY'] .= $qobj->sortfields[$propkey] . " $order ";
@@ -713,12 +713,11 @@
714714 /**
715715 * After querying, make sure no temporary database tables are left.
716716 */
717 - protected function cleanUp() {
718 - if ($this->m_qmode !== SMWQuery::MODE_DEBUG) {
719 - foreach ($this->m_querylog as $table => $log) {
720 - $this->m_dbs->query("DROP TEMPORARY TABLE " . $this->m_dbs->tableName($table), 'SMW::getQueryResult');
 717+ protected function cleanUp() {
 718+ if ( $this->m_qmode !== SMWQuery::MODE_DEBUG ) {
 719+ foreach ( $this->m_querylog as $table => $log ) {
 720+ $this->m_dbs->query( "DROP TEMPORARY TABLE " . $this->m_dbs->tableName( $table ), 'SMW::getQueryResult' );
721721 }
722722 }
723723 }
724 -
725724 }
Property changes on: trunk/extensions/SemanticNotifyMe/includes/storage/SMW_SQLStore2_QueriesNM.php
___________________________________________________________________
Name: svn:eol-style
726725 + native
Index: trunk/extensions/SemanticNotifyMe/includes/storage/SMW_NMStorageSQL.php
@@ -1,700 +1,697 @@
2 -<?php
3 -/**
4 - * This file provides the access to the MediaWiki SQL database tables that are
5 - * used by the NotifyMe extension.
6 - *
7 - * @author dch
8 - *
9 - */
10 -if ( !defined( 'MEDIAWIKI' ) ) die;
11 -global $smwgNMIP;
12 -require_once $smwgNMIP . '/includes/SMW_NMDBHelper.php';
13 -
14 -/**
15 - * This class encapsulates all methods that care about the database tables of
16 - * the NotifyMe extension.
17 - *
18 - */
19 -class NMStorageSQL {
20 -
21 - public function setup($verbose) {
22 -
23 - $db =& wfGetDB( DB_MASTER );
24 -
25 - SNMDBHelper::reportProgress("Setting up NotifyMe database ...\n",$verbose);
26 -
27 - extract( $db->tableNames('smw_nm_monitor', 'smw_nm_query', 'smw_nm_relations', 'smw_nm_rss') );
28 -
29 - // page_id, monitored page id
30 - SNMDBHelper::setupTable($smw_nm_monitor,
31 - array('notify_id' => 'INT(8) UNSIGNED NOT NULL',
32 - 'page_id' => 'INT(8) UNSIGNED NOT NULL'), $db, $verbose);
33 - SNMDBHelper::setupIndex($smw_nm_monitor, array('page_id'), $db);
34 - SNMDBHelper::setupTable($smw_nm_query,
35 - array('notify_id' => 'INT(8) UNSIGNED NOT NULL KEY AUTO_INCREMENT',
36 - 'user_id' => 'INT(8) UNSIGNED NOT NULL',
37 - 'delegate' => 'BLOB',
38 - 'name' => 'VARCHAR(255) binary NOT NULL',
39 - 'rep_all' => 'TINYINT(1) NOT NULL default \'1\'',
40 - 'show_all' => 'TINYINT(1) NOT NULL default \'0\'',
41 - 'query' => 'BLOB NOT NULL',
42 - 'nm_sql' => 'BLOB',
43 - 'nm_hierarchy' => 'BLOB',
44 - 'enable' => 'TINYINT(1) NOT NULL default \'0\''), $db, $verbose);
45 - SNMDBHelper::setupIndex($smw_nm_query, array('user_id'), $db);
46 - // page_id, related page / property id in notify query
47 - SNMDBHelper::setupTable($smw_nm_relations,
48 - array('notify_id' => 'INT(8) UNSIGNED NOT NULL',
49 - 'smw_id' => 'INT(8) UNSIGNED NOT NULL',
50 - // 0 category, 1 instance, 2 property
51 - 'type' => 'INT(8) UNSIGNED NOT NULL',
52 - 'subquery' => 'INT(8) UNSIGNED NOT NULL default \'0\''), $db, $verbose);
53 - SNMDBHelper::setupIndex($smw_nm_relations, array('smw_id', 'notify_id'), $db);
54 - SNMDBHelper::setupTable($smw_nm_rss,
55 - array('msg_id' => 'INT(8) UNSIGNED NOT NULL KEY AUTO_INCREMENT',
56 - 'mailed' => 'TINYINT(1) NOT NULL default \'0\'',
57 - 'user_id' => 'INT(8) UNSIGNED',
58 - 'notify_id' => 'INT(8) UNSIGNED',
59 - 'title' => 'VARCHAR(255) binary NOT NULL',
60 - 'link' => 'BLOB',
61 - 'notify' => 'BLOB NOT NULL',
62 - 'timestamp' => 'VARCHAR(14) binary NOT NULL'), $db, $verbose);
63 - SNMDBHelper::setupIndex($smw_nm_rss, array('user_id'), $db);
64 -
65 - SNMDBHelper::reportProgress("... done!\n",$verbose);
66 -
67 - }
68 -
69 - public function addNotifyQuery($user_id, $querystring, $name, $rep_all, $show_all, $delegate) {
70 - $fname = 'NotifyMe::addNotifyQuery';
71 - wfProfileIn( $fname );
72 -
73 - $dbw =& wfGetDB( DB_MASTER );
74 - $notify_id = $dbw->nextSequenceValue('nmquery_notify_id_seq');
75 - if($dbw->insert( 'smw_nm_query', array(
76 - 'notify_id' => $notify_id,
77 - 'user_id' => $user_id,
78 - 'query' => $querystring,
79 - 'name' => $name,
80 - 'rep_all' => $rep_all,
81 - 'show_all' => $show_all,
82 - 'delegate' => $delegate), $fname))
83 - {
84 - $notify_id = $dbw->insertId();
85 - } else {
86 - $notify_id = 0;
87 - }
88 - wfProfileOut( $fname );
89 - return $notify_id;
90 - }
91 - public function removeNotifyQuery($notify_ids){
92 - $fname = 'NotifyMe::delNotify';
93 - wfProfileIn( $fname );
94 - $db =& wfGetDB( DB_MASTER );
95 - $db->delete( $db->tableName('smw_nm_monitor'), array('notify_id'=>$notify_ids), $fname);
96 - $db->delete( $db->tableName('smw_nm_relations'), array('notify_id'=>$notify_ids), $fname);
97 - $db->delete( $db->tableName('smw_nm_query'), array('notify_id'=>$notify_ids), $fname);
98 - wfProfileOut( $fname );
99 - return true;
100 - }
101 - public function addNotifyMonitor($add_monitor){
102 - $fname = 'NotifyMe::addNotifyMonitor';
103 - wfProfileIn( $fname );
104 -
105 - $db =& wfGetDB( DB_MASTER );
106 - $res = $db->insert( 'smw_nm_monitor', $add_monitor, $fname);
107 - wfProfileOut( $fname );
108 - return $res;
109 - }
110 - public function removeNotifyMonitor($remove_monitored){
111 - $fname = 'NotifyMe::addNotifyMonitor';
112 - wfProfileIn( $fname );
113 -
114 - $db =& wfGetDB( DB_MASTER );
115 - foreach($remove_monitored as $monitor) {
116 - $db->delete( $db->tableName('smw_nm_monitor'), array('notify_id'=>$monitor['notify_id'], 'page_id'=>$monitor['page_id']), $fname);
117 - }
118 - wfProfileOut( $fname );
119 - return $res;
120 - }
121 - public function addNotifyRelations($notify_id, $rels, $subquery=0){
122 - $fname = 'NotifyMe::addNotifyRelations';
123 - wfProfileIn( $fname );
124 -
125 - foreach($rels as $i=>$vi) {
126 - foreach($rels as $j=>$vj) {
127 - if($i != $j && $vi['namespace']==$vj['namespace'] && $vi['title']==$vj['title']) {
128 - unset($rels[$i]);
129 - break;
130 - }
131 - }
132 - }
133 -
134 - $dbw =& wfGetDB( DB_MASTER );
135 - $relations = array();
136 - $new_rel = false;
137 - foreach($rels as $smw){
138 - $res = $dbw->select( $dbw->tableName('smw_ids'),
139 - 'smw_id',
140 - // array( 'smw_namespace' => $smw['namespace'], 'smw_title' => $smw['title']),
141 - 'smw_namespace='.$smw['namespace'].' AND smw_title='.$dbw->addQuotes($smw['title']),
142 - 'NotifyMe::getRelatedSmwId');
143 - $rel_smw_id = 0;
144 - if($dbw->numRows( $res ) > 0) {
145 - $rel_smw_id = $dbw->fetchObject($res)->smw_id;
146 - $dbw->freeResult($res);
147 - } else {
148 - $dbw->freeResult($res);
149 - return false;
150 - }
151 -
152 - if($rel_smw_id > 0) {
153 - $new_rel = true;
154 - $relations[] = array(
155 - 'notify_id' => $notify_id,
156 - 'smw_id' => $rel_smw_id,
157 - // $type: 0 category, 1 instance, 2 property
158 - 'type' => (($smw['namespace']==NS_CATEGORY)?0:(($smw['namespace']==SMW_NS_PROPERTY)?2:1)),
159 - 'subquery' => $subquery);
160 - }
161 - }
162 - if($new_rel) {
163 - $dbw->insert( 'smw_nm_relations', $relations, $fname);
164 - }
165 - wfProfileOut( $fname );
166 - return true;
167 - }
168 - public function getNotifications($user_id){
169 - $fname = 'NotifyMe::getNotifications';
170 - wfProfileIn( $fname );
171 -
172 - $result = array();
173 -
174 - $db = wfGetDB( DB_SLAVE );
175 - $res = $db->select( $db->tableName('smw_nm_query'),
176 - array('notify_id', 'delegate', 'name', 'query', 'enable', 'rep_all', 'show_all'),
177 - array('user_id'=>$user_id), $fname, array('ORDER BY' => 'notify_id'));
178 - if($db->numRows( $res ) > 0) {
179 - while($row = $db->fetchObject($res)) {
180 - $result[] = array('notify_id'=>$row->notify_id,
181 - 'delegate'=>$row->delegate,
182 - 'name'=>$row->name,
183 - 'query'=>$row->query,
184 - 'enable'=>$row->enable,
185 - 'rep_all'=>$row->rep_all,
186 - 'show_all'=>$row->show_all);
187 - }
188 - }
189 - $db->freeResult($res);
190 - wfProfileOut( $fname );
191 - return $result;
192 - }
193 - public function getNotifyMe($notify_ids){
194 - $fname = 'NotifyMe::getNotifyMe';
195 - wfProfileIn( $fname );
196 -
197 - $result = array();
198 -
199 - $db = wfGetDB( DB_SLAVE );
200 - $res = $db->select( $db->tableName('smw_nm_query'),
201 - array('notify_id', 'name', 'query', 'show_all'),
202 - array('notify_id'=>$notify_ids), $fname);
203 - if($db->numRows( $res ) > 0) {
204 - while($row = $db->fetchObject($res)) {
205 - $result[$row->notify_id] = array('query'=>$row->query,
206 - 'name'=>$row->name,
207 - 'show_all'=>$row->show_all);
208 - }
209 - }
210 - $db->freeResult($res);
211 - wfProfileOut( $fname );
212 - return $result;
213 - }
214 - public function getAllNotifications(){
215 - $fname = 'NotifyMe::getAllNotifications';
216 - wfProfileIn( $fname );
217 -
218 - $result = array();
219 -
220 - $db = wfGetDB( DB_SLAVE );
221 - $res = $db->select( $db->tableName('smw_nm_query'),
222 - array('notify_id', 'delegate', 'name', 'query', 'enable', 'rep_all', 'show_all'), '',
223 - $fname, array('ORDER BY' => 'notify_id'));
224 - if($db->numRows( $res ) > 0) {
225 - while($row = $db->fetchObject($res)) {
226 - $result[] = array('notify_id'=>$row->notify_id,
227 - 'delegate'=>$row->delegate,
228 - 'name'=>$row->name,
229 - 'query'=>$row->query,
230 - 'enable'=>$row->enable,
231 - 'rep_all'=>$row->rep_all,
232 - 'show_all'=>$row->show_all);
233 - }
234 - }
235 - $db->freeResult($res);
236 - wfProfileOut( $fname );
237 - return $result;
238 - }
239 - public function disableNotifyState($notify_id){
240 - $fname = 'NotifyMe::disableState';
241 - wfProfileIn( $fname );
242 - $db =& wfGetDB( DB_MASTER );
243 - $db->delete( $db->tableName('smw_nm_monitor'), array('notify_id'=>$notify_id), $fname);
244 - $db->delete( $db->tableName('smw_nm_relations'), array('notify_id'=>$notify_id), $fname);
245 -
246 - $this->updateNotifyState($notify_id, 0);
247 - wfProfileOut( $fname );
248 - return true;
249 - }
250 - public function updateNotifyState($notify_id, $state) {
251 - $fname = 'NotifyMe::updateNotifyState';
252 - wfProfileIn( $fname );
253 -
254 - $dbw =& wfGetDB( DB_MASTER );
255 - $dbw->update( 'smw_nm_query', array('enable' => $state), array('notify_id'=>$notify_id), $fname);
256 - wfProfileOut( $fname );
257 - return true;
258 - }
259 - public function updateDelegate($notify_id, $delegate){
260 - $fname = 'NotifyMe::updateDelegate';
261 - wfProfileIn( $fname );
262 - $dbw =& wfGetDB( DB_MASTER );
263 - $dbw->update( 'smw_nm_query', array('delegate' => $delegate), array('notify_id'=>$notify_id), $fname);
264 - wfProfileOut( $fname );
265 - return true;
266 - }
267 - public function updateNotifyReportAll($notify_id, $rep_all) {
268 - $fname = 'NotifyMe::updateNotifyReportAll';
269 - wfProfileIn( $fname );
270 -
271 - $dbw =& wfGetDB( DB_MASTER );
272 - $dbw->update( 'smw_nm_query', array('rep_all' => $rep_all), array('notify_id'=>$notify_id), $fname);
273 - wfProfileOut( $fname );
274 - return true;
275 - }
276 - public function updateNotifyShowAll($notify_id, $show_all) {
277 - $fname = 'NotifyMe::updateNotifyShowAll';
278 - wfProfileIn( $fname );
279 -
280 - $dbw =& wfGetDB( DB_MASTER );
281 - $dbw->update( 'smw_nm_query', array('show_all' => $show_all), array('notify_id'=>$notify_id), $fname);
282 - wfProfileOut( $fname );
283 - return true;
284 - }
285 -
286 - public function lookupSmwId($namespace, $title) {
287 - $fname = 'NotifyMe::lookupSmwId';
288 - wfProfileIn( $fname );
289 -
290 - $result = 0;
291 - $db = wfGetDB( DB_SLAVE );
292 - $res = $db->selectRow( 'smw_ids', 'smw_id', array( 'smw_namespace' => $namespace, 'smw_title' => $title ), $fname );
293 -
294 - if($res) $result = $res->smw_id;
295 - wfProfileOut( $fname );
296 - return $result;
297 - }
298 - public function getMonitoredNotifications($page_id) {
299 - $fname = 'NotifyMe::getMonitoredNotifications';
300 - wfProfileIn( $fname );
301 -
302 - $result = array();
303 -
304 - $db = wfGetDB( DB_SLAVE );
305 -
306 - $res = $db->select( array($db->tableName('smw_nm_query').' q', $db->tableName('smw_nm_monitor').' m'),
307 - array('q.user_id', 'q.notify_id', 'q.delegate', 'q.name', 'q.rep_all'),
308 - 'm.page_id='.$page_id.' and m.notify_id=q.notify_id', $fname);
309 - if($db->numRows( $res ) > 0) {
310 - while($row = $db->fetchObject($res)) {
311 - $ds = explode(',', $row->delegate);
312 - $delegated = false;
313 - foreach($ds as $delegate) {
314 - $u = User::newFromName(trim($delegate));
315 - if($u==null) continue;
316 - $id = $u->getId();
317 - if($id > 0) {
318 - $result[$id][$row->notify_id] = array('name'=>$row->name, 'rep_all'=>$row->rep_all);
319 - $delegated = true;
320 - }
321 - }
322 - if(!$delegated) {
323 - $result[$row->user_id][$row->notify_id] = array('name'=>$row->name, 'rep_all'=>$row->rep_all);
324 - }
325 - }
326 - }
327 - $db->freeResult($res);
328 -
329 - wfProfileOut( $fname );
330 - return $result;
331 - }
332 - public function getMonitoredNotificationsDetail($page_id) {
333 - $fname = 'NotifyMe::getMonitoredNotificationsDetail';
334 - wfProfileIn( $fname );
335 -
336 - $result = array();
337 -
338 - $notifies = $this->getMonitoredNotifications($page_id);
339 -
340 - $db = wfGetDB( DB_SLAVE );
341 -
342 - foreach ($notifies as $user_id=>$notify) {
343 - foreach($notify as $notify_id=>$notify_detail) {
344 - if($notify_detail['rep_all']==1) {
345 - $result[$user_id]['rep_all'][$notify_id] = $notify_detail['name'];
346 - } else {
347 - $res = $db->select( $db->tableName('smw_nm_relations'), array('smw_id', 'type'), "notify_id=$notify_id AND subquery=0", $fname);
348 - if($db->numRows( $res ) > 0) {
349 - while($row = $db->fetchObject($res)) {
350 - $result[$user_id]['semantic'][SMWNotifyProcessor::toInfoId($row->type,0,$row->smw_id)][$notify_id] = $notify_detail['name'];
351 - }
352 - }
353 - $db->freeResult($res);
354 - }
355 - }
356 - }
357 -
358 - wfProfileOut( $fname );
359 - return $result;
360 - }
361 - public function getPossibleQuery($info) {
362 - $cnt = count($info);
363 - if($cnt == 0) {
364 - return null;
365 - }
366 - $fname = 'NotifyMe::getPossibleQuery';
367 - wfProfileIn( $fname );
368 -
369 - $first = true;
370 - foreach($info as $key=>$value) {
371 - if($first) {
372 - $first = false;
373 - } else {
374 - $cond .= "OR ";
375 - }
376 - $i = SMWNotifyProcessor::getInfoFromId($key);
377 - $cond .= "(smw_id=$i[attr_id] AND type=$i[type]) ";
378 - }
379 -
380 - $db =& wfGetDB( DB_SLAVE );
381 - $result = array(0=>array(), 1=>array());
382 - extract( $db->tableNames('smw_nm_query', 'smw_nm_relations') );
383 - $res = $db->query("SELECT q.notify_id, q.name, q.user_id, q.delegate, q.nm_sql, q.nm_hierarchy, c1.subquery FROM (".
384 - "SELECT count(*) cnt, notify_id, subquery FROM $smw_nm_relations ".
385 - "WHERE $cond GROUP BY notify_id, subquery".
386 - ") c1 INNER JOIN (".
387 - "SELECT count(*) cnt, notify_id, subquery FROM $smw_nm_relations ".
388 - "WHERE type<>1 GROUP BY notify_id, subquery".
389 - ") c2 ON c1.notify_id=c2.notify_id AND c1.subquery=c2.subquery AND c1.cnt=c2.cnt ".
390 - "LEFT JOIN $smw_nm_query q ON q.notify_id = c1.notify_id WHERE c1.cnt<=$cnt", $fname);
391 - if($db->numRows( $res ) > 0) {
392 - while($row = $db->fetchObject($res)) {
393 - $ds = explode(',', $row->delegate);
394 - $delegated = false;
395 - foreach($ds as $delegate) {
396 - $u = User::newFromName(trim($delegate));
397 - if($u==null) continue;
398 - $id = $u->getId();
399 - if($id > 0) {
400 - $result[$row->subquery>0?1:0][$row->notify_id] = array('user_id'=>$id, 'name'=>$row->name, 'sql'=>$row->nm_sql, 'hierarchy'=>$row->nm_hierarchy);
401 - $delegated = true;
402 - }
403 - }
404 - if(!$delegated) {
405 - $result[$row->subquery>0?1:0][$row->notify_id] = array('user_id'=>$row->user_id, 'name'=>$row->name, 'sql'=>$row->nm_sql, 'hierarchy'=>$row->nm_hierarchy);
406 - }
407 - }
408 - }
409 - $db->freeResult($res);
410 - wfProfileOut( $fname );
411 - return $result;
412 - }
413 - public function getMonitoredQuery($page_id) {
414 - $fname = 'NotifyMe::getMonitoredQuery';
415 - wfProfileIn( $fname );
416 -
417 - $db =& wfGetDB( DB_SLAVE );
418 - $res = $db->select( array($db->tableName('smw_nm_monitor').' m', $db->tableName('smw_nm_query').' q'),
419 - array('q.notify_id, q.delegate, q.name, q.user_id, q.nm_sql, q.nm_hierarchy'),
420 - "m.notify_id=q.notify_id AND m.page_id=$page_id", $fname);
421 - if($db->numRows( $res ) > 0) {
422 - while($row = $db->fetchObject($res)) {
423 - $ds = explode(',', $row->delegate);
424 - $delegated = false;
425 - foreach($ds as $delegate) {
426 - $u = User::newFromName(trim($delegate));
427 - if($u==null) continue;
428 - $id = $u->getId();
429 - if($id > 0) {
430 - $result[$row->notify_id] = array('user_id'=>$id, 'name'=>$row->name, 'sql'=>$row->nm_sql, 'hierarchy'=>$row->nm_hierarchy);
431 - $delegated = true;
432 - }
433 - }
434 - if(!$delegated) {
435 - $result[$row->notify_id] = array('user_id'=>$row->user_id, 'name'=>$row->name, 'sql'=>$row->nm_sql, 'hierarchy'=>$row->nm_hierarchy);
436 - }
437 - }
438 - }
439 - $db->freeResult($res);
440 - wfProfileOut( $fname );
441 - return $result;
442 - }
443 - public function updateNMSql($notify_id, $sql, $tmp_hierarchy) {
444 - $fname = 'NotifyMe::updateNMSql';
445 - wfProfileIn( $fname );
446 -
447 - $dbw =& wfGetDB( DB_MASTER );
448 - $dbw->update( 'smw_nm_query', array('nm_sql' => $sql, 'nm_hierarchy' => $tmp_hierarchy), array('notify_id'=>$notify_id), $fname);
449 - wfProfileOut( $fname );
450 - return true;
451 - }
452 - public function getNotifyInMainQuery($page_id, $notify_id, $sql, $hierarchy, &$match, &$monitoring) {
453 - $fname = 'NotifyMe::getNotifyInMainQuery';
454 - wfProfileIn( $fname );
455 -
456 - $db =& wfGetDB( DB_SLAVE );
457 -
458 - $tmp_tables = array();
459 - if($hierarchy != '') {
460 - $_hierarchies = array();
461 - foreach(explode(";",$hierarchy) as $attrs) {
462 - $part = explode(":",$attrs,3);
463 - $tablename = $db->tableName($part[0]);
464 - $depth = intval($part[1]);
465 - $values = $part[2];
466 -
467 - $tmp_tables[] = $tablename;
468 -
469 - $db->query( "CREATE TEMPORARY TABLE $tablename ( id INT UNSIGNED NOT NULL KEY) TYPE=MEMORY", 'SMW::executeQueries' );
470 - if (array_key_exists($values, $_hierarchies)) { // just copy known result
471 - $db->query("INSERT INTO $tablename (id) SELECT id FROM " . $_hierarchies[$values], 'SMW::executeQueries');
472 - } else {
473 - $tmpnew = 'smw_new';
474 - $tmpres = 'smw_res';
475 - $db->query( "CREATE TEMPORARY TABLE $tmpnew ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
476 - $db->query( "CREATE TEMPORARY TABLE $tmpres ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
477 - $db->query("INSERT IGNORE INTO $tablename (id) VALUES $values", 'SMW::executeQueries');
478 - $db->query("INSERT IGNORE INTO $tmpnew (id) VALUES $values", 'SMW::executeQueries');
479 - $smw_subs2 = $db->tableName('smw_subs2');
480 - for ($i=0; $i<$depth; $i++) {
481 - $db->query("INSERT INTO $tmpres (id) SELECT s_id FROM $smw_subs2, $tmpnew WHERE o_id=id", 'SMW::executeQueries');
482 - if ($db->affectedRows() == 0) { // no change, exit loop
483 - break;
484 - }
485 - $db->query("INSERT IGNORE INTO $tablename (id) SELECT $tmpres.id FROM $tmpres", 'SMW::executeQueries');
486 - if ($db->affectedRows() == 0) { // no change, exit loop
487 - break;
488 - }
489 - $db->query('TRUNCATE TABLE ' . $tmpnew, 'SMW::executeQueries'); // empty "new" table
490 - $tmpname = $tmpnew;
491 - $tmpnew = $tmpres;
492 - $tmpres = $tmpname;
493 - }
494 - $_hierarchies[$values] = $tablename;
495 - $db->query('DROP TEMPORARY TABLE smw_new', 'SMW::executeQueries');
496 - $db->query('DROP TEMPORARY TABLE smw_res', 'SMW::executeQueries');
497 - }
498 - }
499 - }
500 -
501 - $sql = "SELECT p.page_id FROM " . $db->tableName('page') . " AS p INNER JOIN ($sql) AS s ON s.t=p.page_title AND s.ns=p.page_namespace WHERE p.page_id=$page_id";
502 - $res = $db->query($sql, $fname);
503 - $match = ($db->numRows( $res ) > 0);
504 - $db->freeResult($res);
505 -
506 - foreach ($tmp_tables as $tablename) {
507 - $db->query("DROP TEMPORARY TABLE $tablename", 'SMW::getQueryResult');
508 - }
509 -
510 - $monitoring = ($db->selectRow( 'smw_nm_monitor', array( 'page_id' ),
511 - array( 'page_id' => $page_id, 'notify_id' => $notify_id ), $fname ) != false);
512 -
513 - wfProfileOut( $fname );
514 - return true;
515 - }
516 - public function getNotifyInSubquery($notify_id, $sql, $hierarchy) {
517 - $fname = 'NotifyMe::getNotifyInSubquery';
518 - wfProfileIn( $fname );
519 -
520 - $result = array('monitoring'=>array(), 'match'=>array());
521 -
522 - $db =& wfGetDB( DB_SLAVE );
523 -
524 - $tmp_tables = array();
525 - if($hierarchy != '') {
526 - $_hierarchies = array();
527 - foreach(explode(";",$hierarchy) as $attrs) {
528 - $part = explode(":",$attrs,3);
529 - $tablename = $db->tableName($part[0]);
530 - $depth = intval($part[1]);
531 - $values = $part[2];
532 -
533 - $tmp_tables[] = $tablename;
534 -
535 - $db->query( "CREATE TEMPORARY TABLE $tablename ( id INT UNSIGNED NOT NULL KEY) TYPE=MEMORY", 'SMW::executeQueries' );
536 - if (array_key_exists($values, $_hierarchies)) { // just copy known result
537 - $db->query("INSERT INTO $tablename (id) SELECT id FROM " . $_hierarchies[$values], 'SMW::executeQueries');
538 - } else {
539 - $tmpnew = 'smw_new';
540 - $tmpres = 'smw_res';
541 - $db->query( "CREATE TEMPORARY TABLE $tmpnew ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
542 - $db->query( "CREATE TEMPORARY TABLE $tmpres ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
543 - $db->query("INSERT IGNORE INTO $tablename (id) VALUES $values", 'SMW::executeQueries');
544 - $db->query("INSERT IGNORE INTO $tmpnew (id) VALUES $values", 'SMW::executeQueries');
545 - $smw_subs2 = $db->tableName('smw_subs2');
546 - for ($i=0; $i<$depth; $i++) {
547 - $db->query("INSERT INTO $tmpres (id) SELECT s_id FROM $smw_subs2, $tmpnew WHERE o_id=id", 'SMW::executeQueries');
548 - if ($db->affectedRows() == 0) { // no change, exit loop
549 - break;
550 - }
551 - $db->query("INSERT IGNORE INTO $tablename (id) SELECT $tmpres.id FROM $tmpres", 'SMW::executeQueries');
552 - if ($db->affectedRows() == 0) { // no change, exit loop
553 - break;
554 - }
555 - $db->query('TRUNCATE TABLE ' . $tmpnew, 'SMW::executeQueries'); // empty "new" table
556 - $tmpname = $tmpnew;
557 - $tmpnew = $tmpres;
558 - $tmpres = $tmpname;
559 - }
560 - $_hierarchies[$values] = $tablename;
561 - $db->query('DROP TEMPORARY TABLE smw_new', 'SMW::executeQueries');
562 - $db->query('DROP TEMPORARY TABLE smw_res', 'SMW::executeQueries');
563 - }
564 - }
565 - }
566 -
567 - $res = $db->query("SELECT p.page_id FROM " . $db->tableName('page') . " AS p INNER JOIN ($sql) AS s ON s.t=p.page_title AND s.ns=p.page_namespace", $fname);
568 - if($db->numRows( $res ) > 0) {
569 - while($row = $db->fetchObject($res)) {
570 - $result['match'][] = $row->page_id;
571 - }
572 - }
573 - $db->freeResult($res);
574 -
575 - foreach ($tmp_tables as $tablename) {
576 - $db->query("DROP TEMPORARY TABLE $tablename", 'SMW::getQueryResult');
577 - }
578 -
579 - $res = $db->select( $db->tableName('smw_nm_monitor'), array( 'page_id' ), array( 'notify_id' => $notify_id ), $fname );
580 - if($db->numRows( $res ) > 0) {
581 - while($row = $db->fetchObject($res)) {
582 - $result['monitoring'][] = $row->page_id;
583 - }
584 - }
585 - $db->freeResult($res);
586 -
587 - wfProfileOut( $fname );
588 - return $result;
589 - }
590 - public function getUserInfo($user_id) {
591 - $fname = 'NotifyMe::getUserInfo';
592 - wfProfileIn( $fname );
593 -
594 - $db = wfGetDB( DB_SLAVE );
595 - $result = $db->selectRow( 'user', array( 'user_name', 'user_real_name', 'user_email', 'user_options' ), array( 'user_id' => $user_id ), $fname );
596 -
597 - wfProfileOut( $fname );
598 - return $result;
599 - }
600 - public function getPageTitle($page_id) {
601 - $db =& wfGetDB( DB_SLAVE );
602 - return $db->selectRow('page', 'page_title', array('page_id' => $page_id));
603 - }
604 - public function addNotifyRSS($type, $id, $title, $msg, $link = NULL) {
605 - $fname = 'NotifyMe::addNotifyRSS';
606 - wfProfileIn( $fname );
607 - $db =& wfGetDB( DB_MASTER );
608 -
609 - $rid = $db->nextSequenceValue('nmrss_msg_id_seq');
610 - $values = array('msg_id' => $rid,
611 - 'title' => $title,
612 - 'notify' => $msg,
613 - 'timestamp' => $db->timestamp());
614 - if($type == "uid") {
615 - $values['user_id'] = $id;
616 - } else {
617 - $values['notify_id'] = $id;
618 - }
619 - if($link !== NULL) {
620 - $values['link'] = $link;
621 - }
622 -
623 - $db->insert( 'smw_nm_rss', $values, $fname);
624 - $id = $db->insertId();
625 -
626 - wfProfileOut( $fname );
627 - return $id;
628 - }
629 - public function getNotifyRSS($type, $id, $limit) {
630 - $fname = 'NotifyMe::getNotifyRSS';
631 - wfProfileIn( $fname );
632 - $db =& wfGetDB( DB_SLAVE );
633 - $result = array();
634 - if($type == "uid") {
635 - $ids = array('user_id'=>$id);
636 - } else {
637 - $ids = array('notify_id'=>$id);
638 - }
639 - $res = $db->select( $db->tableName('smw_nm_rss'), array('title', 'link', 'notify', 'timestamp'), $ids, $fname, array('ORDER BY' => 'timestamp DESC', 'LIMIT'=>$limit));
640 - if($db->numRows( $res ) > 0) {
641 - while($row = $db->fetchObject($res)) {
642 - $result[] = array('title' => $row->title, 'link'=>$row->link, 'notify'=>$row->notify, 'timestamp'=>$row->timestamp);
643 - }
644 - }
645 - $db->freeResult($res);
646 - wfProfileOut( $fname );
647 - return $result;
648 - }
649 - public function getUnmailedNMMessages() {
650 - $fname = 'NotifyMe::getUnmailedNMMessages';
651 - wfProfileIn( $fname );
652 - $db =& wfGetDB( DB_MASTER );
653 - $smw_nm_rss = $db->tableName('smw_nm_rss');
654 - $result = array();
655 - $res = $db->select( $smw_nm_rss,
656 - array('user_id', 'title', 'notify', 'timestamp'),
657 - array('mailed'=>'0'), $fname);
658 - if($db->numRows( $res ) > 0) {
659 - while($row = $db->fetchObject($res)) {
660 - $result[] = array('user_id' => $row->user_id, 'title' => $row->title, 'notify'=>$row->notify, 'timestamp'=>$row->timestamp);
661 - }
662 - }
663 - $db->freeResult($res);
664 - $db->update($smw_nm_rss, array('mailed' => '1'), array('mailed' => '0'), $fname);
665 - wfProfileOut( $fname );
666 - return $result;
667 - }
668 -
669 - public function getGroupedUsers($groups) {
670 - $fname = 'NotifyMe::getGroupedUsers';
671 - wfProfileIn( $fname );
672 - $db =& wfGetDB( DB_SLAVE );
673 - extract( $db->tableNames('user_groups', 'user') );
674 - $result = array();
675 - $res = $db->query( "SELECT u.user_name FROM $user u".
676 - ($groups ? " LEFT JOIN $user_groups g ON u.user_id = g.ug_user
677 - WHERE g.ug_group IN ('".join("','", $groups)."')
678 - GROUP BY user_name":""), $fname);
679 - if($db->numRows( $res ) > 0) {
680 - while($row = $db->fetchObject($res)) {
681 - $result[] = $row->user_name;
682 - }
683 - }
684 - $db->freeResult($res);
685 - wfProfileOut( $fname );
686 - return $result;
687 - }
688 -
689 - function getNMQueryResult(SMWQuery $query) {
690 - wfProfileIn('SMWSQLStore2::getNMQueryResult (SMW)');
691 - global $smwgNMIP;
692 - include_once("$smwgNMIP/includes/storage/SMW_SQLStore2_QueriesNM.php");
693 - $qe = new SMWSQLStore2QueryEngineNM(smwfGetStore(), wfGetDB( DB_SLAVE ));
694 - $result = $qe->getQueryResult($query);
695 - wfProfileOut('SMWSQLStore2::getNMQueryResult (SMW)');
696 - return $result;
697 - }
698 -
699 -}
700 -
701 -?>
\ No newline at end of file
 2+<?php
 3+/**
 4+ * This file provides the access to the MediaWiki SQL database tables that are
 5+ * used by the NotifyMe extension.
 6+ *
 7+ * @author dch
 8+ *
 9+ */
 10+if ( !defined( 'MEDIAWIKI' ) ) die;
 11+global $smwgNMIP;
 12+require_once $smwgNMIP . '/includes/SMW_NMDBHelper.php';
 13+
 14+/**
 15+ * This class encapsulates all methods that care about the database tables of
 16+ * the NotifyMe extension.
 17+ *
 18+ */
 19+class NMStorageSQL {
 20+
 21+ public function setup( $verbose ) {
 22+
 23+ $db =& wfGetDB( DB_MASTER );
 24+
 25+ SNMDBHelper::reportProgress( "Setting up NotifyMe database ...\n", $verbose );
 26+
 27+ extract( $db->tableNames( 'smw_nm_monitor', 'smw_nm_query', 'smw_nm_relations', 'smw_nm_rss' ) );
 28+
 29+ // page_id, monitored page id
 30+ SNMDBHelper::setupTable( $smw_nm_monitor,
 31+ array( 'notify_id' => 'INT(8) UNSIGNED NOT NULL',
 32+ 'page_id' => 'INT(8) UNSIGNED NOT NULL' ), $db, $verbose );
 33+ SNMDBHelper::setupIndex( $smw_nm_monitor, array( 'page_id' ), $db );
 34+ SNMDBHelper::setupTable( $smw_nm_query,
 35+ array( 'notify_id' => 'INT(8) UNSIGNED NOT NULL KEY AUTO_INCREMENT',
 36+ 'user_id' => 'INT(8) UNSIGNED NOT NULL',
 37+ 'delegate' => 'BLOB',
 38+ 'name' => 'VARCHAR(255) binary NOT NULL',
 39+ 'rep_all' => 'TINYINT(1) NOT NULL default \'1\'',
 40+ 'show_all' => 'TINYINT(1) NOT NULL default \'0\'',
 41+ 'query' => 'BLOB NOT NULL',
 42+ 'nm_sql' => 'BLOB',
 43+ 'nm_hierarchy' => 'BLOB',
 44+ 'enable' => 'TINYINT(1) NOT NULL default \'0\'' ), $db, $verbose );
 45+ SNMDBHelper::setupIndex( $smw_nm_query, array( 'user_id' ), $db );
 46+ // page_id, related page / property id in notify query
 47+ SNMDBHelper::setupTable( $smw_nm_relations,
 48+ array( 'notify_id' => 'INT(8) UNSIGNED NOT NULL',
 49+ 'smw_id' => 'INT(8) UNSIGNED NOT NULL',
 50+ // 0 category, 1 instance, 2 property
 51+ 'type' => 'INT(8) UNSIGNED NOT NULL',
 52+ 'subquery' => 'INT(8) UNSIGNED NOT NULL default \'0\'' ), $db, $verbose );
 53+ SNMDBHelper::setupIndex( $smw_nm_relations, array( 'smw_id', 'notify_id' ), $db );
 54+ SNMDBHelper::setupTable( $smw_nm_rss,
 55+ array( 'msg_id' => 'INT(8) UNSIGNED NOT NULL KEY AUTO_INCREMENT',
 56+ 'mailed' => 'TINYINT(1) NOT NULL default \'0\'',
 57+ 'user_id' => 'INT(8) UNSIGNED',
 58+ 'notify_id' => 'INT(8) UNSIGNED',
 59+ 'title' => 'VARCHAR(255) binary NOT NULL',
 60+ 'link' => 'BLOB',
 61+ 'notify' => 'BLOB NOT NULL',
 62+ 'timestamp' => 'VARCHAR(14) binary NOT NULL' ), $db, $verbose );
 63+ SNMDBHelper::setupIndex( $smw_nm_rss, array( 'user_id' ), $db );
 64+
 65+ SNMDBHelper::reportProgress( "... done!\n", $verbose );
 66+
 67+ }
 68+
 69+ public function addNotifyQuery( $user_id, $querystring, $name, $rep_all, $show_all, $delegate ) {
 70+ $fname = 'NotifyMe::addNotifyQuery';
 71+ wfProfileIn( $fname );
 72+
 73+ $dbw =& wfGetDB( DB_MASTER );
 74+ $notify_id = $dbw->nextSequenceValue( 'nmquery_notify_id_seq' );
 75+ if ( $dbw->insert( 'smw_nm_query', array(
 76+ 'notify_id' => $notify_id,
 77+ 'user_id' => $user_id,
 78+ 'query' => $querystring,
 79+ 'name' => $name,
 80+ 'rep_all' => $rep_all,
 81+ 'show_all' => $show_all,
 82+ 'delegate' => $delegate ), $fname ) )
 83+ {
 84+ $notify_id = $dbw->insertId();
 85+ } else {
 86+ $notify_id = 0;
 87+ }
 88+ wfProfileOut( $fname );
 89+ return $notify_id;
 90+ }
 91+ public function removeNotifyQuery( $notify_ids ) {
 92+ $fname = 'NotifyMe::delNotify';
 93+ wfProfileIn( $fname );
 94+ $db =& wfGetDB( DB_MASTER );
 95+ $db->delete( $db->tableName( 'smw_nm_monitor' ), array( 'notify_id' => $notify_ids ), $fname );
 96+ $db->delete( $db->tableName( 'smw_nm_relations' ), array( 'notify_id' => $notify_ids ), $fname );
 97+ $db->delete( $db->tableName( 'smw_nm_query' ), array( 'notify_id' => $notify_ids ), $fname );
 98+ wfProfileOut( $fname );
 99+ return true;
 100+ }
 101+ public function addNotifyMonitor( $add_monitor ) {
 102+ $fname = 'NotifyMe::addNotifyMonitor';
 103+ wfProfileIn( $fname );
 104+
 105+ $db =& wfGetDB( DB_MASTER );
 106+ $res = $db->insert( 'smw_nm_monitor', $add_monitor, $fname );
 107+ wfProfileOut( $fname );
 108+ return $res;
 109+ }
 110+ public function removeNotifyMonitor( $remove_monitored ) {
 111+ $fname = 'NotifyMe::addNotifyMonitor';
 112+ wfProfileIn( $fname );
 113+
 114+ $db =& wfGetDB( DB_MASTER );
 115+ foreach ( $remove_monitored as $monitor ) {
 116+ $db->delete( $db->tableName( 'smw_nm_monitor' ), array( 'notify_id' => $monitor['notify_id'], 'page_id' => $monitor['page_id'] ), $fname );
 117+ }
 118+ wfProfileOut( $fname );
 119+ return $res;
 120+ }
 121+ public function addNotifyRelations( $notify_id, $rels, $subquery = 0 ) {
 122+ $fname = 'NotifyMe::addNotifyRelations';
 123+ wfProfileIn( $fname );
 124+
 125+ foreach ( $rels as $i => $vi ) {
 126+ foreach ( $rels as $j => $vj ) {
 127+ if ( $i != $j && $vi['namespace'] == $vj['namespace'] && $vi['title'] == $vj['title'] ) {
 128+ unset( $rels[$i] );
 129+ break;
 130+ }
 131+ }
 132+ }
 133+
 134+ $dbw =& wfGetDB( DB_MASTER );
 135+ $relations = array();
 136+ $new_rel = false;
 137+ foreach ( $rels as $smw ) {
 138+ $res = $dbw->select( $dbw->tableName( 'smw_ids' ),
 139+ 'smw_id',
 140+ // array( 'smw_namespace' => $smw['namespace'], 'smw_title' => $smw['title']),
 141+ 'smw_namespace=' . $smw['namespace'] . ' AND smw_title=' . $dbw->addQuotes( $smw['title'] ),
 142+ 'NotifyMe::getRelatedSmwId' );
 143+ $rel_smw_id = 0;
 144+ if ( $dbw->numRows( $res ) > 0 ) {
 145+ $rel_smw_id = $dbw->fetchObject( $res )->smw_id;
 146+ $dbw->freeResult( $res );
 147+ } else {
 148+ $dbw->freeResult( $res );
 149+ return false;
 150+ }
 151+
 152+ if ( $rel_smw_id > 0 ) {
 153+ $new_rel = true;
 154+ $relations[] = array(
 155+ 'notify_id' => $notify_id,
 156+ 'smw_id' => $rel_smw_id,
 157+ // $type: 0 category, 1 instance, 2 property
 158+ 'type' => ( ( $smw['namespace'] == NS_CATEGORY ) ? 0:( ( $smw['namespace'] == SMW_NS_PROPERTY ) ? 2:1 ) ),
 159+ 'subquery' => $subquery );
 160+ }
 161+ }
 162+ if ( $new_rel ) {
 163+ $dbw->insert( 'smw_nm_relations', $relations, $fname );
 164+ }
 165+ wfProfileOut( $fname );
 166+ return true;
 167+ }
 168+ public function getNotifications( $user_id ) {
 169+ $fname = 'NotifyMe::getNotifications';
 170+ wfProfileIn( $fname );
 171+
 172+ $result = array();
 173+
 174+ $db = wfGetDB( DB_SLAVE );
 175+ $res = $db->select( $db->tableName( 'smw_nm_query' ),
 176+ array( 'notify_id', 'delegate', 'name', 'query', 'enable', 'rep_all', 'show_all' ),
 177+ array( 'user_id' => $user_id ), $fname, array( 'ORDER BY' => 'notify_id' ) );
 178+ if ( $db->numRows( $res ) > 0 ) {
 179+ while ( $row = $db->fetchObject( $res ) ) {
 180+ $result[] = array( 'notify_id' => $row->notify_id,
 181+ 'delegate' => $row->delegate,
 182+ 'name' => $row->name,
 183+ 'query' => $row->query,
 184+ 'enable' => $row->enable,
 185+ 'rep_all' => $row->rep_all,
 186+ 'show_all' => $row->show_all );
 187+ }
 188+ }
 189+ $db->freeResult( $res );
 190+ wfProfileOut( $fname );
 191+ return $result;
 192+ }
 193+ public function getNotifyMe( $notify_ids ) {
 194+ $fname = 'NotifyMe::getNotifyMe';
 195+ wfProfileIn( $fname );
 196+
 197+ $result = array();
 198+
 199+ $db = wfGetDB( DB_SLAVE );
 200+ $res = $db->select( $db->tableName( 'smw_nm_query' ),
 201+ array( 'notify_id', 'name', 'query', 'show_all' ),
 202+ array( 'notify_id' => $notify_ids ), $fname );
 203+ if ( $db->numRows( $res ) > 0 ) {
 204+ while ( $row = $db->fetchObject( $res ) ) {
 205+ $result[$row->notify_id] = array( 'query' => $row->query,
 206+ 'name' => $row->name,
 207+ 'show_all' => $row->show_all );
 208+ }
 209+ }
 210+ $db->freeResult( $res );
 211+ wfProfileOut( $fname );
 212+ return $result;
 213+ }
 214+ public function getAllNotifications() {
 215+ $fname = 'NotifyMe::getAllNotifications';
 216+ wfProfileIn( $fname );
 217+
 218+ $result = array();
 219+
 220+ $db = wfGetDB( DB_SLAVE );
 221+ $res = $db->select( $db->tableName( 'smw_nm_query' ),
 222+ array( 'notify_id', 'delegate', 'name', 'query', 'enable', 'rep_all', 'show_all' ), '',
 223+ $fname, array( 'ORDER BY' => 'notify_id' ) );
 224+ if ( $db->numRows( $res ) > 0 ) {
 225+ while ( $row = $db->fetchObject( $res ) ) {
 226+ $result[] = array( 'notify_id' => $row->notify_id,
 227+ 'delegate' => $row->delegate,
 228+ 'name' => $row->name,
 229+ 'query' => $row->query,
 230+ 'enable' => $row->enable,
 231+ 'rep_all' => $row->rep_all,
 232+ 'show_all' => $row->show_all );
 233+ }
 234+ }
 235+ $db->freeResult( $res );
 236+ wfProfileOut( $fname );
 237+ return $result;
 238+ }
 239+ public function disableNotifyState( $notify_id ) {
 240+ $fname = 'NotifyMe::disableState';
 241+ wfProfileIn( $fname );
 242+ $db =& wfGetDB( DB_MASTER );
 243+ $db->delete( $db->tableName( 'smw_nm_monitor' ), array( 'notify_id' => $notify_id ), $fname );
 244+ $db->delete( $db->tableName( 'smw_nm_relations' ), array( 'notify_id' => $notify_id ), $fname );
 245+
 246+ $this->updateNotifyState( $notify_id, 0 );
 247+ wfProfileOut( $fname );
 248+ return true;
 249+ }
 250+ public function updateNotifyState( $notify_id, $state ) {
 251+ $fname = 'NotifyMe::updateNotifyState';
 252+ wfProfileIn( $fname );
 253+
 254+ $dbw =& wfGetDB( DB_MASTER );
 255+ $dbw->update( 'smw_nm_query', array( 'enable' => $state ), array( 'notify_id' => $notify_id ), $fname );
 256+ wfProfileOut( $fname );
 257+ return true;
 258+ }
 259+ public function updateDelegate( $notify_id, $delegate ) {
 260+ $fname = 'NotifyMe::updateDelegate';
 261+ wfProfileIn( $fname );
 262+ $dbw =& wfGetDB( DB_MASTER );
 263+ $dbw->update( 'smw_nm_query', array( 'delegate' => $delegate ), array( 'notify_id' => $notify_id ), $fname );
 264+ wfProfileOut( $fname );
 265+ return true;
 266+ }
 267+ public function updateNotifyReportAll( $notify_id, $rep_all ) {
 268+ $fname = 'NotifyMe::updateNotifyReportAll';
 269+ wfProfileIn( $fname );
 270+
 271+ $dbw =& wfGetDB( DB_MASTER );
 272+ $dbw->update( 'smw_nm_query', array( 'rep_all' => $rep_all ), array( 'notify_id' => $notify_id ), $fname );
 273+ wfProfileOut( $fname );
 274+ return true;
 275+ }
 276+ public function updateNotifyShowAll( $notify_id, $show_all ) {
 277+ $fname = 'NotifyMe::updateNotifyShowAll';
 278+ wfProfileIn( $fname );
 279+
 280+ $dbw =& wfGetDB( DB_MASTER );
 281+ $dbw->update( 'smw_nm_query', array( 'show_all' => $show_all ), array( 'notify_id' => $notify_id ), $fname );
 282+ wfProfileOut( $fname );
 283+ return true;
 284+ }
 285+
 286+ public function lookupSmwId( $namespace, $title ) {
 287+ $fname = 'NotifyMe::lookupSmwId';
 288+ wfProfileIn( $fname );
 289+
 290+ $result = 0;
 291+ $db = wfGetDB( DB_SLAVE );
 292+ $res = $db->selectRow( 'smw_ids', 'smw_id', array( 'smw_namespace' => $namespace, 'smw_title' => $title ), $fname );
 293+
 294+ if ( $res ) $result = $res->smw_id;
 295+ wfProfileOut( $fname );
 296+ return $result;
 297+ }
 298+ public function getMonitoredNotifications( $page_id ) {
 299+ $fname = 'NotifyMe::getMonitoredNotifications';
 300+ wfProfileIn( $fname );
 301+
 302+ $result = array();
 303+
 304+ $db = wfGetDB( DB_SLAVE );
 305+
 306+ $res = $db->select( array( $db->tableName( 'smw_nm_query' ) . ' q', $db->tableName( 'smw_nm_monitor' ) . ' m' ),
 307+ array( 'q.user_id', 'q.notify_id', 'q.delegate', 'q.name', 'q.rep_all' ),
 308+ 'm.page_id=' . $page_id . ' and m.notify_id=q.notify_id', $fname );
 309+ if ( $db->numRows( $res ) > 0 ) {
 310+ while ( $row = $db->fetchObject( $res ) ) {
 311+ $ds = explode( ',', $row->delegate );
 312+ $delegated = false;
 313+ foreach ( $ds as $delegate ) {
 314+ $u = User::newFromName( trim( $delegate ) );
 315+ if ( $u == null ) continue;
 316+ $id = $u->getId();
 317+ if ( $id > 0 ) {
 318+ $result[$id][$row->notify_id] = array( 'name' => $row->name, 'rep_all' => $row->rep_all );
 319+ $delegated = true;
 320+ }
 321+ }
 322+ if ( !$delegated ) {
 323+ $result[$row->user_id][$row->notify_id] = array( 'name' => $row->name, 'rep_all' => $row->rep_all );
 324+ }
 325+ }
 326+ }
 327+ $db->freeResult( $res );
 328+
 329+ wfProfileOut( $fname );
 330+ return $result;
 331+ }
 332+ public function getMonitoredNotificationsDetail( $page_id ) {
 333+ $fname = 'NotifyMe::getMonitoredNotificationsDetail';
 334+ wfProfileIn( $fname );
 335+
 336+ $result = array();
 337+
 338+ $notifies = $this->getMonitoredNotifications( $page_id );
 339+
 340+ $db = wfGetDB( DB_SLAVE );
 341+
 342+ foreach ( $notifies as $user_id => $notify ) {
 343+ foreach ( $notify as $notify_id => $notify_detail ) {
 344+ if ( $notify_detail['rep_all'] == 1 ) {
 345+ $result[$user_id]['rep_all'][$notify_id] = $notify_detail['name'];
 346+ } else {
 347+ $res = $db->select( $db->tableName( 'smw_nm_relations' ), array( 'smw_id', 'type' ), "notify_id=$notify_id AND subquery=0", $fname );
 348+ if ( $db->numRows( $res ) > 0 ) {
 349+ while ( $row = $db->fetchObject( $res ) ) {
 350+ $result[$user_id]['semantic'][SMWNotifyProcessor::toInfoId( $row->type, 0, $row->smw_id )][$notify_id] = $notify_detail['name'];
 351+ }
 352+ }
 353+ $db->freeResult( $res );
 354+ }
 355+ }
 356+ }
 357+
 358+ wfProfileOut( $fname );
 359+ return $result;
 360+ }
 361+ public function getPossibleQuery( $info ) {
 362+ $cnt = count( $info );
 363+ if ( $cnt == 0 ) {
 364+ return null;
 365+ }
 366+ $fname = 'NotifyMe::getPossibleQuery';
 367+ wfProfileIn( $fname );
 368+
 369+ $first = true;
 370+ foreach ( $info as $key => $value ) {
 371+ if ( $first ) {
 372+ $first = false;
 373+ } else {
 374+ $cond .= "OR ";
 375+ }
 376+ $i = SMWNotifyProcessor::getInfoFromId( $key );
 377+ $cond .= "(smw_id=$i[attr_id] AND type=$i[type]) ";
 378+ }
 379+
 380+ $db =& wfGetDB( DB_SLAVE );
 381+ $result = array( 0 => array(), 1 => array() );
 382+ extract( $db->tableNames( 'smw_nm_query', 'smw_nm_relations' ) );
 383+ $res = $db->query( "SELECT q.notify_id, q.name, q.user_id, q.delegate, q.nm_sql, q.nm_hierarchy, c1.subquery FROM (" .
 384+ "SELECT count(*) cnt, notify_id, subquery FROM $smw_nm_relations " .
 385+ "WHERE $cond GROUP BY notify_id, subquery" .
 386+ ") c1 INNER JOIN (" .
 387+ "SELECT count(*) cnt, notify_id, subquery FROM $smw_nm_relations " .
 388+ "WHERE type<>1 GROUP BY notify_id, subquery" .
 389+ ") c2 ON c1.notify_id=c2.notify_id AND c1.subquery=c2.subquery AND c1.cnt=c2.cnt " .
 390+ "LEFT JOIN $smw_nm_query q ON q.notify_id = c1.notify_id WHERE c1.cnt<=$cnt", $fname );
 391+ if ( $db->numRows( $res ) > 0 ) {
 392+ while ( $row = $db->fetchObject( $res ) ) {
 393+ $ds = explode( ',', $row->delegate );
 394+ $delegated = false;
 395+ foreach ( $ds as $delegate ) {
 396+ $u = User::newFromName( trim( $delegate ) );
 397+ if ( $u == null ) continue;
 398+ $id = $u->getId();
 399+ if ( $id > 0 ) {
 400+ $result[$row->subquery > 0 ? 1:0][$row->notify_id] = array( 'user_id' => $id, 'name' => $row->name, 'sql' => $row->nm_sql, 'hierarchy' => $row->nm_hierarchy );
 401+ $delegated = true;
 402+ }
 403+ }
 404+ if ( !$delegated ) {
 405+ $result[$row->subquery > 0 ? 1:0][$row->notify_id] = array( 'user_id' => $row->user_id, 'name' => $row->name, 'sql' => $row->nm_sql, 'hierarchy' => $row->nm_hierarchy );
 406+ }
 407+ }
 408+ }
 409+ $db->freeResult( $res );
 410+ wfProfileOut( $fname );
 411+ return $result;
 412+ }
 413+ public function getMonitoredQuery( $page_id ) {
 414+ $fname = 'NotifyMe::getMonitoredQuery';
 415+ wfProfileIn( $fname );
 416+
 417+ $db =& wfGetDB( DB_SLAVE );
 418+ $res = $db->select( array( $db->tableName( 'smw_nm_monitor' ) . ' m', $db->tableName( 'smw_nm_query' ) . ' q' ),
 419+ array( 'q.notify_id, q.delegate, q.name, q.user_id, q.nm_sql, q.nm_hierarchy' ),
 420+ "m.notify_id=q.notify_id AND m.page_id=$page_id", $fname );
 421+ if ( $db->numRows( $res ) > 0 ) {
 422+ while ( $row = $db->fetchObject( $res ) ) {
 423+ $ds = explode( ',', $row->delegate );
 424+ $delegated = false;
 425+ foreach ( $ds as $delegate ) {
 426+ $u = User::newFromName( trim( $delegate ) );
 427+ if ( $u == null ) continue;
 428+ $id = $u->getId();
 429+ if ( $id > 0 ) {
 430+ $result[$row->notify_id] = array( 'user_id' => $id, 'name' => $row->name, 'sql' => $row->nm_sql, 'hierarchy' => $row->nm_hierarchy );
 431+ $delegated = true;
 432+ }
 433+ }
 434+ if ( !$delegated ) {
 435+ $result[$row->notify_id] = array( 'user_id' => $row->user_id, 'name' => $row->name, 'sql' => $row->nm_sql, 'hierarchy' => $row->nm_hierarchy );
 436+ }
 437+ }
 438+ }
 439+ $db->freeResult( $res );
 440+ wfProfileOut( $fname );
 441+ return $result;
 442+ }
 443+ public function updateNMSql( $notify_id, $sql, $tmp_hierarchy ) {
 444+ $fname = 'NotifyMe::updateNMSql';
 445+ wfProfileIn( $fname );
 446+
 447+ $dbw =& wfGetDB( DB_MASTER );
 448+ $dbw->update( 'smw_nm_query', array( 'nm_sql' => $sql, 'nm_hierarchy' => $tmp_hierarchy ), array( 'notify_id' => $notify_id ), $fname );
 449+ wfProfileOut( $fname );
 450+ return true;
 451+ }
 452+ public function getNotifyInMainQuery( $page_id, $notify_id, $sql, $hierarchy, &$match, &$monitoring ) {
 453+ $fname = 'NotifyMe::getNotifyInMainQuery';
 454+ wfProfileIn( $fname );
 455+
 456+ $db =& wfGetDB( DB_SLAVE );
 457+
 458+ $tmp_tables = array();
 459+ if ( $hierarchy != '' ) {
 460+ $_hierarchies = array();
 461+ foreach ( explode( ";", $hierarchy ) as $attrs ) {
 462+ $part = explode( ":", $attrs, 3 );
 463+ $tablename = $db->tableName( $part[0] );
 464+ $depth = intval( $part[1] );
 465+ $values = $part[2];
 466+
 467+ $tmp_tables[] = $tablename;
 468+
 469+ $db->query( "CREATE TEMPORARY TABLE $tablename ( id INT UNSIGNED NOT NULL KEY) TYPE=MEMORY", 'SMW::executeQueries' );
 470+ if ( array_key_exists( $values, $_hierarchies ) ) { // just copy known result
 471+ $db->query( "INSERT INTO $tablename (id) SELECT id FROM " . $_hierarchies[$values], 'SMW::executeQueries' );
 472+ } else {
 473+ $tmpnew = 'smw_new';
 474+ $tmpres = 'smw_res';
 475+ $db->query( "CREATE TEMPORARY TABLE $tmpnew ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
 476+ $db->query( "CREATE TEMPORARY TABLE $tmpres ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
 477+ $db->query( "INSERT IGNORE INTO $tablename (id) VALUES $values", 'SMW::executeQueries' );
 478+ $db->query( "INSERT IGNORE INTO $tmpnew (id) VALUES $values", 'SMW::executeQueries' );
 479+ $smw_subs2 = $db->tableName( 'smw_subs2' );
 480+ for ( $i = 0; $i < $depth; $i++ ) {
 481+ $db->query( "INSERT INTO $tmpres (id) SELECT s_id FROM $smw_subs2, $tmpnew WHERE o_id=id", 'SMW::executeQueries' );
 482+ if ( $db->affectedRows() == 0 ) { // no change, exit loop
 483+ break;
 484+ }
 485+ $db->query( "INSERT IGNORE INTO $tablename (id) SELECT $tmpres.id FROM $tmpres", 'SMW::executeQueries' );
 486+ if ( $db->affectedRows() == 0 ) { // no change, exit loop
 487+ break;
 488+ }
 489+ $db->query( 'TRUNCATE TABLE ' . $tmpnew, 'SMW::executeQueries' ); // empty "new" table
 490+ $tmpname = $tmpnew;
 491+ $tmpnew = $tmpres;
 492+ $tmpres = $tmpname;
 493+ }
 494+ $_hierarchies[$values] = $tablename;
 495+ $db->query( 'DROP TEMPORARY TABLE smw_new', 'SMW::executeQueries' );
 496+ $db->query( 'DROP TEMPORARY TABLE smw_res', 'SMW::executeQueries' );
 497+ }
 498+ }
 499+ }
 500+
 501+ $sql = "SELECT p.page_id FROM " . $db->tableName( 'page' ) . " AS p INNER JOIN ($sql) AS s ON s.t=p.page_title AND s.ns=p.page_namespace WHERE p.page_id=$page_id";
 502+ $res = $db->query( $sql, $fname );
 503+ $match = ( $db->numRows( $res ) > 0 );
 504+ $db->freeResult( $res );
 505+
 506+ foreach ( $tmp_tables as $tablename ) {
 507+ $db->query( "DROP TEMPORARY TABLE $tablename", 'SMW::getQueryResult' );
 508+ }
 509+
 510+ $monitoring = ( $db->selectRow( 'smw_nm_monitor', array( 'page_id' ),
 511+ array( 'page_id' => $page_id, 'notify_id' => $notify_id ), $fname ) != false );
 512+
 513+ wfProfileOut( $fname );
 514+ return true;
 515+ }
 516+ public function getNotifyInSubquery( $notify_id, $sql, $hierarchy ) {
 517+ $fname = 'NotifyMe::getNotifyInSubquery';
 518+ wfProfileIn( $fname );
 519+
 520+ $result = array( 'monitoring' => array(), 'match' => array() );
 521+
 522+ $db =& wfGetDB( DB_SLAVE );
 523+
 524+ $tmp_tables = array();
 525+ if ( $hierarchy != '' ) {
 526+ $_hierarchies = array();
 527+ foreach ( explode( ";", $hierarchy ) as $attrs ) {
 528+ $part = explode( ":", $attrs, 3 );
 529+ $tablename = $db->tableName( $part[0] );
 530+ $depth = intval( $part[1] );
 531+ $values = $part[2];
 532+
 533+ $tmp_tables[] = $tablename;
 534+
 535+ $db->query( "CREATE TEMPORARY TABLE $tablename ( id INT UNSIGNED NOT NULL KEY) TYPE=MEMORY", 'SMW::executeQueries' );
 536+ if ( array_key_exists( $values, $_hierarchies ) ) { // just copy known result
 537+ $db->query( "INSERT INTO $tablename (id) SELECT id FROM " . $_hierarchies[$values], 'SMW::executeQueries' );
 538+ } else {
 539+ $tmpnew = 'smw_new';
 540+ $tmpres = 'smw_res';
 541+ $db->query( "CREATE TEMPORARY TABLE $tmpnew ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
 542+ $db->query( "CREATE TEMPORARY TABLE $tmpres ( id INT UNSIGNED ) TYPE=MEMORY", 'SMW::executeQueries' );
 543+ $db->query( "INSERT IGNORE INTO $tablename (id) VALUES $values", 'SMW::executeQueries' );
 544+ $db->query( "INSERT IGNORE INTO $tmpnew (id) VALUES $values", 'SMW::executeQueries' );
 545+ $smw_subs2 = $db->tableName( 'smw_subs2' );
 546+ for ( $i = 0; $i < $depth; $i++ ) {
 547+ $db->query( "INSERT INTO $tmpres (id) SELECT s_id FROM $smw_subs2, $tmpnew WHERE o_id=id", 'SMW::executeQueries' );
 548+ if ( $db->affectedRows() == 0 ) { // no change, exit loop
 549+ break;
 550+ }
 551+ $db->query( "INSERT IGNORE INTO $tablename (id) SELECT $tmpres.id FROM $tmpres", 'SMW::executeQueries' );
 552+ if ( $db->affectedRows() == 0 ) { // no change, exit loop
 553+ break;
 554+ }
 555+ $db->query( 'TRUNCATE TABLE ' . $tmpnew, 'SMW::executeQueries' ); // empty "new" table
 556+ $tmpname = $tmpnew;
 557+ $tmpnew = $tmpres;
 558+ $tmpres = $tmpname;
 559+ }
 560+ $_hierarchies[$values] = $tablename;
 561+ $db->query( 'DROP TEMPORARY TABLE smw_new', 'SMW::executeQueries' );
 562+ $db->query( 'DROP TEMPORARY TABLE smw_res', 'SMW::executeQueries' );
 563+ }
 564+ }
 565+ }
 566+
 567+ $res = $db->query( "SELECT p.page_id FROM " . $db->tableName( 'page' ) . " AS p INNER JOIN ($sql) AS s ON s.t=p.page_title AND s.ns=p.page_namespace", $fname );
 568+ if ( $db->numRows( $res ) > 0 ) {
 569+ while ( $row = $db->fetchObject( $res ) ) {
 570+ $result['match'][] = $row->page_id;
 571+ }
 572+ }
 573+ $db->freeResult( $res );
 574+
 575+ foreach ( $tmp_tables as $tablename ) {
 576+ $db->query( "DROP TEMPORARY TABLE $tablename", 'SMW::getQueryResult' );
 577+ }
 578+
 579+ $res = $db->select( $db->tableName( 'smw_nm_monitor' ), array( 'page_id' ), array( 'notify_id' => $notify_id ), $fname );
 580+ if ( $db->numRows( $res ) > 0 ) {
 581+ while ( $row = $db->fetchObject( $res ) ) {
 582+ $result['monitoring'][] = $row->page_id;
 583+ }
 584+ }
 585+ $db->freeResult( $res );
 586+
 587+ wfProfileOut( $fname );
 588+ return $result;
 589+ }
 590+ public function getUserInfo( $user_id ) {
 591+ $fname = 'NotifyMe::getUserInfo';
 592+ wfProfileIn( $fname );
 593+
 594+ $db = wfGetDB( DB_SLAVE );
 595+ $result = $db->selectRow( 'user', array( 'user_name', 'user_real_name', 'user_email', 'user_options' ), array( 'user_id' => $user_id ), $fname );
 596+
 597+ wfProfileOut( $fname );
 598+ return $result;
 599+ }
 600+ public function getPageTitle( $page_id ) {
 601+ $db =& wfGetDB( DB_SLAVE );
 602+ return $db->selectRow( 'page', 'page_title', array( 'page_id' => $page_id ) );
 603+ }
 604+ public function addNotifyRSS( $type, $id, $title, $msg, $link = NULL ) {
 605+ $fname = 'NotifyMe::addNotifyRSS';
 606+ wfProfileIn( $fname );
 607+ $db =& wfGetDB( DB_MASTER );
 608+
 609+ $rid = $db->nextSequenceValue( 'nmrss_msg_id_seq' );
 610+ $values = array( 'msg_id' => $rid,
 611+ 'title' => $title,
 612+ 'notify' => $msg,
 613+ 'timestamp' => $db->timestamp() );
 614+ if ( $type == "uid" ) {
 615+ $values['user_id'] = $id;
 616+ } else {
 617+ $values['notify_id'] = $id;
 618+ }
 619+ if ( $link !== NULL ) {
 620+ $values['link'] = $link;
 621+ }
 622+
 623+ $db->insert( 'smw_nm_rss', $values, $fname );
 624+ $id = $db->insertId();
 625+
 626+ wfProfileOut( $fname );
 627+ return $id;
 628+ }
 629+ public function getNotifyRSS( $type, $id, $limit ) {
 630+ $fname = 'NotifyMe::getNotifyRSS';
 631+ wfProfileIn( $fname );
 632+ $db =& wfGetDB( DB_SLAVE );
 633+ $result = array();
 634+ if ( $type == "uid" ) {
 635+ $ids = array( 'user_id' => $id );
 636+ } else {
 637+ $ids = array( 'notify_id' => $id );
 638+ }
 639+ $res = $db->select( $db->tableName( 'smw_nm_rss' ), array( 'title', 'link', 'notify', 'timestamp' ), $ids, $fname, array( 'ORDER BY' => 'timestamp DESC', 'LIMIT' => $limit ) );
 640+ if ( $db->numRows( $res ) > 0 ) {
 641+ while ( $row = $db->fetchObject( $res ) ) {
 642+ $result[] = array( 'title' => $row->title, 'link' => $row->link, 'notify' => $row->notify, 'timestamp' => $row->timestamp );
 643+ }
 644+ }
 645+ $db->freeResult( $res );
 646+ wfProfileOut( $fname );
 647+ return $result;
 648+ }
 649+ public function getUnmailedNMMessages() {
 650+ $fname = 'NotifyMe::getUnmailedNMMessages';
 651+ wfProfileIn( $fname );
 652+ $db =& wfGetDB( DB_MASTER );
 653+ $smw_nm_rss = $db->tableName( 'smw_nm_rss' );
 654+ $result = array();
 655+ $res = $db->select( $smw_nm_rss,
 656+ array( 'user_id', 'title', 'notify', 'timestamp' ),
 657+ array( 'mailed' => '0' ), $fname );
 658+ if ( $db->numRows( $res ) > 0 ) {
 659+ while ( $row = $db->fetchObject( $res ) ) {
 660+ $result[] = array( 'user_id' => $row->user_id, 'title' => $row->title, 'notify' => $row->notify, 'timestamp' => $row->timestamp );
 661+ }
 662+ }
 663+ $db->freeResult( $res );
 664+ $db->update( $smw_nm_rss, array( 'mailed' => '1' ), array( 'mailed' => '0' ), $fname );
 665+ wfProfileOut( $fname );
 666+ return $result;
 667+ }
 668+
 669+ public function getGroupedUsers( $groups ) {
 670+ $fname = 'NotifyMe::getGroupedUsers';
 671+ wfProfileIn( $fname );
 672+ $db =& wfGetDB( DB_SLAVE );
 673+ extract( $db->tableNames( 'user_groups', 'user' ) );
 674+ $result = array();
 675+ $res = $db->query( "SELECT u.user_name FROM $user u" .
 676+ ( $groups ? " LEFT JOIN $user_groups g ON u.user_id = g.ug_user
 677+ WHERE g.ug_group IN ('" . join( "','", $groups ) . "')
 678+ GROUP BY user_name":"" ), $fname );
 679+ if ( $db->numRows( $res ) > 0 ) {
 680+ while ( $row = $db->fetchObject( $res ) ) {
 681+ $result[] = $row->user_name;
 682+ }
 683+ }
 684+ $db->freeResult( $res );
 685+ wfProfileOut( $fname );
 686+ return $result;
 687+ }
 688+
 689+ function getNMQueryResult( SMWQuery $query ) {
 690+ wfProfileIn( 'SMWSQLStore2::getNMQueryResult (SMW)' );
 691+ global $smwgNMIP;
 692+ include_once( "$smwgNMIP/includes/storage/SMW_SQLStore2_QueriesNM.php" );
 693+ $qe = new SMWSQLStore2QueryEngineNM( smwfGetStore(), wfGetDB( DB_SLAVE ) );
 694+ $result = $qe->getQueryResult( $query );
 695+ wfProfileOut( 'SMWSQLStore2::getNMQueryResult (SMW)' );
 696+ return $result;
 697+ }
 698+}
Property changes on: trunk/extensions/SemanticNotifyMe/includes/storage/SMW_NMStorageSQL.php
___________________________________________________________________
Name: svn:eol-style
702699 + native
Index: trunk/extensions/SemanticNotifyMe/includes/SMW_NMStorage.php
@@ -1,84 +1,82 @@
2 -<?php
3 -
4 -/**
5 - * This file provides the access to the database tables that are
6 - * used by the NotifyMe extension.
7 - *
8 - * @author dch
9 - *
10 - */
11 -if ( !defined( 'MEDIAWIKI' ) ) die;
12 -global $smwgNMIP;
13 -require_once $smwgNMIP . '/includes/SMW_NMDBHelper.php';
14 -
15 -
16 -
17 -/**
18 - * This class encapsulates all methods that care about the database tables of
19 - * the NotifyMe extension. It is a singleton that contains an instance
20 - * of the actual database access object e.g. the Mediawiki SQL database.
21 - *
22 - */
23 -class NMStorage {
24 -
25 - //--- Private fields---
26 -
27 - private static $mInstance; // NMStorage: the only instance of this singleton
28 - private static $mDatabase; // The actual database object
29 -
30 - //--- Constructor ---
31 -
32 - /**
33 - * Constructor.
34 - * Creates the object that handles the concrete database access.
35 - *
36 - */
37 - private function __construct() {
38 - if (self::$mDatabase == NULL) {
39 - global $smwgBaseStore;
40 - switch ($smwgBaseStore) {
41 - case (SMW_STORE_TESTING):
42 - trigger_error('Testing store not implemented for NotifyMe extension.');
43 - break;
44 - case (SMW_STORE_MWDB):
45 - default:
46 - global $smwgNMIP;
47 - require_once($smwgNMIP . '/includes/storage/SMW_NMStorageSQL.php');
48 - self::$mDatabase = new NMStorageSQL();
49 - break;
50 - }
51 - }
52 -
53 - }
54 -
55 - //--- Public methods ---
56 -
57 - /**
58 - * Returns the single instance of this class.
59 - *
60 - * @return NMStorage
61 - * The single instance of this class.
62 - */
63 - public static function getInstance() {
64 - if (!isset(self::$mInstance)) {
65 - $c = __CLASS__;
66 - self::$mInstance = new $c;
67 - }
68 -
69 - return self::$mInstance;
70 - }
71 -
72 - /**
73 - * Returns the actual database.
74 - *
75 - * @return object
76 - * The object to access the database.
77 - */
78 - public static function getDatabase() {
79 - self::getInstance(); // Make sure, singleton is initialized
80 - return self::$mDatabase;
81 - }
82 -
83 -}
84 -
85 -?>
\ No newline at end of file
 2+<?php
 3+
 4+/**
 5+ * This file provides the access to the database tables that are
 6+ * used by the NotifyMe extension.
 7+ *
 8+ * @author dch
 9+ *
 10+ */
 11+if ( !defined( 'MEDIAWIKI' ) ) die;
 12+global $smwgNMIP;
 13+require_once $smwgNMIP . '/includes/SMW_NMDBHelper.php';
 14+
 15+
 16+
 17+/**
 18+ * This class encapsulates all methods that care about the database tables of
 19+ * the NotifyMe extension. It is a singleton that contains an instance
 20+ * of the actual database access object e.g. the Mediawiki SQL database.
 21+ *
 22+ */
 23+class NMStorage {
 24+
 25+ // --- Private fields---
 26+
 27+ private static $mInstance; // NMStorage: the only instance of this singleton
 28+ private static $mDatabase; // The actual database object
 29+
 30+ // --- Constructor ---
 31+
 32+ /**
 33+ * Constructor.
 34+ * Creates the object that handles the concrete database access.
 35+ *
 36+ */
 37+ private function __construct() {
 38+ if ( self::$mDatabase == NULL ) {
 39+ global $smwgBaseStore;
 40+ switch ( $smwgBaseStore ) {
 41+ case ( SMW_STORE_TESTING ):
 42+ trigger_error( 'Testing store not implemented for NotifyMe extension.' );
 43+ break;
 44+ case ( SMW_STORE_MWDB ):
 45+ default:
 46+ global $smwgNMIP;
 47+ require_once( $smwgNMIP . '/includes/storage/SMW_NMStorageSQL.php' );
 48+ self::$mDatabase = new NMStorageSQL();
 49+ break;
 50+ }
 51+ }
 52+
 53+ }
 54+
 55+ // --- Public methods ---
 56+
 57+ /**
 58+ * Returns the single instance of this class.
 59+ *
 60+ * @return NMStorage
 61+ * The single instance of this class.
 62+ */
 63+ public static function getInstance() {
 64+ if ( !isset( self::$mInstance ) ) {
 65+ $c = __CLASS__;
 66+ self::$mInstance = new $c;
 67+ }
 68+
 69+ return self::$mInstance;
 70+ }
 71+
 72+ /**
 73+ * Returns the actual database.
 74+ *
 75+ * @return object
 76+ * The object to access the database.
 77+ */
 78+ public static function getDatabase() {
 79+ self::getInstance(); // Make sure, singleton is initialized
 80+ return self::$mDatabase;
 81+ }
 82+
 83+}
Property changes on: trunk/extensions/SemanticNotifyMe/includes/SMW_NMStorage.php
___________________________________________________________________
Name: svn:eol-style
8684 + native
Index: trunk/extensions/SemanticNotifyMe/includes/SMW_NMDBHelper.php
@@ -1,304 +1,299 @@
2 -<?php
3 -/*
4 - * Created on 19.10.2008
5 - *
6 - * Author: dch
7 - */
8 -
9 -
10 -
11 -class SNMDBHelper {
12 -
13 -
14 - /**
15 - * Make sure the table of the given name has the given fields, provided
16 - * as an array with entries fieldname => typeparams. typeparams should be
17 - * in a normalised form and order to match to existing values.
18 - *
19 - * The function returns an array that includes all columns that have been
20 - * changed. For each such column, the array contains an entry
21 - * columnname => action, where action is one of 'up', 'new', or 'del'
22 - * If the table was already fine or was created completely anew, an empty
23 - * array is returned (assuming that both cases require no action).
24 - *
25 - * NOTE: the function partly ignores the order in which fields are set up.
26 - * Only if the type of some field changes will its order be adjusted explicitly.
27 - *
28 - * @param string $primaryKeys
29 - * This optional string specifies the primary keys if there is more
30 - * than one. This is a comma separated list of column names. The primary
31 - * keys are not altered, if the table already exists.
32 - */
33 - public static function setupTable($table, $fields, $db, $verbose, $primaryKeys = "") {
34 - global $wgDBname;
35 - SNMDBHelper::reportProgress("Setting up table $table ...\n",$verbose);
36 - if ($db->tableExists($table) === false) { // create new table
37 - $sql = 'CREATE TABLE ' . $wgDBname . '.' . $table . ' (';
38 - $first = true;
39 - foreach ($fields as $name => $type) {
40 - if ($first) {
41 - $first = false;
42 - } else {
43 - $sql .= ',';
44 - }
45 - $sql .= $name . ' ' . $type;
46 - }
47 - if (!empty($primaryKeys)) {
48 - $sql .= ", PRIMARY KEY(".$primaryKeys.")";
49 - }
50 - $sql .= ') TYPE=myisam';
51 - $db->query( $sql, 'SNMDBHelper::setupTable' );
52 - SNMDBHelper::reportProgress(" ... new table created\n",$verbose);
53 - return array();
54 - } else { // check table signature
55 - SNMDBHelper::reportProgress(" ... table exists already, checking structure ...\n",$verbose);
56 - $res = $db->query( 'DESCRIBE ' . $table, 'SNMDBHelper::setupTable' );
57 - $curfields = array();
58 - $result = array();
59 - while ($row = $db->fetchObject($res)) {
60 - $type = strtoupper($row->Type);
61 - if (substr($type,0,8) == 'VARCHAR(') {
62 - $type .= ' binary'; // just assume this to be the case for VARCHAR, avoid collation checks
63 - }
64 - if ($row->Null != 'YES') {
65 - $type .= ' NOT NULL';
66 - }
67 - if ($row->Key == 'PRI') { /// FIXME: updating "KEY" is not possible, the below query will fail in this case.
68 - $type .= ' KEY';
69 - }
70 - if ($row->Extra == 'auto_increment') {
71 - $type .= ' AUTO_INCREMENT';
72 - }
73 - if ($row->Default != '') {
74 - $type .= ' default \''.$row->Default.'\'';
75 - }
76 -
77 - $curfields[$row->Field] = $type;
78 - }
79 - $position = 'FIRST';
80 - foreach ($fields as $name => $type) {
81 - if ( !array_key_exists($name,$curfields) ) {
82 - SNMDBHelper::reportProgress(" ... creating column $name ... ",$verbose);
83 - $db->query("ALTER TABLE $table ADD `$name` $type $position", 'SNMDBHelper::setupTable');
84 - $result[$name] = 'new';
85 - SNMDBHelper::reportProgress("done \n",$verbose);
86 - } elseif ($curfields[$name] != $type) {// && stripos("auto_increment", $type) == -1) {
87 - SNMDBHelper::reportProgress(" ... changing type of column $name from '$curfields[$name]' to '$type' ... ",$verbose);
88 - $db->query("ALTER TABLE $table CHANGE `$name` `$name` $type $position", 'SNMDBHelper::setupTable');
89 - $result[$name] = 'up';
90 - $curfields[$name] = false;
91 - SNMDBHelper::reportProgress("done.\n",$verbose);
92 - } else {
93 - SNMDBHelper::reportProgress(" ... column $name is fine\n",$verbose);
94 - $curfields[$name] = false;
95 - }
96 - $position = "AFTER $name";
97 - }
98 - foreach ($curfields as $name => $value) {
99 - if ($value !== false) { // not encountered yet --> delete
100 - SNMDBHelper::reportProgress(" ... deleting obsolete column $name ... ",$verbose);
101 - $db->query("ALTER TABLE $table DROP COLUMN `$name`", 'SNMDBHelper::setupTable');
102 - $result[$name] = 'del';
103 - SNMDBHelper::reportProgress("done.\n",$verbose);
104 - }
105 - }
106 - SNMDBHelper::reportProgress(" ... table $table set up successfully.\n",$verbose);
107 - return $result;
108 - }
109 - }
110 -
111 - /**
112 - * Make sure that each of the column descriptions in the given array is indexed by *one* index
113 - * in the given DB table.
114 - */
115 - public static function setupIndex($table, $columns, $db) {
116 - $table = $db->tableName($table);
117 - $res = $db->query( 'SHOW INDEX FROM ' . $table , 'SMW::SetupIndex');
118 - if ( !$res ) {
119 - return false;
120 - }
121 - $indexes = array();
122 - while ( $row = $db->fetchObject( $res ) ) {
123 - if (!array_key_exists($row->Key_name, $indexes)) {
124 - $indexes[$row->Key_name] = array();
125 - }
126 - $indexes[$row->Key_name][$row->Seq_in_index] = $row->Column_name;
127 - }
128 - foreach ($indexes as $key => $index) { // clean up existing indexes
129 - $id = array_search(implode(',', $index), $columns );
130 - if ( $id !== false ) {
131 - $columns[$id] = false;
132 - } else { // duplicate or unrequired index
133 - if($key != 'PRIMARY') {
134 - $db->query( 'DROP INDEX ' . $key . ' ON ' . $table, 'SMW::SetupIndex');
135 - }
136 - }
137 - }
138 -
139 - foreach ($columns as $column) { // add remaining indexes
140 - if ($column != false) {
141 - $db->query( "ALTER TABLE $table ADD INDEX ( $column )", 'SMW::SetupIndex');
142 - }
143 - }
144 - return true;
145 - }
146 -
147 - /**
148 - * Print some output to indicate progress. The output message is given by
149 - * $msg, while $verbose indicates whether or not output is desired at all.
150 - */
151 - public static function reportProgress($msg, $verbose) {
152 - if (!$verbose) {
153 - return;
154 - }
155 - if (ob_get_level() == 0) { // be sure to have some buffer, otherwise some PHPs complain
156 - ob_start();
157 - }
158 - print $msg;
159 - ob_flush();
160 - flush();
161 - }
162 -
163 - /**
164 - * Transform input parameters into a suitable array of SQL options.
165 - * The parameter $valuecol defines the string name of the column to which
166 - * sorting requests etc. are to be applied.
167 - */
168 - public static function getSQLOptions($requestoptions, $valuecol = NULL) {
169 - $sql_options = array();
170 - if ($requestoptions !== NULL) {
171 - if (is_numeric($requestoptions->limit) && $requestoptions->limit >= 0) {
172 - $sql_options['LIMIT'] = $requestoptions->limit;
173 - }
174 - if (is_numeric($requestoptions->offset) && $requestoptions->offset > 0) {
175 - $sql_options['OFFSET'] = $requestoptions->offset;
176 - }
177 - if ( ($valuecol !== NULL) && ($requestoptions->sort) ) {
178 - if (is_array($valuecol)) {
179 - $sql_options['ORDER BY'] = $requestoptions->ascending ? mysql_real_escape_string(implode(",",$valuecol)) : mysql_real_escape_string(implode(",",$valuecol)) . ' DESC';
180 - } else {
181 - $sql_options['ORDER BY'] = $requestoptions->ascending ? mysql_real_escape_string($valuecol) : mysql_real_escape_string($valuecol) . ' DESC';
182 - }
183 - }
184 - }
185 - return $sql_options;
186 - }
187 -
188 - public static function getSQLOptionsAsString($requestoptions, $valuecol = NULL) {
189 - $options = SNMDBHelper::getSQLOptions($requestoptions,$valuecol);
190 - $limit = array_key_exists('LIMIT', $options) && is_numeric($options['LIMIT'])? 'LIMIT '.$options['LIMIT'] : '';
191 - $offset = array_key_exists('OFFSET', $options) && is_numeric($options['OFFSET']) ? 'OFFSET '.$options['OFFSET'] : '';
192 - $orderby = array_key_exists('ORDER BY', $options) ? 'ORDER BY '.$options['ORDER BY'] : '';
193 - return $orderby.' '.$limit.' '.$offset;
194 - }
195 -
196 - /**
197 - * Transform input parameters into a suitable string of additional SQL conditions.
198 - * The parameter $valuecol defines the string name of the column to which
199 - * value restrictions etc. are to be applied.
200 - * @param $requestoptions object with options
201 - * @param $valuecol name of SQL column to which conditions apply
202 - * @param $labelcol name of SQL column to which string conditions apply, if any
203 - */
204 - public static function getSQLConditions($requestoptions, $valuecol, $labelcol = NULL) {
205 - $sql_conds = '';
206 - if ($requestoptions !== NULL) {
207 - $db =& wfGetDB( DB_SLAVE ); // TODO: use slave?
208 - if ($requestoptions->boundary !== NULL) { // apply value boundary
209 - if ($requestoptions->ascending) {
210 - if ($requestoptions->include_boundary) {
211 - $op = ' >= ';
212 - } else {
213 - $op = ' > ';
214 - }
215 - } else {
216 - if ($requestoptions->include_boundary) {
217 - $op = ' <= ';
218 - } else {
219 - $op = ' < ';
220 - }
221 - }
222 - $sql_conds .= ' AND ' . mysql_real_escape_string($valuecol) . $op . $db->addQuotes($requestoptions->boundary);
223 - }
224 - $operator = isset($requestoptions->disjunctiveStrings) && $requestoptions->disjunctiveStrings === true ? ' OR ' : ' AND ';
225 - $neutral = isset($requestoptions->disjunctiveStrings) && $requestoptions->disjunctiveStrings === true ? ' FALSE ' : ' TRUE ';
226 - if ($labelcol !== NULL) { // apply string conditions
227 -
228 - $sql_conds .= ' AND ( ';
229 -
230 - foreach ($requestoptions->getStringConditions() as $strcond) {
231 - $string = str_replace(array('_', ' '), array('\_', '\_'), $strcond->string);
232 - switch ($strcond->condition) {
233 - case SMWStringCondition::STRCOND_PRE:
234 - $string .= '%';
235 - break;
236 - case SMWStringCondition::STRCOND_POST:
237 - $string = '%' . $string;
238 - break;
239 - case SMWStringCondition::STRCOND_MID:
240 - $string = '%' . $string . '%';
241 - break;
242 - }
243 - if ($requestoptions->isCaseSensitive) {
244 - $sql_conds .= mysql_real_escape_string($labelcol) . ' LIKE ' . $db->addQuotes($string). $operator;
245 - } else {
246 - $sql_conds .= ' UPPER(' . mysql_real_escape_string($labelcol) . ') LIKE UPPER(' . $db->addQuotes($string).') '.$operator;
247 - }
248 - }
249 - $sql_conds .= ' '.$neutral.' ) ';
250 - }
251 - }
252 - return $sql_conds;
253 - }
254 -
255 - /**
256 - * Returns sql conditions of $requestoptions in an Array.
257 - * Warning! Does not support SMWAdvRequestOptions
258 - *
259 - * @param SMWRequestOptions $requestoptions
260 - * @param string $valuecol
261 - * @param string $labelcol
262 - * @return array
263 - */
264 - public static function getSQLConditionsAsArray($requestoptions, $valuecol, $labelcol = NULL) {
265 - $sql_conds = array();
266 - if ($requestoptions !== NULL) {
267 - $db =& wfGetDB( DB_SLAVE );
268 - if ($requestoptions->boundary !== NULL) { // apply value boundary
269 - if ($requestoptions->ascending) {
270 - if ($requestoptions->include_boundary) {
271 - $op = ' >= ';
272 - } else {
273 - $op = ' > ';
274 - }
275 - } else {
276 - if ($requestoptions->include_boundary) {
277 - $op = ' <= ';
278 - } else {
279 - $op = ' < ';
280 - }
281 - }
282 - $sql_conds[] = mysql_real_escape_string($valuecol) . $op . $db->addQuotes($requestoptions->boundary);
283 - }
284 - if ($labelcol !== NULL) { // apply string conditions
285 - foreach ($requestoptions->getStringConditions() as $strcond) {
286 - $string = str_replace(array('_', ' '), array('\_', '\_'), $strcond->string);
287 - switch ($strcond->condition) {
288 - case SMWStringCondition::STRCOND_PRE:
289 - $string .= '%';
290 - break;
291 - case SMWStringCondition::STRCOND_POST:
292 - $string = '%' . $string;
293 - break;
294 - case SMWStringCondition::STRCOND_MID:
295 - $string = '%' . $string . '%';
296 - break;
297 - }
298 - $sql_conds[] = 'UPPER('.mysql_real_escape_string($labelcol) . ') LIKE UPPER(' . $db->addQuotes($string).')';
299 - }
300 - }
301 - }
302 - return $sql_conds;
303 - }
304 -}
305 -?>
 2+<?php
 3+/*
 4+ * Created on 19.10.2008
 5+ *
 6+ * Author: dch
 7+ */
 8+
 9+class SNMDBHelper {
 10+ /**
 11+ * Make sure the table of the given name has the given fields, provided
 12+ * as an array with entries fieldname => typeparams. typeparams should be
 13+ * in a normalised form and order to match to existing values.
 14+ *
 15+ * The function returns an array that includes all columns that have been
 16+ * changed. For each such column, the array contains an entry
 17+ * columnname => action, where action is one of 'up', 'new', or 'del'
 18+ * If the table was already fine or was created completely anew, an empty
 19+ * array is returned (assuming that both cases require no action).
 20+ *
 21+ * NOTE: the function partly ignores the order in which fields are set up.
 22+ * Only if the type of some field changes will its order be adjusted explicitly.
 23+ *
 24+ * @param string $primaryKeys
 25+ * This optional string specifies the primary keys if there is more
 26+ * than one. This is a comma separated list of column names. The primary
 27+ * keys are not altered, if the table already exists.
 28+ */
 29+ public static function setupTable( $table, $fields, $db, $verbose, $primaryKeys = "" ) {
 30+ global $wgDBname;
 31+ SNMDBHelper::reportProgress( "Setting up table $table ...\n", $verbose );
 32+ if ( $db->tableExists( $table ) === false ) { // create new table
 33+ $sql = 'CREATE TABLE ' . $wgDBname . '.' . $table . ' (';
 34+ $first = true;
 35+ foreach ( $fields as $name => $type ) {
 36+ if ( $first ) {
 37+ $first = false;
 38+ } else {
 39+ $sql .= ',';
 40+ }
 41+ $sql .= $name . ' ' . $type;
 42+ }
 43+ if ( !empty( $primaryKeys ) ) {
 44+ $sql .= ", PRIMARY KEY(" . $primaryKeys . ")";
 45+ }
 46+ $sql .= ') TYPE=myisam';
 47+ $db->query( $sql, 'SNMDBHelper::setupTable' );
 48+ SNMDBHelper::reportProgress( " ... new table created\n", $verbose );
 49+ return array();
 50+ } else { // check table signature
 51+ SNMDBHelper::reportProgress( " ... table exists already, checking structure ...\n", $verbose );
 52+ $res = $db->query( 'DESCRIBE ' . $table, 'SNMDBHelper::setupTable' );
 53+ $curfields = array();
 54+ $result = array();
 55+ while ( $row = $db->fetchObject( $res ) ) {
 56+ $type = strtoupper( $row->Type );
 57+ if ( substr( $type, 0, 8 ) == 'VARCHAR(' ) {
 58+ $type .= ' binary'; // just assume this to be the case for VARCHAR, avoid collation checks
 59+ }
 60+ if ( $row->Null != 'YES' ) {
 61+ $type .= ' NOT NULL';
 62+ }
 63+ if ( $row->Key == 'PRI' ) { // / FIXME: updating "KEY" is not possible, the below query will fail in this case.
 64+ $type .= ' KEY';
 65+ }
 66+ if ( $row->Extra == 'auto_increment' ) {
 67+ $type .= ' AUTO_INCREMENT';
 68+ }
 69+ if ( $row->Default != '' ) {
 70+ $type .= ' default \'' . $row->Default . '\'';
 71+ }
 72+
 73+ $curfields[$row->Field] = $type;
 74+ }
 75+ $position = 'FIRST';
 76+ foreach ( $fields as $name => $type ) {
 77+ if ( !array_key_exists( $name, $curfields ) ) {
 78+ SNMDBHelper::reportProgress( " ... creating column $name ... ", $verbose );
 79+ $db->query( "ALTER TABLE $table ADD `$name` $type $position", 'SNMDBHelper::setupTable' );
 80+ $result[$name] = 'new';
 81+ SNMDBHelper::reportProgress( "done \n", $verbose );
 82+ } elseif ( $curfields[$name] != $type ) {// && stripos("auto_increment", $type) == -1) {
 83+ SNMDBHelper::reportProgress( " ... changing type of column $name from '$curfields[$name]' to '$type' ... ", $verbose );
 84+ $db->query( "ALTER TABLE $table CHANGE `$name` `$name` $type $position", 'SNMDBHelper::setupTable' );
 85+ $result[$name] = 'up';
 86+ $curfields[$name] = false;
 87+ SNMDBHelper::reportProgress( "done.\n", $verbose );
 88+ } else {
 89+ SNMDBHelper::reportProgress( " ... column $name is fine\n", $verbose );
 90+ $curfields[$name] = false;
 91+ }
 92+ $position = "AFTER $name";
 93+ }
 94+ foreach ( $curfields as $name => $value ) {
 95+ if ( $value !== false ) { // not encountered yet --> delete
 96+ SNMDBHelper::reportProgress( " ... deleting obsolete column $name ... ", $verbose );
 97+ $db->query( "ALTER TABLE $table DROP COLUMN `$name`", 'SNMDBHelper::setupTable' );
 98+ $result[$name] = 'del';
 99+ SNMDBHelper::reportProgress( "done.\n", $verbose );
 100+ }
 101+ }
 102+ SNMDBHelper::reportProgress( " ... table $table set up successfully.\n", $verbose );
 103+ return $result;
 104+ }
 105+ }
 106+
 107+ /**
 108+ * Make sure that each of the column descriptions in the given array is indexed by *one* index
 109+ * in the given DB table.
 110+ */
 111+ public static function setupIndex( $table, $columns, $db ) {
 112+ $table = $db->tableName( $table );
 113+ $res = $db->query( 'SHOW INDEX FROM ' . $table , 'SMW::SetupIndex' );
 114+ if ( !$res ) {
 115+ return false;
 116+ }
 117+ $indexes = array();
 118+ while ( $row = $db->fetchObject( $res ) ) {
 119+ if ( !array_key_exists( $row->Key_name, $indexes ) ) {
 120+ $indexes[$row->Key_name] = array();
 121+ }
 122+ $indexes[$row->Key_name][$row->Seq_in_index] = $row->Column_name;
 123+ }
 124+ foreach ( $indexes as $key => $index ) { // clean up existing indexes
 125+ $id = array_search( implode( ',', $index ), $columns );
 126+ if ( $id !== false ) {
 127+ $columns[$id] = false;
 128+ } else { // duplicate or unrequired index
 129+ if ( $key != 'PRIMARY' ) {
 130+ $db->query( 'DROP INDEX ' . $key . ' ON ' . $table, 'SMW::SetupIndex' );
 131+ }
 132+ }
 133+ }
 134+
 135+ foreach ( $columns as $column ) { // add remaining indexes
 136+ if ( $column != false ) {
 137+ $db->query( "ALTER TABLE $table ADD INDEX ( $column )", 'SMW::SetupIndex' );
 138+ }
 139+ }
 140+ return true;
 141+ }
 142+
 143+ /**
 144+ * Print some output to indicate progress. The output message is given by
 145+ * $msg, while $verbose indicates whether or not output is desired at all.
 146+ */
 147+ public static function reportProgress( $msg, $verbose ) {
 148+ if ( !$verbose ) {
 149+ return;
 150+ }
 151+ if ( ob_get_level() == 0 ) { // be sure to have some buffer, otherwise some PHPs complain
 152+ ob_start();
 153+ }
 154+ print $msg;
 155+ ob_flush();
 156+ flush();
 157+ }
 158+
 159+ /**
 160+ * Transform input parameters into a suitable array of SQL options.
 161+ * The parameter $valuecol defines the string name of the column to which
 162+ * sorting requests etc. are to be applied.
 163+ */
 164+ public static function getSQLOptions( $requestoptions, $valuecol = NULL ) {
 165+ $sql_options = array();
 166+ if ( $requestoptions !== NULL ) {
 167+ if ( is_numeric( $requestoptions->limit ) && $requestoptions->limit >= 0 ) {
 168+ $sql_options['LIMIT'] = $requestoptions->limit;
 169+ }
 170+ if ( is_numeric( $requestoptions->offset ) && $requestoptions->offset > 0 ) {
 171+ $sql_options['OFFSET'] = $requestoptions->offset;
 172+ }
 173+ if ( ( $valuecol !== NULL ) && ( $requestoptions->sort ) ) {
 174+ if ( is_array( $valuecol ) ) {
 175+ $sql_options['ORDER BY'] = $requestoptions->ascending ? mysql_real_escape_string( implode( ",", $valuecol ) ) : mysql_real_escape_string( implode( ",", $valuecol ) ) . ' DESC';
 176+ } else {
 177+ $sql_options['ORDER BY'] = $requestoptions->ascending ? mysql_real_escape_string( $valuecol ) : mysql_real_escape_string( $valuecol ) . ' DESC';
 178+ }
 179+ }
 180+ }
 181+ return $sql_options;
 182+ }
 183+
 184+ public static function getSQLOptionsAsString( $requestoptions, $valuecol = NULL ) {
 185+ $options = SNMDBHelper::getSQLOptions( $requestoptions, $valuecol );
 186+ $limit = array_key_exists( 'LIMIT', $options ) && is_numeric( $options['LIMIT'] ) ? 'LIMIT ' . $options['LIMIT'] : '';
 187+ $offset = array_key_exists( 'OFFSET', $options ) && is_numeric( $options['OFFSET'] ) ? 'OFFSET ' . $options['OFFSET'] : '';
 188+ $orderby = array_key_exists( 'ORDER BY', $options ) ? 'ORDER BY ' . $options['ORDER BY'] : '';
 189+ return $orderby . ' ' . $limit . ' ' . $offset;
 190+ }
 191+
 192+ /**
 193+ * Transform input parameters into a suitable string of additional SQL conditions.
 194+ * The parameter $valuecol defines the string name of the column to which
 195+ * value restrictions etc. are to be applied.
 196+ * @param $requestoptions object with options
 197+ * @param $valuecol name of SQL column to which conditions apply
 198+ * @param $labelcol name of SQL column to which string conditions apply, if any
 199+ */
 200+ public static function getSQLConditions( $requestoptions, $valuecol, $labelcol = NULL ) {
 201+ $sql_conds = '';
 202+ if ( $requestoptions !== NULL ) {
 203+ $db =& wfGetDB( DB_SLAVE ); // TODO: use slave?
 204+ if ( $requestoptions->boundary !== NULL ) { // apply value boundary
 205+ if ( $requestoptions->ascending ) {
 206+ if ( $requestoptions->include_boundary ) {
 207+ $op = ' >= ';
 208+ } else {
 209+ $op = ' > ';
 210+ }
 211+ } else {
 212+ if ( $requestoptions->include_boundary ) {
 213+ $op = ' <= ';
 214+ } else {
 215+ $op = ' < ';
 216+ }
 217+ }
 218+ $sql_conds .= ' AND ' . mysql_real_escape_string( $valuecol ) . $op . $db->addQuotes( $requestoptions->boundary );
 219+ }
 220+ $operator = isset( $requestoptions->disjunctiveStrings ) && $requestoptions->disjunctiveStrings === true ? ' OR ' : ' AND ';
 221+ $neutral = isset( $requestoptions->disjunctiveStrings ) && $requestoptions->disjunctiveStrings === true ? ' FALSE ' : ' TRUE ';
 222+ if ( $labelcol !== NULL ) { // apply string conditions
 223+
 224+ $sql_conds .= ' AND ( ';
 225+
 226+ foreach ( $requestoptions->getStringConditions() as $strcond ) {
 227+ $string = str_replace( array( '_', ' ' ), array( '\_', '\_' ), $strcond->string );
 228+ switch ( $strcond->condition ) {
 229+ case SMWStringCondition::STRCOND_PRE:
 230+ $string .= '%';
 231+ break;
 232+ case SMWStringCondition::STRCOND_POST:
 233+ $string = '%' . $string;
 234+ break;
 235+ case SMWStringCondition::STRCOND_MID:
 236+ $string = '%' . $string . '%';
 237+ break;
 238+ }
 239+ if ( $requestoptions->isCaseSensitive ) {
 240+ $sql_conds .= mysql_real_escape_string( $labelcol ) . ' LIKE ' . $db->addQuotes( $string ) . $operator;
 241+ } else {
 242+ $sql_conds .= ' UPPER(' . mysql_real_escape_string( $labelcol ) . ') LIKE UPPER(' . $db->addQuotes( $string ) . ') ' . $operator;
 243+ }
 244+ }
 245+ $sql_conds .= ' ' . $neutral . ' ) ';
 246+ }
 247+ }
 248+ return $sql_conds;
 249+ }
 250+
 251+ /**
 252+ * Returns sql conditions of $requestoptions in an Array.
 253+ * Warning! Does not support SMWAdvRequestOptions
 254+ *
 255+ * @param SMWRequestOptions $requestoptions
 256+ * @param string $valuecol
 257+ * @param string $labelcol
 258+ * @return array
 259+ */
 260+ public static function getSQLConditionsAsArray( $requestoptions, $valuecol, $labelcol = NULL ) {
 261+ $sql_conds = array();
 262+ if ( $requestoptions !== NULL ) {
 263+ $db =& wfGetDB( DB_SLAVE );
 264+ if ( $requestoptions->boundary !== NULL ) { // apply value boundary
 265+ if ( $requestoptions->ascending ) {
 266+ if ( $requestoptions->include_boundary ) {
 267+ $op = ' >= ';
 268+ } else {
 269+ $op = ' > ';
 270+ }
 271+ } else {
 272+ if ( $requestoptions->include_boundary ) {
 273+ $op = ' <= ';
 274+ } else {
 275+ $op = ' < ';
 276+ }
 277+ }
 278+ $sql_conds[] = mysql_real_escape_string( $valuecol ) . $op . $db->addQuotes( $requestoptions->boundary );
 279+ }
 280+ if ( $labelcol !== NULL ) { // apply string conditions
 281+ foreach ( $requestoptions->getStringConditions() as $strcond ) {
 282+ $string = str_replace( array( '_', ' ' ), array( '\_', '\_' ), $strcond->string );
 283+ switch ( $strcond->condition ) {
 284+ case SMWStringCondition::STRCOND_PRE:
 285+ $string .= '%';
 286+ break;
 287+ case SMWStringCondition::STRCOND_POST:
 288+ $string = '%' . $string;
 289+ break;
 290+ case SMWStringCondition::STRCOND_MID:
 291+ $string = '%' . $string . '%';
 292+ break;
 293+ }
 294+ $sql_conds[] = 'UPPER(' . mysql_real_escape_string( $labelcol ) . ') LIKE UPPER(' . $db->addQuotes( $string ) . ')';
 295+ }
 296+ }
 297+ }
 298+ return $sql_conds;
 299+ }
 300+}
Property changes on: trunk/extensions/SemanticNotifyMe/includes/SMW_NMDBHelper.php
___________________________________________________________________
Name: svn:eol-style
306301 + native
Index: trunk/extensions/SemanticNotifyMe/includes/jobs/SMW_NMRefreshJob.php
@@ -1,18 +1,18 @@
22 <?php
33 /**
4 - * @author dch
 4+ * @author dch
55 */
66
7 -if ( !defined( 'MEDIAWIKI' ) ) {
8 - die( "This file is part of the Semantic NotifyMe Extension. It is not a valid entry point.\n" );
9 -}
10 -global $IP;
11 -require_once( "$IP/includes/JobQueue.php" );
12 -
 7+if ( !defined( 'MEDIAWIKI' ) ) {
 8+ die( "This file is part of the Semantic NotifyMe Extension. It is not a valid entry point.\n" );
 9+}
 10+global $IP;
 11+require_once( "$IP/includes/JobQueue.php" );
 12+
1313 class SMWNMRefreshJob extends Job {
1414
15 - function __construct(Title $title) {
16 - parent::__construct( 'SMWNMRefreshJob', $title);
 15+ function __construct( Title $title ) {
 16+ parent::__construct( 'SMWNMRefreshJob', $title );
1717 }
1818
1919 /**
@@ -20,9 +20,9 @@
2121 * @return boolean success
2222 */
2323 function run() {
24 - wfProfileIn('SMWNMRefreshJob::run (SMW)');
25 - SMWNotifyProcessor::refreshNotifyMe();
26 - wfProfileOut('SMWNMRefreshJob::run (SMW)');
 24+ wfProfileIn( 'SMWNMRefreshJob::run (SMW)' );
 25+ SMWNotifyProcessor::refreshNotifyMe();
 26+ wfProfileOut( 'SMWNMRefreshJob::run (SMW)' );
2727 return true;
2828 }
2929
@@ -34,7 +34,7 @@
3535 */
3636 function insert() {
3737 global $smwgEnableUpdateJobs;
38 - if ($smwgEnableUpdateJobs) {
 38+ if ( $smwgEnableUpdateJobs ) {
3939 parent::insert();
4040 }
4141 }
Property changes on: trunk/extensions/SemanticNotifyMe/includes/jobs/SMW_NMRefreshJob.php
___________________________________________________________________
Name: svn:eol-style
4242 + native
Index: trunk/extensions/SemanticNotifyMe/includes/jobs/SMW_NMSendMailJob.php
@@ -1,52 +1,50 @@
2 -<?php
3 -/*
4 - * SMW_NMSendMailJob.php
5 - *
6 - * This job is triggered whenever a notify-me page was saved or removed.
7 - *
8 - * @author dch
9 - *
10 - */
11 -if ( !defined( 'MEDIAWIKI' ) ) {
12 - die( "This file is part of the Semantic NotifyMe Extension. It is not a valid entry point.\n" );
13 -}
14 -global $IP;
15 -require_once( "$IP/includes/JobQueue.php" );
16 -
17 -
18 -class SMW_NMSendMailJob extends Job {
19 -
20 - /**
21 - * Creates a NMSendMailJob
22 - *
23 - * @param Title $title
24 - */
25 - function __construct($title, $params) {
26 - wfDebug(__METHOD__." ".get_class($this)." \r\n");
27 - wfProfileIn( __METHOD__ );
28 - parent::__construct( get_class($this), Title::newMainPage(), $params);
29 -
30 - wfProfileOut( __METHOD__ );
31 - }
32 -
33 - /**
34 - * Run a SMW_NMSendMailJob job
35 - * @return boolean success
36 - */
37 - function run() {
38 - wfDebug(__METHOD__);
39 - wfProfileIn( __METHOD__ );
40 -
41 - UserMailer::send( //userMailer(
42 - $this->params['to'],
43 - $this->params['from'],
44 - $this->params['subj'],
45 - $this->params['body'],
46 - $this->params['replyto']
47 - );
48 -
49 - wfProfileOut( __METHOD__ );
50 - return true;
51 - }
52 -}
53 -?>
 2+<?php
 3+/*
 4+ * SMW_NMSendMailJob.php
 5+ *
 6+ * This job is triggered whenever a notify-me page was saved or removed.
 7+ *
 8+ * @author dch
 9+ *
 10+ */
 11+if ( !defined( 'MEDIAWIKI' ) ) {
 12+ die( "This file is part of the Semantic NotifyMe Extension. It is not a valid entry point.\n" );
 13+}
 14+global $IP;
 15+require_once( "$IP/includes/JobQueue.php" );
 16+
 17+class SMW_NMSendMailJob extends Job {
 18+
 19+ /**
 20+ * Creates a NMSendMailJob
 21+ *
 22+ * @param Title $title
 23+ */
 24+ function __construct( $title, $params ) {
 25+ wfDebug( __METHOD__ . " " . get_class( $this ) . " \r\n" );
 26+ wfProfileIn( __METHOD__ );
 27+ parent::__construct( get_class( $this ), Title::newMainPage(), $params );
 28+
 29+ wfProfileOut( __METHOD__ );
 30+ }
 31+
 32+ /**
 33+ * Run a SMW_NMSendMailJob job
 34+ * @return boolean success
 35+ */
 36+ function run() {
 37+ wfDebug( __METHOD__ );
 38+ wfProfileIn( __METHOD__ );
 39+
 40+ UserMailer::send( // userMailer(
 41+ $this->params['to'],
 42+ $this->params['from'],
 43+ $this->params['subj'],
 44+ $this->params['body'],
 45+ $this->params['replyto']
 46+ );
 47+
 48+ wfProfileOut( __METHOD__ );
 49+ return true;
 50+ }
 51+}
Property changes on: trunk/extensions/SemanticNotifyMe/includes/jobs/SMW_NMSendMailJob.php
___________________________________________________________________
Name: svn:eol-style
5452 + native
Index: trunk/extensions/SemanticNotifyMe/languages/SMW_NMLanguage.php
@@ -1,138 +1,133 @@
2 -<?php
3 -/**
4 - * @author dch
5 - */
6 -
7 -/**
8 - * Base class for all language classes.
9 - */
10 -abstract class SMW_NMLanguage {
11 -
12 - // the message arrays ...
13 - protected $smwContentMessages;
14 - protected $smwUserMessages;
15 - protected $smwDatatypeLabels;
16 - protected $smwSpecialProperties;
17 - protected $smwSpecialSchemaProperties;
18 - protected $smwNMDatatypes;
19 - protected $smwNMNamespaces;
20 - protected $smwNMNamespaceAliases;
21 -
22 - /**
23 - * Function that returns an array of namespace identifiers. This function
24 - * is obsolete
25 - */
26 - abstract function getNamespaceArray();
27 -
28 -
29 - /**
30 - * Find the internal message id of some localised message string
31 - * for a datatype. If no type of the given name exists (maybe a
32 - * custom of compound type) then FALSE is returned.
33 - */
34 - function findDatatypeMsgID($label) {
35 - return array_search($label, $this->smwDatatypeLabels);
36 - }
37 -
38 - /**
39 - * Registers all special properties of this extension in Semantic Media Wiki.
40 - *
41 - * The language files of the NM extension contain a mapping from special
42 - * property constants to their string representation. These mappings are
43 - * added to the mapping defined by Semantic Media Wiki.
44 - */
45 - function registerSpecialProperties() {
46 - global $smwgContLang;
47 - foreach ($this->smwSpecialProperties as $key => $prop) {
48 - list($typeid, $label) = $prop;
49 - SMWPropertyValue::registerProperty($key, $typeid, $label, true);
50 -
51 - }
52 - }
53 -
54 - /**
55 - * Returns the label of the special property with the ID $propID.
56 - * @param int propID
57 - * ID of the special property
58 - * @return String Label of the special property
59 - */
60 - function getSpecialPropertyLabel($propID) {
61 - return $this->smwSpecialProperties[$propID];
62 - }
63 -
64 - /**
65 - * Returns all labels of the special properties.
66 - * @return array<String> Labels of the special properties
67 - */
68 - function getSpecialPropertyLabels() {
69 - return $this->smwSpecialProperties;
70 - }
71 -
72 - function getSpecialSchemaPropertyArray() {
73 - return $this->smwSpecialSchemaProperties;
74 - }
75 -
76 - function getSpecialCategoryArray() {
77 - return $this->smwSpecialCategories;
78 - }
79 -
80 - function getNMDatatype($datatypeID) {
81 - return $this->smwNMDatatypes[$datatypeID];
82 - }
83 -
84 - /**
85 - * Function that returns all content messages (those that are stored
86 - * in some article, and can thus not be translated to individual users).
87 - */
88 - function getContentMsgArray() {
89 - return $this->smwContentMessages;
90 - }
91 -
92 - /**
93 - * Function that returns all user messages (those that are given only to
94 - * the current user, and can thus be given in the individual user language).
95 - */
96 - function getUserMsgArray() {
97 - return $this->smwUserMessages;
98 - }
99 -
100 - /**
101 - * Returns the name of the namespace with the ID <$namespaceID>.
102 - *
103 - * @param int $namespaceID
104 - * ID of the namespace whose name is requested
105 - * @return string
106 - * Name of the namespace or <null>.
107 - *
108 - */
109 - public function getNamespace($namespaceID) {
110 - return $this->smwNMNamespaces[$namespaceID];
111 - }
112 -
113 - /**
114 - * Returns the array with all namespaces of the NM extension.
115 - *
116 - * @return string
117 - * Array of additional namespaces.
118 - *
119 - */
120 - public function getNamespaces() {
121 - return $this->smwNMNamespaces;
122 - }
123 -
124 - /**
125 - * Returns the array with all namespace aliases of the NM extension.
126 - *
127 - * @return string
128 - * Array of additional namespace aliases.
129 - *
130 - */
131 - public function getNamespaceAliases() {
132 - return $this->smwNMNamespaceAliases;
133 - }
134 -
135 -
136 -
137 -}
138 -
139 -
 2+<?php
 3+/**
 4+ * @author dch
 5+ */
 6+
 7+/**
 8+ * Base class for all language classes.
 9+ */
 10+abstract class SMW_NMLanguage {
 11+
 12+ // the message arrays ...
 13+ protected $smwContentMessages;
 14+ protected $smwUserMessages;
 15+ protected $smwDatatypeLabels;
 16+ protected $smwSpecialProperties;
 17+ protected $smwSpecialSchemaProperties;
 18+ protected $smwNMDatatypes;
 19+ protected $smwNMNamespaces;
 20+ protected $smwNMNamespaceAliases;
 21+
 22+ /**
 23+ * Function that returns an array of namespace identifiers. This function
 24+ * is obsolete
 25+ */
 26+ abstract function getNamespaceArray();
 27+
 28+
 29+ /**
 30+ * Find the internal message id of some localised message string
 31+ * for a datatype. If no type of the given name exists (maybe a
 32+ * custom of compound type) then FALSE is returned.
 33+ */
 34+ function findDatatypeMsgID( $label ) {
 35+ return array_search( $label, $this->smwDatatypeLabels );
 36+ }
 37+
 38+ /**
 39+ * Registers all special properties of this extension in Semantic Media Wiki.
 40+ *
 41+ * The language files of the NM extension contain a mapping from special
 42+ * property constants to their string representation. These mappings are
 43+ * added to the mapping defined by Semantic Media Wiki.
 44+ */
 45+ function registerSpecialProperties() {
 46+ global $smwgContLang;
 47+ foreach ( $this->smwSpecialProperties as $key => $prop ) {
 48+ list( $typeid, $label ) = $prop;
 49+ SMWPropertyValue::registerProperty( $key, $typeid, $label, true );
 50+
 51+ }
 52+ }
 53+
 54+ /**
 55+ * Returns the label of the special property with the ID $propID.
 56+ * @param int propID
 57+ * ID of the special property
 58+ * @return String Label of the special property
 59+ */
 60+ function getSpecialPropertyLabel( $propID ) {
 61+ return $this->smwSpecialProperties[$propID];
 62+ }
 63+
 64+ /**
 65+ * Returns all labels of the special properties.
 66+ * @return array<String> Labels of the special properties
 67+ */
 68+ function getSpecialPropertyLabels() {
 69+ return $this->smwSpecialProperties;
 70+ }
 71+
 72+ function getSpecialSchemaPropertyArray() {
 73+ return $this->smwSpecialSchemaProperties;
 74+ }
 75+
 76+ function getSpecialCategoryArray() {
 77+ return $this->smwSpecialCategories;
 78+ }
 79+
 80+ function getNMDatatype( $datatypeID ) {
 81+ return $this->smwNMDatatypes[$datatypeID];
 82+ }
 83+
 84+ /**
 85+ * Function that returns all content messages (those that are stored
 86+ * in some article, and can thus not be translated to individual users).
 87+ */
 88+ function getContentMsgArray() {
 89+ return $this->smwContentMessages;
 90+ }
 91+
 92+ /**
 93+ * Function that returns all user messages (those that are given only to
 94+ * the current user, and can thus be given in the individual user language).
 95+ */
 96+ function getUserMsgArray() {
 97+ return $this->smwUserMessages;
 98+ }
 99+
 100+ /**
 101+ * Returns the name of the namespace with the ID <$namespaceID>.
 102+ *
 103+ * @param int $namespaceID
 104+ * ID of the namespace whose name is requested
 105+ * @return string
 106+ * Name of the namespace or <null>.
 107+ *
 108+ */
 109+ public function getNamespace( $namespaceID ) {
 110+ return $this->smwNMNamespaces[$namespaceID];
 111+ }
 112+
 113+ /**
 114+ * Returns the array with all namespaces of the NM extension.
 115+ *
 116+ * @return string
 117+ * Array of additional namespaces.
 118+ *
 119+ */
 120+ public function getNamespaces() {
 121+ return $this->smwNMNamespaces;
 122+ }
 123+
 124+ /**
 125+ * Returns the array with all namespace aliases of the NM extension.
 126+ *
 127+ * @return string
 128+ * Array of additional namespace aliases.
 129+ *
 130+ */
 131+ public function getNamespaceAliases() {
 132+ return $this->smwNMNamespaceAliases;
 133+ }
 134+}
Property changes on: trunk/extensions/SemanticNotifyMe/languages/SMW_NMLanguage.php
___________________________________________________________________
Name: svn:eol-style
140135 + native
Index: trunk/extensions/SemanticNotifyMe/languages/SMW_NMLanguageEn.php
@@ -1,59 +1,53 @@
2 -<?php
3 -/**
4 - * @author dch
5 - */
6 -
7 -global $smwgNMIP;
8 -include_once($smwgNMIP . '/languages/SMW_NMLanguage.php');
9 -
10 -class SMW_NMLanguageEn extends SMW_NMLanguage {
11 -
12 - protected $smwContentMessages = array(
13 -
14 - );
15 -
16 -
17 - protected $smwUserMessages = array(
18 - /*Messages for Notify Me*/
19 - 'notifyme' => 'Notify Me',
20 - 'smw_notifyme' => 'Notify Me',
21 -
22 - 'smw_qi_addNotify' => 'Notify me',
23 - 'smw_qi_tt_addNotify' => 'Notify me when article-updates meet query condition',
24 - 'smw_nm_tt_query' => 'Add #ask query to Notify Me',
25 - 'smw_nm_tt_qtext' => 'Support query in {{#ask syntax',
26 - 'smw_nm_tt_nmm' => 'Notify Me Manager enable you to control your notifications',
27 - 'smw_nm_tt_clipboard' => 'Copies your RSS Feed URL to the clipboard so it can easily be inserted into any RSS reader',
28 - );
29 -
30 -
31 - protected $smwSpecialProperties = array(
32 - );
33 -
34 -
35 - var $smwSpecialSchemaProperties = array (
36 - );
37 -
38 - var $smwSpecialCategories = array (
39 - );
40 -
41 - var $smwNMDatatypes = array(
42 - );
43 -
44 - protected $smwNMNamespaces = array(
45 - );
46 -
47 - protected $smwNMNamespaceAliases = array(
48 - );
49 -
50 - /**
51 - * Function that returns the namespace identifiers. This is probably obsolete!
52 - */
53 - public function getNamespaceArray() {
54 - return array();
55 - }
56 -
57 -
58 -}
59 -
60 -
 2+<?php
 3+/**
 4+ * @author dch
 5+ */
 6+
 7+global $smwgNMIP;
 8+include_once( $smwgNMIP . '/languages/SMW_NMLanguage.php' );
 9+
 10+class SMW_NMLanguageEn extends SMW_NMLanguage {
 11+ protected $smwContentMessages = array(
 12+
 13+ );
 14+
 15+ protected $smwUserMessages = array(
 16+ /*Messages for Notify Me*/
 17+ 'notifyme' => 'Notify Me',
 18+ 'smw_notifyme' => 'Notify Me',
 19+
 20+ 'smw_qi_addNotify' => 'Notify me',
 21+ 'smw_qi_tt_addNotify' => 'Notify me when article-updates meet query condition',
 22+ 'smw_nm_tt_query' => 'Add #ask query to Notify Me',
 23+ 'smw_nm_tt_qtext' => 'Support query in {{#ask syntax',
 24+ 'smw_nm_tt_nmm' => 'Notify Me Manager enable you to control your notifications',
 25+ 'smw_nm_tt_clipboard' => 'Copies your RSS Feed URL to the clipboard so it can easily be inserted into any RSS reader',
 26+ );
 27+
 28+
 29+ protected $smwSpecialProperties = array(
 30+ );
 31+
 32+
 33+ var $smwSpecialSchemaProperties = array (
 34+ );
 35+
 36+ var $smwSpecialCategories = array (
 37+ );
 38+
 39+ var $smwNMDatatypes = array(
 40+ );
 41+
 42+ protected $smwNMNamespaces = array(
 43+ );
 44+
 45+ protected $smwNMNamespaceAliases = array(
 46+ );
 47+
 48+ /**
 49+ * Function that returns the namespace identifiers. This is probably obsolete!
 50+ */
 51+ public function getNamespaceArray() {
 52+ return array();
 53+ }
 54+}
Property changes on: trunk/extensions/SemanticNotifyMe/languages/SMW_NMLanguageEn.php
___________________________________________________________________
Name: svn:eol-style
6155 + native
Index: trunk/extensions/SemanticNotifyMe/COPYING
@@ -1,348 +1,348 @@
2 -The license text below "----" applies to all files within this distribution, other
3 -than those that are in a directory which contains files named "LICENSE" or
4 -"COPYING", or a subdirectory thereof. For those files, the license text contained in
5 -said file overrides any license information contained in directories of smaller depth.
6 -Alternative licenses are typically used for software that is provided by external
7 -parties, and merely packaged with the Semantic MediaWiki release for convenience.
8 -
9 - GNU GENERAL PUBLIC LICENSE
10 - Version 2, June 1991
11 -
12 - Copyright (C) 1989, 1991 Free Software Foundation, Inc.
13 - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 - Everyone is permitted to copy and distribute verbatim copies
15 - of this license document, but changing it is not allowed.
16 -
17 - Preamble
18 -
19 - The licenses for most software are designed to take away your
20 -freedom to share and change it. By contrast, the GNU General Public
21 -License is intended to guarantee your freedom to share and change free
22 -software--to make sure the software is free for all its users. This
23 -General Public License applies to most of the Free Software
24 -Foundation's software and to any other program whose authors commit to
25 -using it. (Some other Free Software Foundation software is covered by
26 -the GNU Library General Public License instead.) You can apply it to
27 -your programs, too.
28 -
29 - When we speak of free software, we are referring to freedom, not
30 -price. Our General Public Licenses are designed to make sure that you
31 -have the freedom to distribute copies of free software (and charge for
32 -this service if you wish), that you receive source code or can get it
33 -if you want it, that you can change the software or use pieces of it
34 -in new free programs; and that you know you can do these things.
35 -
36 - To protect your rights, we need to make restrictions that forbid
37 -anyone to deny you these rights or to ask you to surrender the rights.
38 -These restrictions translate to certain responsibilities for you if you
39 -distribute copies of the software, or if you modify it.
40 -
41 - For example, if you distribute copies of such a program, whether
42 -gratis or for a fee, you must give the recipients all the rights that
43 -you have. You must make sure that they, too, receive or can get the
44 -source code. And you must show them these terms so they know their
45 -rights.
46 -
47 - We protect your rights with two steps: (1) copyright the software, and
48 -(2) offer you this license which gives you legal permission to copy,
49 -distribute and/or modify the software.
50 -
51 - Also, for each author's protection and ours, we want to make certain
52 -that everyone understands that there is no warranty for this free
53 -software. If the software is modified by someone else and passed on, we
54 -want its recipients to know that what they have is not the original, so
55 -that any problems introduced by others will not reflect on the original
56 -authors' reputations.
57 -
58 - Finally, any free program is threatened constantly by software
59 -patents. We wish to avoid the danger that redistributors of a free
60 -program will individually obtain patent licenses, in effect making the
61 -program proprietary. To prevent this, we have made it clear that any
62 -patent must be licensed for everyone's free use or not licensed at all.
63 -
64 - The precise terms and conditions for copying, distribution and
65 -modification follow.
66 -
67 - GNU GENERAL PUBLIC LICENSE
68 - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
69 -
70 - 0. This License applies to any program or other work which contains
71 -a notice placed by the copyright holder saying it may be distributed
72 -under the terms of this General Public License. The "Program", below,
73 -refers to any such program or work, and a "work based on the Program"
74 -means either the Program or any derivative work under copyright law:
75 -that is to say, a work containing the Program or a portion of it,
76 -either verbatim or with modifications and/or translated into another
77 -language. (Hereinafter, translation is included without limitation in
78 -the term "modification".) Each licensee is addressed as "you".
79 -
80 -Activities other than copying, distribution and modification are not
81 -covered by this License; they are outside its scope. The act of
82 -running the Program is not restricted, and the output from the Program
83 -is covered only if its contents constitute a work based on the
84 -Program (independent of having been made by running the Program).
85 -Whether that is true depends on what the Program does.
86 -
87 - 1. You may copy and distribute verbatim copies of the Program's
88 -source code as you receive it, in any medium, provided that you
89 -conspicuously and appropriately publish on each copy an appropriate
90 -copyright notice and disclaimer of warranty; keep intact all the
91 -notices that refer to this License and to the absence of any warranty;
92 -and give any other recipients of the Program a copy of this License
93 -along with the Program.
94 -
95 -You may charge a fee for the physical act of transferring a copy, and
96 -you may at your option offer warranty protection in exchange for a fee.
97 -
98 - 2. You may modify your copy or copies of the Program or any portion
99 -of it, thus forming a work based on the Program, and copy and
100 -distribute such modifications or work under the terms of Section 1
101 -above, provided that you also meet all of these conditions:
102 -
103 - a) You must cause the modified files to carry prominent notices
104 - stating that you changed the files and the date of any change.
105 -
106 - b) You must cause any work that you distribute or publish, that in
107 - whole or in part contains or is derived from the Program or any
108 - part thereof, to be licensed as a whole at no charge to all third
109 - parties under the terms of this License.
110 -
111 - c) If the modified program normally reads commands interactively
112 - when run, you must cause it, when started running for such
113 - interactive use in the most ordinary way, to print or display an
114 - announcement including an appropriate copyright notice and a
115 - notice that there is no warranty (or else, saying that you provide
116 - a warranty) and that users may redistribute the program under
117 - these conditions, and telling the user how to view a copy of this
118 - License. (Exception: if the Program itself is interactive but
119 - does not normally print such an announcement, your work based on
120 - the Program is not required to print an announcement.)
121 -
122 -These requirements apply to the modified work as a whole. If
123 -identifiable sections of that work are not derived from the Program,
124 -and can be reasonably considered independent and separate works in
125 -themselves, then this License, and its terms, do not apply to those
126 -sections when you distribute them as separate works. But when you
127 -distribute the same sections as part of a whole which is a work based
128 -on the Program, the distribution of the whole must be on the terms of
129 -this License, whose permissions for other licensees extend to the
130 -entire whole, and thus to each and every part regardless of who wrote it.
131 -
132 -Thus, it is not the intent of this section to claim rights or contest
133 -your rights to work written entirely by you; rather, the intent is to
134 -exercise the right to control the distribution of derivative or
135 -collective works based on the Program.
136 -
137 -In addition, mere aggregation of another work not based on the Program
138 -with the Program (or with a work based on the Program) on a volume of
139 -a storage or distribution medium does not bring the other work under
140 -the scope of this License.
141 -
142 - 3. You may copy and distribute the Program (or a work based on it,
143 -under Section 2) in object code or executable form under the terms of
144 -Sections 1 and 2 above provided that you also do one of the following:
145 -
146 - a) Accompany it with the complete corresponding machine-readable
147 - source code, which must be distributed under the terms of Sections
148 - 1 and 2 above on a medium customarily used for software interchange; or,
149 -
150 - b) Accompany it with a written offer, valid for at least three
151 - years, to give any third party, for a charge no more than your
152 - cost of physically performing source distribution, a complete
153 - machine-readable copy of the corresponding source code, to be
154 - distributed under the terms of Sections 1 and 2 above on a medium
155 - customarily used for software interchange; or,
156 -
157 - c) Accompany it with the information you received as to the offer
158 - to distribute corresponding source code. (This alternative is
159 - allowed only for noncommercial distribution and only if you
160 - received the program in object code or executable form with such
161 - an offer, in accord with Subsection b above.)
162 -
163 -The source code for a work means the preferred form of the work for
164 -making modifications to it. For an executable work, complete source
165 -code means all the source code for all modules it contains, plus any
166 -associated interface definition files, plus the scripts used to
167 -control compilation and installation of the executable. However, as a
168 -special exception, the source code distributed need not include
169 -anything that is normally distributed (in either source or binary
170 -form) with the major components (compiler, kernel, and so on) of the
171 -operating system on which the executable runs, unless that component
172 -itself accompanies the executable.
173 -
174 -If distribution of executable or object code is made by offering
175 -access to copy from a designated place, then offering equivalent
176 -access to copy the source code from the same place counts as
177 -distribution of the source code, even though third parties are not
178 -compelled to copy the source along with the object code.
179 -
180 - 4. You may not copy, modify, sublicense, or distribute the Program
181 -except as expressly provided under this License. Any attempt
182 -otherwise to copy, modify, sublicense or distribute the Program is
183 -void, and will automatically terminate your rights under this License.
184 -However, parties who have received copies, or rights, from you under
185 -this License will not have their licenses terminated so long as such
186 -parties remain in full compliance.
187 -
188 - 5. You are not required to accept this License, since you have not
189 -signed it. However, nothing else grants you permission to modify or
190 -distribute the Program or its derivative works. These actions are
191 -prohibited by law if you do not accept this License. Therefore, by
192 -modifying or distributing the Program (or any work based on the
193 -Program), you indicate your acceptance of this License to do so, and
194 -all its terms and conditions for copying, distributing or modifying
195 -the Program or works based on it.
196 -
197 - 6. Each time you redistribute the Program (or any work based on the
198 -Program), the recipient automatically receives a license from the
199 -original licensor to copy, distribute or modify the Program subject to
200 -these terms and conditions. You may not impose any further
201 -restrictions on the recipients' exercise of the rights granted herein.
202 -You are not responsible for enforcing compliance by third parties to
203 -this License.
204 -
205 - 7. If, as a consequence of a court judgment or allegation of patent
206 -infringement or for any other reason (not limited to patent issues),
207 -conditions are imposed on you (whether by court order, agreement or
208 -otherwise) that contradict the conditions of this License, they do not
209 -excuse you from the conditions of this License. If you cannot
210 -distribute so as to satisfy simultaneously your obligations under this
211 -License and any other pertinent obligations, then as a consequence you
212 -may not distribute the Program at all. For example, if a patent
213 -license would not permit royalty-free redistribution of the Program by
214 -all those who receive copies directly or indirectly through you, then
215 -the only way you could satisfy both it and this License would be to
216 -refrain entirely from distribution of the Program.
217 -
218 -If any portion of this section is held invalid or unenforceable under
219 -any particular circumstance, the balance of the section is intended to
220 -apply and the section as a whole is intended to apply in other
221 -circumstances.
222 -
223 -It is not the purpose of this section to induce you to infringe any
224 -patents or other property right claims or to contest validity of any
225 -such claims; this section has the sole purpose of protecting the
226 -integrity of the free software distribution system, which is
227 -implemented by public license practices. Many people have made
228 -generous contributions to the wide range of software distributed
229 -through that system in reliance on consistent application of that
230 -system; it is up to the author/donor to decide if he or she is willing
231 -to distribute software through any other system and a licensee cannot
232 -impose that choice.
233 -
234 -This section is intended to make thoroughly clear what is believed to
235 -be a consequence of the rest of this License.
236 -
237 - 8. If the distribution and/or use of the Program is restricted in
238 -certain countries either by patents or by copyrighted interfaces, the
239 -original copyright holder who places the Program under this License
240 -may add an explicit geographical distribution limitation excluding
241 -those countries, so that distribution is permitted only in or among
242 -countries not thus excluded. In such case, this License incorporates
243 -the limitation as if written in the body of this License.
244 -
245 - 9. The Free Software Foundation may publish revised and/or new versions
246 -of the General Public License from time to time. Such new versions will
247 -be similar in spirit to the present version, but may differ in detail to
248 -address new problems or concerns.
249 -
250 -Each version is given a distinguishing version number. If the Program
251 -specifies a version number of this License which applies to it and "any
252 -later version", you have the option of following the terms and conditions
253 -either of that version or of any later version published by the Free
254 -Software Foundation. If the Program does not specify a version number of
255 -this License, you may choose any version ever published by the Free Software
256 -Foundation.
257 -
258 - 10. If you wish to incorporate parts of the Program into other free
259 -programs whose distribution conditions are different, write to the author
260 -to ask for permission. For software which is copyrighted by the Free
261 -Software Foundation, write to the Free Software Foundation; we sometimes
262 -make exceptions for this. Our decision will be guided by the two goals
263 -of preserving the free status of all derivatives of our free software and
264 -of promoting the sharing and reuse of software generally.
265 -
266 - NO WARRANTY
267 -
268 - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
269 -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
270 -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
271 -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
272 -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
273 -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
274 -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
275 -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
276 -REPAIR OR CORRECTION.
277 -
278 - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
279 -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
280 -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
281 -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
282 -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
283 -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
284 -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
285 -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
286 -POSSIBILITY OF SUCH DAMAGES.
287 -
288 - END OF TERMS AND CONDITIONS
289 -
290 - How to Apply These Terms to Your New Programs
291 -
292 - If you develop a new program, and you want it to be of the greatest
293 -possible use to the public, the best way to achieve this is to make it
294 -free software which everyone can redistribute and change under these terms.
295 -
296 - To do so, attach the following notices to the program. It is safest
297 -to attach them to the start of each source file to most effectively
298 -convey the exclusion of warranty; and each file should have at least
299 -the "copyright" line and a pointer to where the full notice is found.
300 -
301 - <one line to give the program's name and a brief idea of what it does.>
302 - Copyright (C) <year> <name of author>
303 -
304 - This program is free software; you can redistribute it and/or modify
305 - it under the terms of the GNU General Public License as published by
306 - the Free Software Foundation; either version 2 of the License, or
307 - (at your option) any later version.
308 -
309 - This program is distributed in the hope that it will be useful,
310 - but WITHOUT ANY WARRANTY; without even the implied warranty of
311 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
312 - GNU General Public License for more details.
313 -
314 - You should have received a copy of the GNU General Public License
315 - along with this program; if not, write to the Free Software
316 - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
317 -
318 -
319 -Also add information on how to contact you by electronic and paper mail.
320 -
321 -If the program is interactive, make it output a short notice like this
322 -when it starts in an interactive mode:
323 -
324 - Gnomovision version 69, Copyright (C) year name of author
325 - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
326 - This is free software, and you are welcome to redistribute it
327 - under certain conditions; type `show c' for details.
328 -
329 -The hypothetical commands `show w' and `show c' should show the appropriate
330 -parts of the General Public License. Of course, the commands you use may
331 -be called something other than `show w' and `show c'; they could even be
332 -mouse-clicks or menu items--whatever suits your program.
333 -
334 -You should also get your employer (if you work as a programmer) or your
335 -school, if any, to sign a "copyright disclaimer" for the program, if
336 -necessary. Here is a sample; alter the names:
337 -
338 - Yoyodyne, Inc., hereby disclaims all copyright interest in the program
339 - `Gnomovision' (which makes passes at compilers) written by James Hacker.
340 -
341 - <signature of Ty Coon>, 1 April 1989
342 - Ty Coon, President of Vice
343 -
344 -This General Public License does not permit incorporating your program into
345 -proprietary programs. If your program is a subroutine library, you may
346 -consider it more useful to permit linking proprietary applications with the
347 -library. If this is what you want to do, use the GNU Library General
348 -Public License instead of this License.
 2+The license text below "----" applies to all files within this distribution, other
 3+than those that are in a directory which contains files named "LICENSE" or
 4+"COPYING", or a subdirectory thereof. For those files, the license text contained in
 5+said file overrides any license information contained in directories of smaller depth.
 6+Alternative licenses are typically used for software that is provided by external
 7+parties, and merely packaged with the Semantic MediaWiki release for convenience.
 8+----
 9+
 10+ GNU GENERAL PUBLIC LICENSE
 11+ Version 2, June 1991
 12+
 13+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 14+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 15+ Everyone is permitted to copy and distribute verbatim copies
 16+ of this license document, but changing it is not allowed.
 17+
 18+ Preamble
 19+
 20+ The licenses for most software are designed to take away your
 21+freedom to share and change it. By contrast, the GNU General Public
 22+License is intended to guarantee your freedom to share and change free
 23+software--to make sure the software is free for all its users. This
 24+General Public License applies to most of the Free Software
 25+Foundation's software and to any other program whose authors commit to
 26+using it. (Some other Free Software Foundation software is covered by
 27+the GNU Library General Public License instead.) You can apply it to
 28+your programs, too.
 29+
 30+ When we speak of free software, we are referring to freedom, not
 31+price. Our General Public Licenses are designed to make sure that you
 32+have the freedom to distribute copies of free software (and charge for
 33+this service if you wish), that you receive source code or can get it
 34+if you want it, that you can change the software or use pieces of it
 35+in new free programs; and that you know you can do these things.
 36+
 37+ To protect your rights, we need to make restrictions that forbid
 38+anyone to deny you these rights or to ask you to surrender the rights.
 39+These restrictions translate to certain responsibilities for you if you
 40+distribute copies of the software, or if you modify it.
 41+
 42+ For example, if you distribute copies of such a program, whether
 43+gratis or for a fee, you must give the recipients all the rights that
 44+you have. You must make sure that they, too, receive or can get the
 45+source code. And you must show them these terms so they know their
 46+rights.
 47+
 48+ We protect your rights with two steps: (1) copyright the software, and
 49+(2) offer you this license which gives you legal permission to copy,
 50+distribute and/or modify the software.
 51+
 52+ Also, for each author's protection and ours, we want to make certain
 53+that everyone understands that there is no warranty for this free
 54+software. If the software is modified by someone else and passed on, we
 55+want its recipients to know that what they have is not the original, so
 56+that any problems introduced by others will not reflect on the original
 57+authors' reputations.
 58+
 59+ Finally, any free program is threatened constantly by software
 60+patents. We wish to avoid the danger that redistributors of a free
 61+program will individually obtain patent licenses, in effect making the
 62+program proprietary. To prevent this, we have made it clear that any
 63+patent must be licensed for everyone's free use or not licensed at all.
 64+
 65+ The precise terms and conditions for copying, distribution and
 66+modification follow.
 67+
 68+ GNU GENERAL PUBLIC LICENSE
 69+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 70+
 71+ 0. This License applies to any program or other work which contains
 72+a notice placed by the copyright holder saying it may be distributed
 73+under the terms of this General Public License. The "Program", below,
 74+refers to any such program or work, and a "work based on the Program"
 75+means either the Program or any derivative work under copyright law:
 76+that is to say, a work containing the Program or a portion of it,
 77+either verbatim or with modifications and/or translated into another
 78+language. (Hereinafter, translation is included without limitation in
 79+the term "modification".) Each licensee is addressed as "you".
 80+
 81+Activities other than copying, distribution and modification are not
 82+covered by this License; they are outside its scope. The act of
 83+running the Program is not restricted, and the output from the Program
 84+is covered only if its contents constitute a work based on the
 85+Program (independent of having been made by running the Program).
 86+Whether that is true depends on what the Program does.
 87+
 88+ 1. You may copy and distribute verbatim copies of the Program's
 89+source code as you receive it, in any medium, provided that you
 90+conspicuously and appropriately publish on each copy an appropriate
 91+copyright notice and disclaimer of warranty; keep intact all the
 92+notices that refer to this License and to the absence of any warranty;
 93+and give any other recipients of the Program a copy of this License
 94+along with the Program.
 95+
 96+You may charge a fee for the physical act of transferring a copy, and
 97+you may at your option offer warranty protection in exchange for a fee.
 98+
 99+ 2. You may modify your copy or copies of the Program or any portion
 100+of it, thus forming a work based on the Program, and copy and
 101+distribute such modifications or work under the terms of Section 1
 102+above, provided that you also meet all of these conditions:
 103+
 104+ a) You must cause the modified files to carry prominent notices
 105+ stating that you changed the files and the date of any change.
 106+
 107+ b) You must cause any work that you distribute or publish, that in
 108+ whole or in part contains or is derived from the Program or any
 109+ part thereof, to be licensed as a whole at no charge to all third
 110+ parties under the terms of this License.
 111+
 112+ c) If the modified program normally reads commands interactively
 113+ when run, you must cause it, when started running for such
 114+ interactive use in the most ordinary way, to print or display an
 115+ announcement including an appropriate copyright notice and a
 116+ notice that there is no warranty (or else, saying that you provide
 117+ a warranty) and that users may redistribute the program under
 118+ these conditions, and telling the user how to view a copy of this
 119+ License. (Exception: if the Program itself is interactive but
 120+ does not normally print such an announcement, your work based on
 121+ the Program is not required to print an announcement.)
 122+
 123+These requirements apply to the modified work as a whole. If
 124+identifiable sections of that work are not derived from the Program,
 125+and can be reasonably considered independent and separate works in
 126+themselves, then this License, and its terms, do not apply to those
 127+sections when you distribute them as separate works. But when you
 128+distribute the same sections as part of a whole which is a work based
 129+on the Program, the distribution of the whole must be on the terms of
 130+this License, whose permissions for other licensees extend to the
 131+entire whole, and thus to each and every part regardless of who wrote it.
 132+
 133+Thus, it is not the intent of this section to claim rights or contest
 134+your rights to work written entirely by you; rather, the intent is to
 135+exercise the right to control the distribution of derivative or
 136+collective works based on the Program.
 137+
 138+In addition, mere aggregation of another work not based on the Program
 139+with the Program (or with a work based on the Program) on a volume of
 140+a storage or distribution medium does not bring the other work under
 141+the scope of this License.
 142+
 143+ 3. You may copy and distribute the Program (or a work based on it,
 144+under Section 2) in object code or executable form under the terms of
 145+Sections 1 and 2 above provided that you also do one of the following:
 146+
 147+ a) Accompany it with the complete corresponding machine-readable
 148+ source code, which must be distributed under the terms of Sections
 149+ 1 and 2 above on a medium customarily used for software interchange; or,
 150+
 151+ b) Accompany it with a written offer, valid for at least three
 152+ years, to give any third party, for a charge no more than your
 153+ cost of physically performing source distribution, a complete
 154+ machine-readable copy of the corresponding source code, to be
 155+ distributed under the terms of Sections 1 and 2 above on a medium
 156+ customarily used for software interchange; or,
 157+
 158+ c) Accompany it with the information you received as to the offer
 159+ to distribute corresponding source code. (This alternative is
 160+ allowed only for noncommercial distribution and only if you
 161+ received the program in object code or executable form with such
 162+ an offer, in accord with Subsection b above.)
 163+
 164+The source code for a work means the preferred form of the work for
 165+making modifications to it. For an executable work, complete source
 166+code means all the source code for all modules it contains, plus any
 167+associated interface definition files, plus the scripts used to
 168+control compilation and installation of the executable. However, as a
 169+special exception, the source code distributed need not include
 170+anything that is normally distributed (in either source or binary
 171+form) with the major components (compiler, kernel, and so on) of the
 172+operating system on which the executable runs, unless that component
 173+itself accompanies the executable.
 174+
 175+If distribution of executable or object code is made by offering
 176+access to copy from a designated place, then offering equivalent
 177+access to copy the source code from the same place counts as
 178+distribution of the source code, even though third parties are not
 179+compelled to copy the source along with the object code.
 180+
 181+ 4. You may not copy, modify, sublicense, or distribute the Program
 182+except as expressly provided under this License. Any attempt
 183+otherwise to copy, modify, sublicense or distribute the Program is
 184+void, and will automatically terminate your rights under this License.
 185+However, parties who have received copies, or rights, from you under
 186+this License will not have their licenses terminated so long as such
 187+parties remain in full compliance.
 188+
 189+ 5. You are not required to accept this License, since you have not
 190+signed it. However, nothing else grants you permission to modify or
 191+distribute the Program or its derivative works. These actions are
 192+prohibited by law if you do not accept this License. Therefore, by
 193+modifying or distributing the Program (or any work based on the
 194+Program), you indicate your acceptance of this License to do so, and
 195+all its terms and conditions for copying, distributing or modifying
 196+the Program or works based on it.
 197+
 198+ 6. Each time you redistribute the Program (or any work based on the
 199+Program), the recipient automatically receives a license from the
 200+original licensor to copy, distribute or modify the Program subject to
 201+these terms and conditions. You may not impose any further
 202+restrictions on the recipients' exercise of the rights granted herein.
 203+You are not responsible for enforcing compliance by third parties to
 204+this License.
 205+
 206+ 7. If, as a consequence of a court judgment or allegation of patent
 207+infringement or for any other reason (not limited to patent issues),
 208+conditions are imposed on you (whether by court order, agreement or
 209+otherwise) that contradict the conditions of this License, they do not
 210+excuse you from the conditions of this License. If you cannot
 211+distribute so as to satisfy simultaneously your obligations under this
 212+License and any other pertinent obligations, then as a consequence you
 213+may not distribute the Program at all. For example, if a patent
 214+license would not permit royalty-free redistribution of the Program by
 215+all those who receive copies directly or indirectly through you, then
 216+the only way you could satisfy both it and this License would be to
 217+refrain entirely from distribution of the Program.
 218+
 219+If any portion of this section is held invalid or unenforceable under
 220+any particular circumstance, the balance of the section is intended to
 221+apply and the section as a whole is intended to apply in other
 222+circumstances.
 223+
 224+It is not the purpose of this section to induce you to infringe any
 225+patents or other property right claims or to contest validity of any
 226+such claims; this section has the sole purpose of protecting the
 227+integrity of the free software distribution system, which is
 228+implemented by public license practices. Many people have made
 229+generous contributions to the wide range of software distributed
 230+through that system in reliance on consistent application of that
 231+system; it is up to the author/donor to decide if he or she is willing
 232+to distribute software through any other system and a licensee cannot
 233+impose that choice.
 234+
 235+This section is intended to make thoroughly clear what is believed to
 236+be a consequence of the rest of this License.
 237+
 238+ 8. If the distribution and/or use of the Program is restricted in
 239+certain countries either by patents or by copyrighted interfaces, the
 240+original copyright holder who places the Program under this License
 241+may add an explicit geographical distribution limitation excluding
 242+those countries, so that distribution is permitted only in or among
 243+countries not thus excluded. In such case, this License incorporates
 244+the limitation as if written in the body of this License.
 245+
 246+ 9. The Free Software Foundation may publish revised and/or new versions
 247+of the General Public License from time to time. Such new versions will
 248+be similar in spirit to the present version, but may differ in detail to
 249+address new problems or concerns.
 250+
 251+Each version is given a distinguishing version number. If the Program
 252+specifies a version number of this License which applies to it and "any
 253+later version", you have the option of following the terms and conditions
 254+either of that version or of any later version published by the Free
 255+Software Foundation. If the Program does not specify a version number of
 256+this License, you may choose any version ever published by the Free Software
 257+Foundation.
 258+
 259+ 10. If you wish to incorporate parts of the Program into other free
 260+programs whose distribution conditions are different, write to the author
 261+to ask for permission. For software which is copyrighted by the Free
 262+Software Foundation, write to the Free Software Foundation; we sometimes
 263+make exceptions for this. Our decision will be guided by the two goals
 264+of preserving the free status of all derivatives of our free software and
 265+of promoting the sharing and reuse of software generally.
 266+
 267+ NO WARRANTY
 268+
 269+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 270+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
 271+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 272+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 273+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 274+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
 275+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
 276+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 277+REPAIR OR CORRECTION.
 278+
 279+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 280+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 281+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 282+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 283+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 284+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 285+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 286+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 287+POSSIBILITY OF SUCH DAMAGES.
 288+
 289+ END OF TERMS AND CONDITIONS
 290+
 291+ How to Apply These Terms to Your New Programs
 292+
 293+ If you develop a new program, and you want it to be of the greatest
 294+possible use to the public, the best way to achieve this is to make it
 295+free software which everyone can redistribute and change under these terms.
 296+
 297+ To do so, attach the following notices to the program. It is safest
 298+to attach them to the start of each source file to most effectively
 299+convey the exclusion of warranty; and each file should have at least
 300+the "copyright" line and a pointer to where the full notice is found.
 301+
 302+ <one line to give the program's name and a brief idea of what it does.>
 303+ Copyright (C) <year> <name of author>
 304+
 305+ This program is free software; you can redistribute it and/or modify
 306+ it under the terms of the GNU General Public License as published by
 307+ the Free Software Foundation; either version 2 of the License, or
 308+ (at your option) any later version.
 309+
 310+ This program is distributed in the hope that it will be useful,
 311+ but WITHOUT ANY WARRANTY; without even the implied warranty of
 312+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 313+ GNU General Public License for more details.
 314+
 315+ You should have received a copy of the GNU General Public License
 316+ along with this program; if not, write to the Free Software
 317+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 318+
 319+
 320+Also add information on how to contact you by electronic and paper mail.
 321+
 322+If the program is interactive, make it output a short notice like this
 323+when it starts in an interactive mode:
 324+
 325+ Gnomovision version 69, Copyright (C) year name of author
 326+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 327+ This is free software, and you are welcome to redistribute it
 328+ under certain conditions; type `show c' for details.
 329+
 330+The hypothetical commands `show w' and `show c' should show the appropriate
 331+parts of the General Public License. Of course, the commands you use may
 332+be called something other than `show w' and `show c'; they could even be
 333+mouse-clicks or menu items--whatever suits your program.
 334+
 335+You should also get your employer (if you work as a programmer) or your
 336+school, if any, to sign a "copyright disclaimer" for the program, if
 337+necessary. Here is a sample; alter the names:
 338+
 339+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 340+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
 341+
 342+ <signature of Ty Coon>, 1 April 1989
 343+ Ty Coon, President of Vice
 344+
 345+This General Public License does not permit incorporating your program into
 346+proprietary programs. If your program is a subroutine library, you may
 347+consider it more useful to permit linking proprietary applications with the
 348+library. If this is what you want to do, use the GNU Library General
 349+Public License instead of this License.
Property changes on: trunk/extensions/SemanticNotifyMe/COPYING
___________________________________________________________________
Name: svn:eol-style
349350 + native
Index: trunk/extensions/SemanticNotifyMe/README
@@ -1,29 +1,29 @@
2 -== About ==
3 -
4 -Semantic NotifyMe is a project for extending Semantic MediaWiki extension with
5 -"realtime notification" functions that allows users to get realtime notifications
6 -on semantic property-value changes. For details and further links, see
7 -http://www.mediawiki.org/wiki/Extension:Semantic_NotifyMe.
8 -
9 -Notes on installing Semantic NotifyMe are found in the file INSTALL.
10 -
11 -== Contact ==
12 -
13 -If you have remarks, questions, or suggestions, please send them to
14 -ning@teammersion.com.
15 -
16 -Bugs should be filed at MediaZilla, http://bugzilla.wikimedia.org/.
17 -
18 -== Developers ==
19 -
20 -Development is coordinated by Ning Hu and Justin Zhang.
21 -
22 -Semantic NotifyMe development is funded by Vulcan Inc.
23 -Semantic NotifyMe has also been supported in the Halo
24 -project funded by Vulcan Inc., where development is coordinated
25 -by ontoprise GmbH, Karlsruhe, Germany.
26 -
27 -== Contributors ==
28 -
29 -N/A
30 -
 2+== About ==
 3+
 4+Semantic NotifyMe is a project for extending Semantic MediaWiki extension with
 5+"realtime notification" functions that allows users to get realtime notifications
 6+on semantic property-value changes. For details and further links, see
 7+http://www.mediawiki.org/wiki/Extension:Semantic_NotifyMe.
 8+
 9+Notes on installing Semantic NotifyMe are found in the file INSTALL.
 10+
 11+== Contact ==
 12+
 13+If you have remarks, questions, or suggestions, please send them to
 14+ning@teammersion.com.
 15+
 16+Bugs should be filed at MediaZilla, http://bugzilla.wikimedia.org/.
 17+
 18+== Developers ==
 19+
 20+Development is coordinated by Ning Hu and Justin Zhang.
 21+
 22+Semantic NotifyMe development is funded by Vulcan Inc.
 23+Semantic NotifyMe has also been supported in the Halo
 24+project funded by Vulcan Inc., where development is coordinated
 25+by ontoprise GmbH, Karlsruhe, Germany.
 26+
 27+== Contributors ==
 28+
 29+N/A
 30+
Property changes on: trunk/extensions/SemanticNotifyMe/README
___________________________________________________________________
Name: svn:eol-style
3131 + native

Status & tagging log