Netbrain has submitted this change and it was merged.
Change subject: Initial import of code
......................................................................
Initial import of code
Change-Id: Iee080eec7c33b355433b3d13ddec35e4b857295c
---
A SemanticSifter.i18n.magic.php
A SemanticSifter.i18n.php
A SemanticSifter.php
A resources/main/css/ext.semanticsifter.css
A resources/main/js/ext.semanticsifter.js
A src/main/SemanticSifterHooks.php
A src/main/api/API.php
A src/main/components/SemanticSifterComponent.php
A src/main/model/FilterStorageHTTPQuery.php
A src/main/parserfunction/Sift.php
A src/main/parserfunction/SiftLink.php
A src/test/model/FilterStorageHTTPQueryTest.php
12 files changed, 842 insertions(+), 0 deletions(-)
Approvals:
Netbrain: Verified; Looks good to me, approved
diff --git a/SemanticSifter.i18n.magic.php b/SemanticSifter.i18n.magic.php
new file mode 100644
index 0000000..1f529e0
--- /dev/null
+++ b/SemanticSifter.i18n.magic.php
@@ -0,0 +1,6 @@
+<?php
+$magicWords = array();
+$magicWords['en'] = array(
+ 'sift' => array( 0, 'sift' ),
+ 'siftlink' => array( 0, 'siftlink' ),
+);
\ No newline at end of file
diff --git a/SemanticSifter.i18n.php b/SemanticSifter.i18n.php
new file mode 100644
index 0000000..1250c09
--- /dev/null
+++ b/SemanticSifter.i18n.php
@@ -0,0 +1,17 @@
+<?php
+$messages = array();
+
+$messages['en'] = array(
+ 'semanticsifter-desc' => 'An extension which allows you to sift through
semantic data',
+ 'semanticsifter-button-apply-filter' => 'Apply filter',
+ 'semanticsifter-message-no-results' => 'No results',
+ 'semanticsifter-message-siftlink-params-error' => 'Missing parameters
to siftlink parser function.'
+);
+
+$messages['qqq'] = array(
+ 'semanticsifter-desc' => 'Extension description',
+ 'semanticsifter-button-apply-filter' => 'Button which applies filter',
+ 'semanticsifter-message-no-results' => 'Message shown when no results
yielded from filtering.',
+ 'semanticsifter-message-siftlink-params-error' => 'Message displayed
when error occurs in parameter handling of #siftlink parser function'
+
+);
\ No newline at end of file
diff --git a/SemanticSifter.php b/SemanticSifter.php
new file mode 100644
index 0000000..682cf9d
--- /dev/null
+++ b/SemanticSifter.php
@@ -0,0 +1,80 @@
+<?php
+if ( !defined( 'MEDIAWIKI' ) ) {
+ echo( "This file is an extension to the MediaWiki software and cannot
be used standalone.\n" );
+ die( 1 );
+}
+
+if ( !defined( 'SMW_VERSION' ) ) {
+ echo( "SemanticSifter extension requires SemanticMediaWiki\n" );
+ die( 1 );
+}
+
+if ( !defined( 'ParamProcessor_VERSION' ) ) {
+ echo( "SemanticSifter extension requires ParamProcessor\n" );
+ die( 1 );
+}
+
+function endsWith($haystack, $needle){
+ return $needle === "" || substr($haystack, -strlen($needle)) ===
$needle;
+}
+
+spl_autoload_register( function ( $className ) {
+ $className = ltrim( $className, '\\' );
+ $fileName = '';
+ $namespace = '';
+ $lastNsPos = strripos( $className, '\\');
+
+ if ( $lastNsPos ) {
+ $namespace = substr( $className, 0, $lastNsPos );
+ $className = substr( $className, $lastNsPos + 1 );
+ $fileName = str_replace( '\\', '/', $namespace ) . '/';
+ }
+
+ $fileName .= str_replace( '_', '/', $className ) . '.php';
+
+ $namespaceSegments = explode( '\\', $namespace );
+
+ if ( array_shift($namespaceSegments) === 'SemanticSifter' ) {
+ $fileName = substr($fileName,$lastNsPos);
+ $namespaceSegments = array_map('strtolower',
$namespaceSegments);
+
+ if(endsWith($fileName,'Test.php')){
+ require_once (__DIR__ . '/src/test/' .
join('/',$namespaceSegments) . $fileName);
+ }else{
+ require_once (__DIR__ . '/src/main/' .
join('/',$namespaceSegments) . $fileName);
+ }
+ }
+} );
+
+call_user_func( function() {
+ global
$wgExtensionCredits,$wgHooks,$wgExtensionMessagesFiles,$wgResourceModules,$wgAjaxExportList;
+
+ //credits
+ $wgExtensionCredits['parserhook'][] = array(
+ 'path' => __FILE__,
+ 'name' => 'Semantic Sifter',
+ 'descriptionmsg' => 'semanticsifter-desc',
+ 'version' => '0.1',
+ 'author' => 'Kim Eik',
+ );
+
+ //ajax
+ $wgAjaxExportList[] = 'SemanticSifter\API\API::filter';
+
+ //hooks
+ $wgHooks['ParserFirstCallInit'][] =
'SemanticSifter\SemanticSifterHooks::parserFunctionInit';
+ $wgHooks['UnitTestsList'][] =
'SemanticSifter\SemanticSifterHooks::unitTestsInit';
+
+ //i18n
+ $wgExtensionMessagesFiles['SemanticSifter'] = dirname( __FILE__ ) .
'/SemanticSifter.i18n.php';
+ $wgExtensionMessagesFiles['SemanticSifterMagic'] = dirname( __FILE__ )
. '/SemanticSifter.i18n.magic.php';
+
+ //resource modules
+ $wgResourceModules['ext.semanticsifter'] = array(
+ 'localBasePath' => dirname( __FILE__ ),
+ 'remoteExtPath' => 'SemanticSifter',
+ 'dependencies' => array( 'jquery.chosen','mediawiki.Uri' ),
+ 'scripts' => '/resources/main/js/ext.semanticsifter.js',
+ 'styles' => '/resources/main/css/ext.semanticsifter.css'
+ );
+});
\ No newline at end of file
diff --git a/resources/main/css/ext.semanticsifter.css
b/resources/main/css/ext.semanticsifter.css
new file mode 100644
index 0000000..a204913
--- /dev/null
+++ b/resources/main/css/ext.semanticsifter.css
@@ -0,0 +1,22 @@
+.ss-noresults {
+ background-color: #f9f9f9;
+ text-align: center;
+ font-weight: bold;
+ padding: 3px;
+ border: 1px solid #aaa;
+ margin: 1em 0px 0px 0px;
+}
+
+.ss-propertyfilter{
+ display: inline-block;
+ width: 20%;
+}
+
+.ss-propertyfilter li.search-field{
+ width: 100%;
+}
+
+.ss-propertyfilter li.search-field input.default{
+ width: auto !important;
+}
+
diff --git a/resources/main/js/ext.semanticsifter.js
b/resources/main/js/ext.semanticsifter.js
new file mode 100644
index 0000000..23eb313
--- /dev/null
+++ b/resources/main/js/ext.semanticsifter.js
@@ -0,0 +1,55 @@
+(function ($, mw) {
+
+
+ function serializeObject(obj) {
+ var o = {};
+ var a = obj.serializeArray();
+ $.each(a, function () {
+ if (o[this.name] !== undefined) {
+ if (!o[this.name].push) {
+ o[this.name] = [o[this.name]];
+ }
+ o[this.name].push(this.value || '');
+ } else {
+ o[this.name] = this.value || '';
+ }
+ });
+ return o;
+ }
+
+ $(document).ready(function () {
+ var container = $('.ss-container');
+ var form = $('.ss-filteringform');
+
+ form.each(function(){
+ $(this).submit(function () {
+ var filters = serializeObject(form)
+ var data = $.get(
+ mw.util.wikiScript(),
+ {
+ action: 'ajax',
+ rs: 'SemanticSifter\\API\\API::filter',
+ rsargs: [JSON.stringify(filters)]
+ }
+ ).done(function (response) {
+ var uri = new mw.Uri();
+ uri.extend( { filter: response } );
+ window.location.href = uri;
+ });
+
+ return false;
+ });
+ });
+
+
+ container.find('.ss-propertyfilter > select').chosen({width:'100%'});
+
+ for(var key in window.SemanticSifter){
+ var config = window.SemanticSifter[key];
+
$('#'+key).find('.ss-propertyfilter').width(config['filterbox-width']);
+
+ }
+
+ container.fadeIn();
+ });
+})($, mw);
\ No newline at end of file
diff --git a/src/main/SemanticSifterHooks.php b/src/main/SemanticSifterHooks.php
new file mode 100644
index 0000000..93fefb9
--- /dev/null
+++ b/src/main/SemanticSifterHooks.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace SemanticSifter;
+
+class SemanticSifterHooks {
+
+ public static function unitTestsInit( &$files ) {
+ $testDir = __DIR__ . '/src/test';
+ $files = array_merge( $files, glob( "$testDir/*Test.php" ) );
+ return true;
+ }
+
+ public static function parserFunctionInit( \Parser &$parser ) {
+ $parser->setFunctionHook( 'sift',
'SemanticSifter\ParserFunction\Sift::parserHook' );
+ $parser->setFunctionHook( 'siftlink',
'SemanticSifter\ParserFunction\SiftLink::parserHook' );
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/api/API.php b/src/main/api/API.php
new file mode 100644
index 0000000..b8f8e6c
--- /dev/null
+++ b/src/main/api/API.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace SemanticSifter\API;
+
+use SemanticSifter\Model\FilterStorageHTTPQuery;
+
+class API {
+
+ public static function filter($filters){
+ $filterStorage = new FilterStorageHTTPQuery(false);
+ $filters = json_decode($filters);
+ foreach($filters as $property => $values){
+ if(!is_array($values)){
+ $values = array($values);
+ }
+
+ foreach($values as $value){
+ $filterStorage->addFilter($property,$value);
+ }
+ }
+ return $filterStorage->getFiltersAsQueryString(false);
+ }
+}
\ No newline at end of file
diff --git a/src/main/components/SemanticSifterComponent.php
b/src/main/components/SemanticSifterComponent.php
new file mode 100644
index 0000000..ec0afcd
--- /dev/null
+++ b/src/main/components/SemanticSifterComponent.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * @author: Kim Eik
+ */
+
+namespace SemanticSifter\Components;
+
+use \SMW\StoreFactory;
+use SemanticSifter\Model\FilterStorageHTTPQuery;
+/**
+ * Class SemanticSifterComponent
+ * @package SemanticSifter
+ */
+class SemanticSifterComponent {
+
+ /**
+ * HTTP Query storage system for filter selection
+ * @var FilterStorageHTTPQuery
+ */
+ protected $filterStorage;
+
+ /**
+ * @var \Parser
+ */
+ protected $parser;
+
+ /**
+ * The title of which the component will be created
+ * @var \Title
+ */
+ protected $title;
+
+
+
+ /**
+ * @param $parser \Parser
+ * @param $filterStorage FilterStorageHTTPQuery
+ */
+ function __construct(&$parser, $filterStorage = null) {
+ if(is_null($filterStorage)){
+ $filterStorage = new FilterStorageHTTPQuery();
+ }
+ $this->filterStorage = $filterStorage;
+ $this->parser = $parser;
+ $this->title = $parser->getTitle();
+ }
+
+ /**
+ * @param SMW\Store $smwStore
+ * @param SMW\DIProperty $property
+ * @return array
+ * @throws \Exception
+ */
+ protected function getPropertyValue( $smwStore, $property ) {
+ $wikiPages = $smwStore->getAllPropertySubjects( $property );
+ $v = array();
+ foreach ( $wikiPages as $wp ) {
+ foreach ( $smwStore->getPropertyValues( $wp, $property
) as $value ) {
+ if ( $value instanceof \SMWDataItem ) {
+ switch ( $value->getDIType() ) {
+ case
\SMWDataItem::TYPE_WIKIPAGE:
+ $title =
$value->getTitle()->getFullText();
+ break;
+ default:
+ $title =
$value->getSerialization();
+ break;
+ }
+ if ( !array_key_exists( $title, $v ) ) {
+ $v[$title] = null;
+ }
+ continue;
+ }
+ throw new \Exception( "Unknown value type,
expected: SMWDataItem but got: " . get_class( $value ) );
+ }
+ }
+ return array_keys($v);
+ }
+
+ public function getComponents($query,$properties,$smwParams =
array(),$smwProperties = array()){
+ //create smw query
+ if(empty($smwProperties)){
+ $smwProperties = $properties;
+ }
+ $tableComponent = $this->createSMWQueryComponent($query,
$smwProperties, $smwParams);
+
+ //get smw property information and generate filterering
component
+ $filteringComponent =
$this->createFilteringComponent($properties);
+
+ return array($filteringComponent,$tableComponent);
+ }
+
+ protected function createSMWQueryFilter() {
+ $filters = $this->filterStorage->getFilters();
+ $tableFilters = '';
+ if ( !empty( $filters ) ) {
+ foreach ($filters as $property => $values ) {
+ $c = 0;
+ $tableFilters .= "[[$property:: ";
+ foreach ( $values as $value ) {
+ if ( $c > 0 ) {
+ $tableFilters .= '||';
+ }
+ $tableFilters .= $value;
+ $c++;
+ }
+ $tableFilters .= ']]';
+ }
+ }
+ return $tableFilters;
+ }
+
+ public function createSMWQueryComponent($query, $properties, $params =
array() ) {
+ $smwParams = array(
+ 'format' => 'broadtable',
+ 'default' => '<div
class="ss-noresults">'.wfMessage('semanticsifter-message-no-results')->text().'</div>'
+ );
+ $smwParams = array_merge($smwParams,$params);
+
+ $tableFilters = $this->createSMWQueryFilter();
+ $tableQuery = "{{#ask: $query $tableFilters";
+ foreach ( $properties as $property => $value ) {
+ $tableQuery .= '|?'.(is_null($value) ? $property :
"$property=$value");
+ }
+
+ foreach($smwParams as $name => $value){
+ $tableQuery .= "|$name=$value";
+ }
+ $tableQuery .= '}}';
+
+ return $tableQuery;
+ }
+
+ protected function createFilteringComponent($properties) {
+ $smwStore = StoreFactory::getStore();
+ $output = '<form class="ss-filteringform">';
+ foreach ( $properties as $p => $v ) {
+ $displayValue = is_null($v) ? $p : $v;
+ $property = \SMWDIProperty::newFromUserLabel( $p );
+ $pValues = $this->getPropertyValue( $smwStore,
$property );
+ $output .= "<div class=\"ss-propertyfilter\">";
+ $output .= "<select name=\"$p\"
class=\"ss-property-select\" data-placeholder=\"$displayValue\"
title=\"$displayValue\" multiple>";
+ foreach($pValues as $pValue){
+ $selected =
$this->filterStorage->filterExists($p,$pValue) ? 'selected' : '';
+ $output .= "<option value=\"$pValue\"
$selected>$pValue</option>";
+ }
+ $output .= "</select>";
+ $output .= "</div>";
+ }
+ $output .= '<div><button
type="submit">'.wfMessage('semanticsifter-button-apply-filter')->text().'</button></div>';
+ $output .= '</form>';
+ return $output;
+ }
+}
\ No newline at end of file
diff --git a/src/main/model/FilterStorageHTTPQuery.php
b/src/main/model/FilterStorageHTTPQuery.php
new file mode 100644
index 0000000..fcfb440
--- /dev/null
+++ b/src/main/model/FilterStorageHTTPQuery.php
@@ -0,0 +1,185 @@
+<?php
+/**
+ * @author: Kim Eik
+ */
+
+namespace SemanticSifter\Model;
+
+/**
+ * Class FilterStorageHTTPQuery
+ * @package SemanticSifter
+ */
+class FilterStorageHTTPQuery{
+ const QUERY_KEY = 'filter';
+ const FILTER_SEPARATOR = ";";
+ const PROPERTY_VALUE_SEPARATOR = "::";
+
+
+ private $filters = array();
+
+ /**
+ * @param bool $loadFromGET
+ */
+ function __construct( $loadFromGET = true ) {
+ $loadFromGET = $loadFromGET &&
array_key_exists(self::QUERY_KEY,$_GET);
+ if($loadFromGET){
+ $filters =
explode(self::FILTER_SEPARATOR,urldecode($_GET[self::QUERY_KEY]));
+ foreach($filters as $filter){
+ if(!empty($filter)){
+ list($property, $value) =
$this->getDecodedFilterString($filter);
+ $this->addFilter($property,$value);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param $property
+ * @param $value
+ * @return $this
+ */
+ public function addFilter($property,$value){
+ $this->filters[$property][$value] = null;
+ return $this;
+ }
+
+ /**
+ * @param $property
+ * @param $value
+ * @return $this
+ */
+ public function removeFilter($property,$value = null){
+ if(is_null($value)){
+ unset($this->filters[$property]);
+ }else{
+ unset($this->filters[$property][$value]);
+ if(count($this->filters[$property]) === 0){
+ $this->removeFilter($property);
+ }
+ }
+ return $this;
+ }
+
+ public function toggleFilter($property,$value){
+ if(array_key_exists($property,$this->filters) &&
array_key_exists($value,$this->filters[$property])){
+ $this->removeFilter($property,$value);
+ }else{
+ $this->addFilter($property,$value);
+ }
+ return $this;
+ }
+
+ /**
+ * @return array
+ */
+ public function getFilters() {
+ $filters = $this->filters;
+ foreach(array_keys($filters) as $key){
+ $filters[$key] = array_keys($filters[$key]);
+ }
+ return $filters;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFiltersAsQueryString($prefixQueryKey = true) {
+ $filters = $this->getFilters();
+ $queryArray = array();
+ foreach($filters as $property => $values){
+ foreach($values as $value){
+ $queryArray[] =
$this->getEncodedFilterString($property,$value);
+ }
+ }
+ if(count($queryArray) > 0){
+ $queryStr = implode(self::FILTER_SEPARATOR,$queryArray);
+ if($prefixQueryKey){
+ $queryStr = self::QUERY_KEY.'='.$queryStr;
+ }
+ return $queryStr;
+ }
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function getFiltersAsSeparatedString() {
+ $filters = $this->getFilters();
+ $queryArray = array();
+ foreach($filters as $property => $values){
+ foreach($values as $value){
+ $queryArray[] =
$this->getFilterString($property,$value);
+ }
+ }
+ $queryStr = implode(self::FILTER_SEPARATOR,$queryArray);
+ return $queryStr;
+ }
+
+
+ /**
+ * @param $filters
+ * @throws \InvalidArgumentException
+ * @return $this
+ */
+ public function setFiltersFromSeparatedString($filters) {
+ if(!empty($filters)){
+ $filters = explode(self::FILTER_SEPARATOR,$filters);
+ foreach($filters as $filter){
+
if(substr_count($filter,self::PROPERTY_VALUE_SEPARATOR) !== 1){
+ throw new
\InvalidArgumentException("'$filter'' does not match the expected format
<property>".
+
self::PROPERTY_VALUE_SEPARATOR."<value>".
+ self::FILTER_SEPARATOR."[<property>".
+
self::PROPERTY_VALUE_SEPARATOR."<value>]...");
+ }
+ list($property,$value) =
explode(self::PROPERTY_VALUE_SEPARATOR,$filter);
+ $this->addFilter($property,$value);
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function size(){
+ return count($this->filters);
+ }
+
+ public function filterExists($property,$value){
+ return array_key_exists($property,$this->filters) &&
array_key_exists($value,$this->filters[$property]);
+ }
+
+ /**
+ * @param $property
+ * @param $value
+ * @return string
+ */
+ private function getEncodedFilterString($property,$value){
+ return base64_encode($this->getFilterString($property,$value));
+ }
+
+ /**
+ * @param $property
+ * @param $value
+ * @return string
+ */
+ private function getFilterString($property, $value){
+ return $property.self::PROPERTY_VALUE_SEPARATOR.$value;
+ }
+
+ /**
+ * @param $input
+ * @return array
+ * @throws \InvalidArgumentException
+ */
+ private function getDecodedFilterString($input){
+ $filter = base64_decode($input,true);
+ if($filter !== false &&
substr_count($filter,self::PROPERTY_VALUE_SEPARATOR) === 1){
+ $filterParts =
explode(self::PROPERTY_VALUE_SEPARATOR,$filter);
+ return $filterParts;
+ }
+ throw new \InvalidArgumentException("'$input ($filter)' does
not match the expected format
<property>".self::PROPERTY_VALUE_SEPARATOR."<value>");
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/parserfunction/Sift.php b/src/main/parserfunction/Sift.php
new file mode 100644
index 0000000..f2dea9c
--- /dev/null
+++ b/src/main/parserfunction/Sift.php
@@ -0,0 +1,133 @@
+<?php
+
+namespace SemanticSifter\ParserFunction;
+
+
+use ParamProcessor\ProcessedParam;
+use ParamProcessor\ProcessingResult;
+use ParamProcessor\Processor;
+use SemanticSifter\Components\SemanticSifterComponent;
+
+class Sift {
+
+ private $component;
+
+ public function __construct(\Parser &$parser){
+ $this->component = new SemanticSifterComponent($parser);
+ }
+
+ public static function parserHook(\Parser &$parser){
+ $parser->getOutput()->addModules( 'ext.semanticsifter' );
+ $parser->disableCache();
+
+ try{
+ //get parameters
+ $args = func_get_args();
+ array_shift($args);
+ $args = self::getParameters( $args );
+ $parameters = $args->getParameters();
+
+ if(!$parameters){
+ throw new \InvalidArgumentException("Error with
parameters.");
+ }
+
+ $properties = array();
+ $smwProperties = array();
+ $smwParams = array();
+ foreach($parameters as $param){
+ if(strpos($param->getName(),'?') === 0){
+
$properties[substr($param->getName(),1)] = $param->getValue();
+ }elseif(strpos($param->getName(),'!?') === 0){
+
$smwProperties[substr($param->getName(),2)] = $param->getValue();
+ }elseif(strpos($param->getName(),'!') === 0){
+ $smwParams[substr($param->getName(),1)]
= $param->getValue();
+ }
+ }
+
+ $component = new SemanticSifterComponent($parser);
+ list($filteringComponent,$tableComponent) =
$component->getComponents(
+ $parameters['query']->getValue(),
+ $properties,
+ $smwParams,
+ $smwProperties
+ );
+
+ //create final html output
+ $id = uniqid();
+ $jsonParams = array(
+ 'filterbox-width' =>
$parameters['filterbox-width']->getValue(),
+ );
+ $jsonParams = json_encode($jsonParams);
+ $output = <<<EOT
+ <script type="text/javascript">
+ if(window.SemanticSifter === undefined){
+ window.SemanticSifter = {};
+ }
+ window.SemanticSifter['$id'] =
$jsonParams;
+ </script>
+ <div id="$id" class="ss-container"
style="display: none;">
+ {$filteringComponent}
+ <div style="overflow:auto">
+
{$parser->recursiveTagParse($tableComponent)}
+ </div>
+ </div>
+EOT;
+ }catch (\Exception $e){
+ //TODO add a more user friendly error
+ return $e;
+ }
+ $output =
str_replace(array("\r","\n","\t"),array('','',''),$output);
+ return array($output, 'noparse' => true, 'isHTML' => true );
+ }
+
+
+ private static function getParameters( array $args = array() ){
+ //Hackish use of ParamProcessor to make input parameters
similar to #ask parser function input
+ $properties = array();
+ foreach($args as $key => &$arg){
+ $arg = trim($arg);
+ switch(substr($arg,0,1)){
+ case '?':
+ case '!':
+ list($property,$display) =
array_pad(explode('=',$arg,2), 2, null);
+ $properties[$property] = new
ProcessedParam($property,$display,false);
+ unset($args[$key]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ $parameterDefs = array(
+ array(
+ 'name' => 'query',
+ 'default' => '',
+ 'message' => 'semanticsifter-param-query',
+ ),
+ array(
+ 'name' => 'filterbox-width',
+ 'default' => '20%',
+ 'message' =>
'semanticsifter-param-filterbox-width',
+ )
+ );
+
+ $defaultParams = array(
+ array(
+ 0 => 'query',
+ 1 => Processor::PARAM_UNNAMED,
+ )
+ );
+
+
+ $processor = Processor::newDefault();
+
$processor->setFunctionParams($args,$parameterDefs,$defaultParams);
+ $processedParams = $processor->processParameters();
+
+ //Postprocess params
+ $processedParams = new
ProcessingResult(array_merge($processedParams->getParameters(),$properties),$processedParams->getErrors());
+ if($processedParams->hasFatal()){
+ return false;
+ }
+ return $processedParams;
+ }
+}
\ No newline at end of file
diff --git a/src/main/parserfunction/SiftLink.php
b/src/main/parserfunction/SiftLink.php
new file mode 100644
index 0000000..e091dd2
--- /dev/null
+++ b/src/main/parserfunction/SiftLink.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace SemanticSifter\ParserFunction;
+
+use SemanticSifter\Model\FilterStorageHTTPQuery;
+
+class SiftLink {
+
+ public static function parserHook(\Parser &$parser,$title, $filters,
$text){
+ if(is_null($title) || is_null($filters) || is_null($text)){
+ return
wfMessage('semanticsifter-message-siftlink-params-error');
+ }
+
+ try{
+ $filterStorage = new FilterStorageHTTPQuery(false);
+ $filterStorage->setFiltersFromSeparatedString($filters);
+
+ $title = \Title::newFromText($title);
+
+ $filters = $filterStorage->size() > 0 ? array(
+ FilterStorageHTTPQuery::QUERY_KEY =>
$filterStorage->getFiltersAsQueryString(false)
+ ) : array();
+
+ $output = \Linker::link($title,$text,array('title' =>
null),$filters);
+
+ return array($output, 'noparse' => true, 'isHTML' =>
true );
+ }catch (\Exception $e){
+ //TODO add a more user friendly error
+ return $e;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/model/FilterStorageHTTPQueryTest.php
b/src/test/model/FilterStorageHTTPQueryTest.php
new file mode 100644
index 0000000..6a61c99
--- /dev/null
+++ b/src/test/model/FilterStorageHTTPQueryTest.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @author: Kim Eik
+ */
+
+namespace SemanticSifter;
+
+
+class FilterStorageHTTPQueryTest extends \MediaWikiTestCase {
+ /**
+ * @var FilterStorageHTTPQuery
+ */
+ private $filterStorage;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->filterStorage = new FilterStorageHTTPQuery();
+ }
+
+ protected function tearDown() {
+ unset( $this->filterStorage );
+ unset($_GET['filter']);
+ parent::tearDown();
+ }
+
+ public function testGetFiltersFromGET() {
+ $_GET['filter'] = base64_encode( 'Property::Value' );
+ $this->filterStorage = new FilterStorageHTTPQuery();
+ $this->assertArrayEquals( array(
+ 'Property' => array( 'Value' )
+ ), $this->filterStorage->getFilters() );
+ }
+
+ public function testGetFiltersFromGETWhenInvalidFormat() {
+ $this->setExpectedException('InvalidArgumentException');
+ $_GET['filter'] = 'INVALID';
+ $this->filterStorage = new FilterStorageHTTPQuery();
+ }
+
+ public function testAddFilter() {
+
$this->assertType('SemanticSifter\FilterStorageHTTPQuery',$this->filterStorage->addFilter('Property','Value'));
+ $this->assertArrayEquals( array(
+ 'Property' => array( 'Value' )
+ ), $this->filterStorage->getFilters() );
+ }
+
+ public function testAddManyFilterByChaining() {
+
$this->filterStorage->addFilter('Property','Value')->addFilter('Property','Value2')->addFilter('Property2','Value');
+ $this->assertArrayEquals( array(
+ 'Property' => array( 'Value','Value2' ),
+ 'Property2' => array( 'Value' )
+ ), $this->filterStorage->getFilters() );
+ }
+
+ public function testRemoveFilter() {
+ $this->filterStorage->addFilter('Property','Value');
+ $this->filterStorage->addFilter('Property','Value2');
+ $this->filterStorage->removeFilter('Property','Value');
+ $this->assertArrayEquals( array(
+ 'Property' => array( 'Value2' )
+ ), $this->filterStorage->getFilters() );
+ }
+
+ public function testRemoveAllFiltersByProperty() {
+ $this->filterStorage->addFilter('Property','Value');
+ $this->filterStorage->addFilter('Property','Value2');
+ $this->filterStorage->removeFilter('Property');
+ $this->assertArrayEquals( array(),
$this->filterStorage->getFilters() );
+ }
+
+ public function testGetFiltersAsHTTPQueryString() {
+ $expected = 'filter=';
+ $expected .= base64_encode('Property::Value');
+ $expected .= ';';
+ $expected .= base64_encode('Property::Value2');
+
+ $this->filterStorage->addFilter('Property','Value');
+ $this->filterStorage->addFilter('Property','Value2');
+ $this->assertEquals( $expected,
$this->filterStorage->getFiltersAsQueryString() );
+ }
+
+ public function testGetFiltersAsSeparatedString() {
+ $expected = 'Property::Value';
+ $expected .= ';';
+ $expected .= 'Property::Value2';
+
+ $this->filterStorage->addFilter('Property','Value');
+ $this->filterStorage->addFilter('Property','Value2');
+ $this->assertEquals( $expected,
$this->filterStorage->getFiltersAsSeparatedString() );
+ }
+
+ public function testToggleFilter(){
+ $this->filterStorage->toggleFilter('Property','Value');
+ $this->assertArrayEquals( array(
+ 'Property' => array('Value')
+ ), $this->filterStorage->getFilters() );
+ $this->filterStorage->toggleFilter('Property','Value');
+ $this->assertArrayEquals( array(),
$this->filterStorage->getFilters() );
+ }
+
+ public function testSetFiltersFromSeparatedString(){
+ $string = 'Property::Value;Property::Value2';
+ $this->assertArrayEquals(array(
+ 'Property' => array(
+ 'Value',
+ 'Value2'
+ )
+
),$this->filterStorage->setFiltersFromSeparatedString($string)->getFilters());
+ }
+
+
+ public function testSetFiltersFromSeparatedStringThatIsEmpty(){
+ $string = '';
+
$this->assertArrayEquals(array(),$this->filterStorage->setFiltersFromSeparatedString($string)->getFilters());
+ }
+
+}
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/89815
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Iee080eec7c33b355433b3d13ddec35e4b857295c
Gerrit-PatchSet: 16
Gerrit-Project: mediawiki/extensions/SemanticSifter
Gerrit-Branch: master
Gerrit-Owner: Netbrain <[email protected]>
Gerrit-Reviewer: Netbrain <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits