Difference between revisions of "InstaGov/SMW"
m (Woozle moved page InstaGov/schema/SMW to InstaGov/SMW: This isn't just about substituting SMW for a specialized schema,) |
(→Syntax: code extracted from User:Woozle/smw-base.php) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 15: | Line 15: | ||
In each case, the remainder of the page (and the talk page) could be used for longer exposition and discussion that doesn't fit within the voting system's formal structure. | In each case, the remainder of the page (and the talk page) could be used for longer exposition and discussion that doesn't fit within the voting system's formal structure. | ||
===Questions=== | ===Questions=== | ||
− | This corresponds to the {{ | + | This corresponds to the {{instagov|schema|question}} table. |
* '''Summary''' would be a short summary of the given question, suitable for displaying in lists. | * '''Summary''' would be a short summary of the given question, suitable for displaying in lists. | ||
* '''Details''' would be a longer explanation, possibly for printing in reports | * '''Details''' would be a longer explanation, possibly for printing in reports | ||
+ | |||
+ | See [[/questions]] for an archive of my notes when I was thinking about replacing only the question table with SMW. | ||
===Answers=== | ===Answers=== | ||
− | This corresponds to the {{ | + | This corresponds to the {{instagov|schema|answer}} table. |
* '''Summary''' would be a short summary of the given answer, suitable for displaying in lists. | * '''Summary''' would be a short summary of the given answer, suitable for displaying in lists. | ||
* '''Details''' would be a longer explanation, possibly for printing in reports | * '''Details''' would be a longer explanation, possibly for printing in reports | ||
+ | * '''Archival notes''' (extracted from {{instagov|schema|answer}} page): | ||
+ | ** '''2011-06-06''' This table may end up not being used, since I've found I can use [[Semantic MediaWiki|SMW]] to store answer data. Also, I'm thinking it should be "choice" rather than "answer", but since it's no longer hard-coded, this is just a matter of updating documentation (and one field name in the {{instagov|schema|rating}} table). | ||
+ | |||
===Ratings=== | ===Ratings=== | ||
This is the tricky part. We need to tie together three things: a user, an answer, and the user's rating for that answer. SMW also lets us tie together three things (a page, a property name, and a property value) -- but how do we reliably map one to the other? | This is the tricky part. We need to tie together three things: a user, an answer, and the user's rating for that answer. SMW also lets us tie together three things (a page, a property name, and a property value) -- but how do we reliably map one to the other? | ||
Line 36: | Line 41: | ||
** <nowiki>{{#ask: [[Response to::</nowiki><u>name of question</u><nowiki>]] [[Category:Igov/answer]]}}</nowiki> | ** <nowiki>{{#ask: [[Response to::</nowiki><u>name of question</u><nowiki>]] [[Category:Igov/answer]]}}</nowiki> | ||
*** this is only somewhat useful, as there is no way of formatting the results based on w3tpl content; more useful output will need coding | *** this is only somewhat useful, as there is no way of formatting the results based on w3tpl content; more useful output will need coding | ||
+ | ==Code== | ||
+ | This code was originally in [[User:Woozle/smw-base.php|smw-base.php]]. | ||
+ | <php> | ||
+ | /* | ||
+ | 2012-08-13 This function was actually written for InstaGov, but appears to represent a significant amount of time-investment in | ||
+ | figuring out how to access SMW data. I don't need it for IG anymore (for now) because I'm doing things differently there now, | ||
+ | but it could well be useful for creating functions here in smw-base. | ||
+ | */ | ||
+ | /*----- | ||
+ | TAG: <igov> | ||
+ | PARAMS: | ||
+ | list=answers | ||
+ | target=(name of page) | ||
+ | name=(name of output array for each row) | ||
+ | vpage=[name of var in which to store each page name] | ||
+ | */ | ||
+ | function efIGov( $input, $args, $parser ) { | ||
+ | global $iggProperty_forResponses,$iggProperty_namespace; | ||
+ | |||
+ | $objArgs = new W3HookArgs($args); | ||
+ | |||
+ | if ($objArgs->Exists('list')) { | ||
+ | if ($objArgs->Exists('name')) { | ||
+ | $strNameRaw = $objArgs->GetArgVal('name'); | ||
+ | $strName = trim($strNameRaw); | ||
+ | $objVar = new clsW3VarName(); | ||
+ | $objVar->ParseName($strName); // resolve any indirection (e.g. $var) | ||
+ | } else { | ||
+ | $out = '[must set output array name using <b>name=</b>]'; | ||
+ | return; | ||
+ | } | ||
+ | $dbr =& wfGetDB( DB_SLAVE ); // read-only db object | ||
+ | |||
+ | // this SQL (when finished) gets a list of pages with the SMW properties we're looking for | ||
+ | $sqlSMW = 'SELECT | ||
+ | s.smw_title AS s_t, | ||
+ | s.smw_namespace AS s_ns, | ||
+ | pg.page_id | ||
+ | FROM | ||
+ | (((smw_rels2 AS x | ||
+ | LEFT JOIN smw_ids AS s ON x.s_id=s.smw_id) | ||
+ | LEFT JOIN smw_ids as p ON x.p_id=p.smw_id) | ||
+ | LEFT JOIN smw_ids AS o ON x.o_id=o.smw_id) | ||
+ | LEFT JOIN page AS pg ON ((s.smw_namespace=pg.page_namespace) AND (s.smw_title=pg.page_title)) | ||
+ | WHERE | ||
+ | (p.smw_title="'.$iggProperty_forResponses.'") AND | ||
+ | (p.smw_namespace='.$iggProperty_namespace.') AND | ||
+ | '; | ||
+ | $strType = $objArgs->GetVal('list'); | ||
+ | $strTarg = $objArgs->GetVal('target'); | ||
+ | $strPgVar = $objArgs->GetVal('vpage'); | ||
+ | $doHide = isset($args['hide']); // TRUE = only output <echo> sections | ||
+ | $objTarg = Title::newFromText($strTarg); | ||
+ | $sqlTarg = SQLValue($objTarg->getDBkey()); | ||
+ | $intNS = $objTarg->mNamespace; // is there not a function for this? | ||
+ | switch($strType) { | ||
+ | case 'answers': | ||
+ | $sqlFiltAdd = '(o.smw_title='.$sqlTarg.') AND (o.smw_namespace='.$intNS.')'; | ||
+ | break; | ||
+ | default: | ||
+ | $out = '[unknown list type]'; | ||
+ | } | ||
+ | $sqlFull = $sqlSMW.$sqlFiltAdd; | ||
+ | try { | ||
+ | $res = $dbr->query($sqlFull); | ||
+ | } | ||
+ | catch (Exception $e) { | ||
+ | $out = "W3TPL encountered a database error - ''".$dbr->lastError()."'' - from this SQL:<pre>$sqlFull</pre>"; | ||
+ | return $parser->recursiveTagParse($out); | ||
+ | } | ||
+ | $fPerRow = function($iRow) use($parser,$strName,$dbr,$objVar,$strPgVar) { | ||
+ | global $wgW3_data; | ||
+ | |||
+ | $idPage = $iRow->page_id; | ||
+ | |||
+ | $sqlMW = 'SELECT pp_propname, pp_value FROM page_props WHERE pp_page='; | ||
+ | $sqlFull = $sqlMW.$idPage; | ||
+ | |||
+ | $out = NULL; | ||
+ | try { | ||
+ | $res = $dbr->query($sqlFull); | ||
+ | } | ||
+ | catch (Exception $e) { | ||
+ | $out = "W3TPL encountered a database error - ''".$dbr->lastError()."'' - from this SQL:<pre>$sqlFull</pre>"; | ||
+ | return $parser->recursiveTagParse($out); | ||
+ | |||
+ | } | ||
+ | $objPage = Title::newFromID($idPage); | ||
+ | $objVar->Name = $strPgVar; | ||
+ | $objVar->Value = $objPage->getPrefixedText(); | ||
+ | $objVar->Store(); | ||
+ | while( $row = $dbr->fetchObject ( $res ) ) { | ||
+ | $strKey = $row->pp_propname; | ||
+ | $txtVal = $row->pp_value; | ||
+ | $objVar->Name = $strKey; | ||
+ | $objVar->Value = $txtVal; | ||
+ | $objVar->Store(); | ||
+ | } | ||
+ | |||
+ | return $out; | ||
+ | }; | ||
+ | $out = ProcessRows($dbr,$res,$strName,$parser,$input,$doHide,$fPerRow); | ||
+ | } | ||
+ | /* probably not using this after all | ||
+ | if (isset($args['type'])) { | ||
+ | $strType = $args['type']; | ||
+ | switch($strType) { | ||
+ | case 'question': | ||
+ | $out = '[question is {'.$input.'}]'; | ||
+ | break; | ||
+ | case 'answer': | ||
+ | $out = '[rnsr is {'.$input.'}]'; | ||
+ | break; | ||
+ | default: | ||
+ | $out = '[unknown type]'; | ||
+ | } | ||
+ | } else { | ||
+ | $out = '[type not specified]'; | ||
+ | } | ||
+ | */ | ||
+ | return $out; | ||
+ | } | ||
+ | </php> |
Latest revision as of 23:50, 12 February 2013
About
Instead of having separate tables for questions and answers, each question or answer could be a wiki page with SMW data. No edit logging would be necessary, as that will be handled automatically by the wiki's edit-logging features.
- Advantages:
- easier to set up (no database mods needed)
- no special software needed for basic functionality (especially if only trusted users have edit access)
- ability to leverage SMW features for analysis and reporting.
- Disadvantages:
- doesn't come with a user-friendly interface; will probably need some coding or at least advanced SMW (semantic forms, perhaps?)
- platform-dependent (need MW and SMW)
- may be difficult to prevent voter fraud (nothing to stop one user from voting multiple times or editing votes of other users)
- probably more CPU-intensive
- If users want to keep votes on any page other than their main user page, some tweaking (and possibly coding) will be needed in order to show votes-by-user in a nice format.
Page Types
In each case, the remainder of the page (and the talk page) could be used for longer exposition and discussion that doesn't fit within the voting system's formal structure.
Questions
This corresponds to the question table.
- Summary would be a short summary of the given question, suitable for displaying in lists.
- Details would be a longer explanation, possibly for printing in reports
See /questions for an archive of my notes when I was thinking about replacing only the question table with SMW.
Answers
This corresponds to the answer table.
- Summary would be a short summary of the given answer, suitable for displaying in lists.
- Details would be a longer explanation, possibly for printing in reports
- Archival notes (extracted from answer page):
Ratings
This is the tricky part. We need to tie together three things: a user, an answer, and the user's rating for that answer. SMW also lets us tie together three things (a page, a property name, and a property value) -- but how do we reliably map one to the other?
A solution:
- Any rating within a user's space means that the user has made that rating.
- The property name is the answer's page name.
- The property value is the user's rating (presumably -10 to +10 or similar).
The main issue here is that other users could edit a given user's vote. We will need to prevent or monitor this. We will also need to do something about out-of-range votes and invalid vote values.
Syntax
Displaying Lists
- answers:
- {{#ask: [[Response to::name of question]] [[Category:Igov/answer]]}}
- this is only somewhat useful, as there is no way of formatting the results based on w3tpl content; more useful output will need coding
- {{#ask: [[Response to::name of question]] [[Category:Igov/answer]]}}
Code
This code was originally in smw-base.php. <php> /*
2012-08-13 This function was actually written for InstaGov, but appears to represent a significant amount of time-investment in figuring out how to access SMW data. I don't need it for IG anymore (for now) because I'm doing things differently there now, but it could well be useful for creating functions here in smw-base.
- /
/*-----
TAG: <igov> PARAMS: list=answers target=(name of page) name=(name of output array for each row) vpage=[name of var in which to store each page name]
- /
function efIGov( $input, $args, $parser ) {
global $iggProperty_forResponses,$iggProperty_namespace;
$objArgs = new W3HookArgs($args);
if ($objArgs->Exists('list')) {
if ($objArgs->Exists('name')) { $strNameRaw = $objArgs->GetArgVal('name'); $strName = trim($strNameRaw); $objVar = new clsW3VarName(); $objVar->ParseName($strName); // resolve any indirection (e.g. $var) } else { $out = '[must set output array name using name=]'; return; } $dbr =& wfGetDB( DB_SLAVE ); // read-only db object
// this SQL (when finished) gets a list of pages with the SMW properties we're looking for $sqlSMW = 'SELECT s.smw_title AS s_t, s.smw_namespace AS s_ns, pg.page_id FROM (((smw_rels2 AS x
LEFT JOIN smw_ids AS s ON x.s_id=s.smw_id) LEFT JOIN smw_ids as p ON x.p_id=p.smw_id) LEFT JOIN smw_ids AS o ON x.o_id=o.smw_id) LEFT JOIN page AS pg ON ((s.smw_namespace=pg.page_namespace) AND (s.smw_title=pg.page_title)) WHERE
(p.smw_title="'.$iggProperty_forResponses.'") AND (p.smw_namespace='.$iggProperty_namespace.') AND '; $strType = $objArgs->GetVal('list'); $strTarg = $objArgs->GetVal('target'); $strPgVar = $objArgs->GetVal('vpage'); $doHide = isset($args['hide']); // TRUE = only output <echo> sections $objTarg = Title::newFromText($strTarg); $sqlTarg = SQLValue($objTarg->getDBkey()); $intNS = $objTarg->mNamespace; // is there not a function for this? switch($strType) { case 'answers': $sqlFiltAdd = '(o.smw_title='.$sqlTarg.') AND (o.smw_namespace='.$intNS.')'; break; default: $out = '[unknown list type]'; } $sqlFull = $sqlSMW.$sqlFiltAdd; try { $res = $dbr->query($sqlFull); } catch (Exception $e) {
$out = "W3TPL encountered a database error - ".$dbr->lastError()." - from this SQL:
$sqlFull
";
return $parser->recursiveTagParse($out); } $fPerRow = function($iRow) use($parser,$strName,$dbr,$objVar,$strPgVar) { global $wgW3_data;
$idPage = $iRow->page_id;
$sqlMW = 'SELECT pp_propname, pp_value FROM page_props WHERE pp_page='; $sqlFull = $sqlMW.$idPage;
$out = NULL; try { $res = $dbr->query($sqlFull); } catch (Exception $e) {
$out = "W3TPL encountered a database error - ".$dbr->lastError()." - from this SQL:
$sqlFull
";
return $parser->recursiveTagParse($out);
} $objPage = Title::newFromID($idPage); $objVar->Name = $strPgVar; $objVar->Value = $objPage->getPrefixedText(); $objVar->Store(); while( $row = $dbr->fetchObject ( $res ) ) { $strKey = $row->pp_propname; $txtVal = $row->pp_value; $objVar->Name = $strKey; $objVar->Value = $txtVal; $objVar->Store(); }
return $out; }; $out = ProcessRows($dbr,$res,$strName,$parser,$input,$doHide,$fPerRow);
}
/* probably not using this after all if (isset($args['type'])) { $strType = $args['type']; switch($strType) { case 'question': $out = '[question is {'.$input.'}]'; break; case 'answer': $out = '[rnsr is {'.$input.'}]'; break; default: $out = '[unknown type]'; } } else { $out = '[type not specified]'; }
- /
return $out;
} </php>