Addshore has uploaded a new change for review.
https://gerrit.wikimedia.org/r/222565
Change subject: Add optional validation to ParseValue api
......................................................................
Add optional validation to ParseValue api
Bug: T104330
Change-Id: Ia6bcd1e85f6867663457122d19310ca4d7e9af81
---
M lib/includes/DataValueFactory.php
M repo/Wikibase.php
M repo/i18n/en.json
M repo/i18n/qqq.json
M repo/includes/api/ParseValue.php
M repo/tests/phpunit/includes/api/ParseValueTest.php
6 files changed, 155 insertions(+), 24 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase
refs/changes/65/222565/1
diff --git a/lib/includes/DataValueFactory.php
b/lib/includes/DataValueFactory.php
index 3f5378c..d8fafe9 100644
--- a/lib/includes/DataValueFactory.php
+++ b/lib/includes/DataValueFactory.php
@@ -23,6 +23,7 @@
*/
protected $values = array(
'boolean' => 'DataValues\BooleanValue',
+ 'decimal' => 'DataValues\DecimalValue',
'number' => 'DataValues\NumberValue',
'string' => 'DataValues\StringValue',
'unknown' => 'DataValues\UnknownValue',
diff --git a/repo/Wikibase.php b/repo/Wikibase.php
index c361c12..a97e90b 100644
--- a/repo/Wikibase.php
+++ b/repo/Wikibase.php
@@ -52,6 +52,7 @@
* @deprecated since 0.5 This is a global registry that provides no control
over object lifecycle
*/
$GLOBALS['wgValueParsers'] = array();
+$GLOBALS['wgValueValidators'] = array();
// Include the WikibaseLib extension if that hasn't been done yet, since it's
required for Wikibase to work.
if ( !defined( 'WBL_VERSION' ) ) {
diff --git a/repo/i18n/en.json b/repo/i18n/en.json
index 6e8d65d..40aedf3 100644
--- a/repo/i18n/en.json
+++ b/repo/i18n/en.json
@@ -548,8 +548,9 @@
"apihelp-wbmergeitems-example-2": "Merges data from Q555 into Q3",
"apihelp-wbmergeitems-example-3": "Merges data from Q66 into Q99
ignoring any conflicting labels",
"apihelp-wbmergeitems-example-4": "Merges data from Q66 into Q99
ignoring any conflicting labels and descriptions",
- "apihelp-wbparsevalue-description": "Parses values using a
ValueParser.",
+ "apihelp-wbparsevalue-description": "Parses values using a ValueParser
and optional Validator.",
"apihelp-wbparsevalue-param-parser": "ID of the ValueParser to use",
+ "apihelp-wbparsevalue-param-validator": "ID of the ValueValidator to
use",
"apihelp-wbparsevalue-param-values": "The values to parse",
"apihelp-wbparsevalue-param-options": "The options the parser should
use. Provided as a JSON object.",
"apihelp-wbparsevalue-example-1": "No change to the format of the
string.",
diff --git a/repo/i18n/qqq.json b/repo/i18n/qqq.json
index be2aa04..3cfa9c0 100644
--- a/repo/i18n/qqq.json
+++ b/repo/i18n/qqq.json
@@ -578,6 +578,7 @@
"apihelp-wbmergeitems-example-4":
"{{doc-apihelp-example|wbmergeitems}}",
"apihelp-wbparsevalue-description":
"{{doc-apihelp-description|wbparsevalue}}",
"apihelp-wbparsevalue-param-parser":
"{{doc-apihelp-param|wbparsevalue|parser}}",
+ "apihelp-wbparsevalue-param-validator":
"{{doc-apihelp-param|wbparsevalue|validator}}",
"apihelp-wbparsevalue-param-values":
"{{doc-apihelp-param|wbparsevalue|values}}",
"apihelp-wbparsevalue-param-options":
"{{doc-apihelp-param|wbparsevalue|options}}",
"apihelp-wbparsevalue-example-1":
"{{doc-apihelp-example|wbparsevalue}}",
diff --git a/repo/includes/api/ParseValue.php b/repo/includes/api/ParseValue.php
index 2cdfa24..5ceea92 100644
--- a/repo/includes/api/ParseValue.php
+++ b/repo/includes/api/ParseValue.php
@@ -10,7 +10,10 @@
use ValueParsers\ParseException;
use ValueParsers\ParserOptions;
use ValueParsers\ValueParser;
+use ValueValidators\Result;
+use ValueValidators\ValueValidator;
use Wikibase\Repo\ValueParserFactory;
+use Wikibase\Repo\ValueValidatorFactory;
/**
* API module for using value parsers.
@@ -20,23 +23,40 @@
* @licence GNU GPL v2+
* @author Jeroen De Dauw < [email protected] >
* @author Daniel Kinzler
+ * @author Adam Shorland
*/
class ParseValue extends ApiWikibase {
/**
* @var null|ValueParserFactory
*/
- private $factory = null;
+ private $parserFactory = null;
+
+ /**
+ * @var null|ValueValidatorFactory
+ */
+ private $validatorFactory = null;
/**
* @return ValueParserFactory
*/
- private function getFactory() {
- if ( $this->factory === null ) {
- $this->factory = new ValueParserFactory(
$GLOBALS['wgValueParsers'] );
+ private function getParserFactory() {
+ if ( $this->parserFactory === null ) {
+ $this->parserFactory = new ValueParserFactory(
$GLOBALS['wgValueParsers'] );
}
- return $this->factory;
+ return $this->parserFactory;
+ }
+
+ /**
+ * @return ValueValidatorFactory
+ */
+ private function getValidatorFactory() {
+ if ( $this->validatorFactory === null ) {
+ $this->validatorFactory = new ValueValidatorFactory(
$GLOBALS['wgValueValidators'] );
+ }
+
+ return $this->validatorFactory;
}
/**
@@ -46,6 +66,7 @@
*/
public function execute() {
$parser = $this->getParser();
+ $validator = $this->getValidator();
$results = array();
@@ -55,7 +76,28 @@
$results[] = $this->parseStringValue( $parser, $value );
}
- $this->outputResults( $results );
+ if ( $validator !== null ) {
+ foreach ( $results as &$result ) {
+ $this->validateParsedValue( $validator, $result
);
+ }
+ }
+
+ $this->outputResults( $this->formatResultsForOutput( $results )
);
+ }
+
+ private function formatResultsForOutput( $results ) {
+ foreach ( $results as &$result ) {
+ if ( array_key_exists( 'parsedvalue', $result ) ) {
+ if ( $result['parsedvalue'] instanceof
DataValue ) {
+ $result['value'] =
$result['parsedvalue']->getArrayValue();
+ $result['type'] =
$result['parsedvalue']->getType();
+ } else {
+ $result['value'] =
$result['parsedvalue'];
+ }
+ unset( $result['parsedvalue'] );
+ }
+ }
+ return $results;
}
/**
@@ -65,15 +107,30 @@
private function getParser() {
$params = $this->extractRequestParams();
- $options = $this->getOptionsObject( $params['options'] );
+ $options = $this->getParserOptionsObject( $params['options'] );
try {
- $parser = $this->getFactory()->newParser(
$params['parser'], $options );
+ $parser = $this->getParserFactory()->newParser(
$params['parser'], $options );
} catch ( OutOfBoundsException $ex ) {
throw new LogicException( 'Could not obtain a
ValueParser instance' );
}
return $parser;
+ }
+
+ /**
+ * @return ValueValidator|null
+ */
+ private function getValidator() {
+ $params = $this->extractRequestParams();
+
+ try {
+ $validator =
$this->getValidatorFactory()->newValidator( $params['validator'] );
+ } catch ( OutOfBoundsException $ex ) {
+ return null;
+ }
+
+ return $validator;
}
/**
@@ -88,22 +145,42 @@
);
try {
- $parseResult = $parser->parse( $value );
+ $result['parsedvalue'] = $parser->parse( $value );
}
catch ( ParseException $parseError ) {
$this->addParseErrorToResult( $result, $parseError );
- return $result;
- }
-
- if ( $parseResult instanceof DataValue ) {
- $result['value'] = $parseResult->getArrayValue();
- $result['type'] = $parseResult->getType();
- }
- else {
- $result['value'] = $parseResult;
}
return $result;
+ }
+
+ private function validateParsedValue( ValueValidator $validator,
&$result ) {
+ if ( array_key_exists( 'parsedvalue', $result ) ) {
+
+ if ( $result['parsedvalue'] instanceof DataValue ) {
+ $validationResult = $validator->validate(
$result['parsedvalue']->getValue() );
+ } else {
+ $validationResult = $validator->validate(
$result['parsedvalue'] );
+ }
+ $this->addValidationResultToResult( $result,
$validationResult );
+
+ } else {
+ $result['valid'] = false;
+ }
+ }
+
+ private function addValidationResultToResult( array &$result, Result
$validationResult ) {
+ $isValid = $validationResult->isValid();
+ if ( $isValid ) {
+ $result['valid'] = true;
+ } else {
+ $result['valid'] = false;
+ $errors = $validationResult->getErrors();
+ foreach ( $errors as $key => $error ) {
+ $result['validation-info'][$key]['code'] =
$error->getCode();
+ $result['validation-info'][$key]['text'] =
$error->getText();
+ }
+ }
}
private function addParseErrorToResult( array &$result, ParseException
$parseError ) {
@@ -131,7 +208,7 @@
*
* @return ParserOptions
*/
- private function getOptionsObject( $optionsParam ) {
+ private function getParserOptionsObject( $optionsParam ) {
$parserOptions = new ParserOptions();
$parserOptions->setOption( ValueParser::OPT_LANG,
$this->getLanguage()->getCode() );
@@ -156,8 +233,12 @@
protected function getAllowedParams() {
return array(
'parser' => array(
- ApiBase::PARAM_TYPE =>
$this->getFactory()->getParserIds(),
+ ApiBase::PARAM_TYPE =>
$this->getParserFactory()->getParserIds(),
ApiBase::PARAM_REQUIRED => true,
+ ),
+ 'validator' => array(
+ ApiBase::PARAM_TYPE =>
$this->getValidatorFactory()->getValidatorIds(),
+ ApiBase::PARAM_REQUIRED => false,
),
'values' => array(
ApiBase::PARAM_TYPE => 'string',
@@ -176,8 +257,10 @@
*/
protected function getExamplesMessages() {
return array(
- 'action=wbparsevalue&parser=null&values=foo|bar' =>
'apihelp-wbparsevalue-example-1',
-
'action=wbparsevalue&parser=time&values=1994-02-08&options={"precision":9}' =>
'apihelp-wbparsevalue-example-2',
+ 'action=wbparsevalue&parser=null&values=foo|bar' =>
+ 'apihelp-wbparsevalue-example-1',
+
'action=wbparsevalue&parser=time&values=1994-02-08&options={"precision":9}' =>
+ 'apihelp-wbparsevalue-example-2',
);
}
diff --git a/repo/tests/phpunit/includes/api/ParseValueTest.php
b/repo/tests/phpunit/includes/api/ParseValueTest.php
index aedfc4f..bc9fa44 100644
--- a/repo/tests/phpunit/includes/api/ParseValueTest.php
+++ b/repo/tests/phpunit/includes/api/ParseValueTest.php
@@ -2,6 +2,8 @@
namespace Wikibase\Test\Api;
+use Wikibase\Validators\StringLengthValidator;
+
/**
* @covers Wikibase\Api\ParseValue
*
@@ -15,6 +17,7 @@
*
* @licence GNU GPL v2+
* @author Daniel Kinzler
+ * @author Adam Shorland
*/
class ParseValueTest extends WikibaseApiTestCase {
@@ -22,6 +25,17 @@
$this->mergeMwGlobalArrayValue(
'wgValueParsers',
array( 'decimal' => 'ValueParsers\DecimalParser' )
+ );
+ $this->mergeMwGlobalArrayValue(
+ 'wgValueValidators',
+ array(
+ 'stringLength6to8' => function() {
+ return new StringLengthValidator( 6, 8
);
+ },
+ 'stringLengthEqual1' => function() {
+ return new StringLengthValidator( 1, 1
);
+ },
+ )
);
parent::setUp();
}
@@ -110,6 +124,32 @@
),
),
+ 'decimal with string length (6-8) validation' => array(
+ '$text' => '123.456',
+ '$parser' => 'decimal',
+ '$expected' => array(
+ '0/raw' => '123.456',
+ '0/type' => 'decimal',
+ '0/value' => '123.456',
+ '0/valid' => true,
+ ),
+ '$validator' => 'stringLength6to8',
+ ),
+
+ 'decimal with string length (=1) validation' => array(
+ '$text' => '123.456',
+ '$parser' => 'decimal',
+ '$expected' => array(
+ '0/raw' => '123.456',
+ '0/type' => 'decimal',
+ '0/value' => '123.456',
+ '0/valid' => false,
+ '0/validation-info/0/code' =>
'too-long',
+ '0/validation-info/0/text' => 'Too
long, maximum length is 1',
+ ),
+ '$validator' => 'stringLengthEqual1',
+ ),
+
);
}
@@ -132,13 +172,17 @@
/**
* @dataProvider provideValid
*/
- public function testParse( $text, $parser, $expected ) {
+ public function testParse( $text, $parser, $expected, $validator = null
) {
$params = array(
'action' => 'wbparsevalue',
'values' => $text,
'parser' => $parser
);
+ if ( $validator !== null ) {
+ $params['validator'] = $validator;
+ }
+
list( $result, , ) = $this->doApiRequest( $params );
$this->assertArrayHasKey( 'results', $result );
--
To view, visit https://gerrit.wikimedia.org/r/222565
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia6bcd1e85f6867663457122d19310ca4d7e9af81
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Addshore <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits