WikidataBuilder has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/381526 )
Change subject: New Wikidata Build - 2017-09-30T10:00:02+0000 ...................................................................... New Wikidata Build - 2017-09-30T10:00:02+0000 Change-Id: Ia73eb3a326437b3bd906acb53297c8090e395c3c --- M Wikidata.localisation.php M Wikidata.php M composer.lock M extensions/Constraints/README.md M extensions/Constraints/extension.json M extensions/Constraints/i18n/en.json M extensions/Constraints/i18n/qqq.json A extensions/Constraints/includes/ConstraintCheck/Checker/ValueOnlyChecker.php M extensions/Constraints/includes/ConstraintCheck/DelegatingConstraintChecker.php M extensions/Constraints/includes/ConstraintReportFactory.php M extensions/Constraints/tests/phpunit/Api/CheckConstraintsTest.php A extensions/Constraints/tests/phpunit/Checker/ValueOnlyCheckerTest.php M extensions/Wikibase/client/WikibaseClient.php M extensions/Wikibase/lib/includes/Formatters/EntityIdHtmlLinkFormatter.php M vendor/composer/autoload_classmap.php M vendor/composer/autoload_static.php M vendor/composer/installed.json 17 files changed, 410 insertions(+), 78 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikidata refs/changes/26/381526/1 diff --git a/Wikidata.localisation.php b/Wikidata.localisation.php index e1cad1c..e166629 100644 --- a/Wikidata.localisation.php +++ b/Wikidata.localisation.php @@ -4,10 +4,6 @@ die( 'Not an entry point.' ); } -// no magic, use wmf configs instead to control which entry points to load -$wgEnableWikibaseRepo = false; -$wgEnableWikibaseClient = false; - $wgWikidataBaseDir = $IP; if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) { diff --git a/Wikidata.php b/Wikidata.php index dcb4143..b96b27c 100755 --- a/Wikidata.php +++ b/Wikidata.php @@ -12,10 +12,6 @@ $wmgUseArticlePlaceholder = true; } -// no magic, use wmf configs instead to control which entry points to load -$wgEnableWikibaseRepo = false; -$wgEnableWikibaseClient = false; - $wgWikidataBaseDir = $IP; if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) { diff --git a/composer.lock b/composer.lock index 4612f5e..79c8573 100644 --- a/composer.lock +++ b/composer.lock @@ -977,7 +977,7 @@ "source": { "type": "git", "url": "https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQualityConstraints", - "reference": "0a46d56c378cd40d15bc4e0e479f1588261648b1" + "reference": "0d4d91f03dafd535e231900ae510c92634682b3e" }, "require": { "php": ">=5.5.9", @@ -1037,7 +1037,7 @@ "support": { "issues": "https://phabricator.wikimedia.org/project/profile/1202/" }, - "time": "2017-09-29 09:37:36" + "time": "2017-09-29 10:04:34" }, { "name": "wikibase/data-model", @@ -1548,12 +1548,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "79f95b564f54ae5499e665a75ffa24860abb9f4b" + "reference": "151dde0e4154467a0195a468ef2468daed1c88ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/79f95b564f54ae5499e665a75ffa24860abb9f4b", - "reference": "79f95b564f54ae5499e665a75ffa24860abb9f4b", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/151dde0e4154467a0195a468ef2468daed1c88ee", + "reference": "151dde0e4154467a0195a468ef2468daed1c88ee", "shasum": "" }, "require": { @@ -1631,7 +1631,7 @@ "wikibaserepo", "wikidata" ], - "time": "2017-09-29 09:36:10" + "time": "2017-09-29 15:47:38" }, { "name": "wikibase/wikimedia-badges", diff --git a/extensions/Constraints/README.md b/extensions/Constraints/README.md index 5ff3655..099b55a 100644 --- a/extensions/Constraints/README.md +++ b/extensions/Constraints/README.md @@ -146,3 +146,94 @@ This runs the tests without coverage report and is therefore much faster. + +### Adding a new constraint type + +To add a new constraint type, the following steps are necessary: + +* Define the constraint checker class. + * It should be defined in a new file in `includes/ConstraintCheck/Checker/`, + named after the class name. + It should be in the `WikibaseQuality\ConstraintReport\ConstraintCheck\Checker` namespace. + * The class name should follow the constraint type name (in English), ending in “Checker”. + * The class must implement the `ConstraintChecker` interface. + * It should have at least the following class-level documentation comment: + ```php + /** + * @package WikibaseQuality\ConstraintReport\ConstraintCheck\Checker + * @author YOUR NAME HERE + * @license GNU GPL v2+ + */ + ``` + * Any services you need (`Config`, `EntityLookup`, …) should be injected as constructor parameters. + * If the constraint has parameters, + add support for parsing them to `ConstraintParameterParser` + (add a config setting for the associated property in `extension.json` + and a method to parse the parameter in `ConstraintParameterParser`), + and then add tests for them in `ConstraintParameterParserTest`. + This should be done in a separate commit. +* Define new messages (at least a violation message for the constraint type). + * Define the message in `i18n/en.json`. + A violation message should have a key like `wbqc-violation-message-constraintType`. + * Document the message in `i18n/qqq.json`. + Use the same message key, + and insert the documentation in the same location where you also added the message in `en.json` + (that is, `en.json` and `qqq.json` should contain message keys in the same order). +* Add a configuration setting for the constraint type item ID. + * Configuration settings are defined in `extension.json`, + as members of the `config` object. + * It should be added right after the current last `…ConstraintId` entry. + * It should be named after the constraint type item’s English label, + following the pattern `WBQualityConstraints___ConstraintId`. + * The default value should be the item ID on Wikidata, + so that no extra configuration is required for Wikidata + and importing the constraint type item (see “Data import” section) works. + * The first part of the description can be copied from similar settings, + the rest should contain a short description of the constraint type. + * The ID can always be public (`"public": true`). +* Configure the constraint type checker in `ConstraintReportFactory`. + * Add an array entry like + ```php + $this->config->get( 'WBQualityConstraints___ConstraintId' ) + => new ___Checker( + // injected services + ), + ``` + at the end of the `getConstraintCheckerMap()` function. +* Add tests for the new constraint checker. + * The test class name should be the same as the checker class name, + with an additional suffix `Test` (i. e., `…CheckerTest`). + * The test class should be placed somewhere in `tests/phpunit/Checker/`, + either in the most suitable subdirectory + or directly in that directory if none of the subdirectories are suitable. + (The division into subdirectories there is dubious anyways, + and we may get rid of it in the future.) + * It should have at least the following class-level documentation comment: + ```php + /** + * @covers \WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\___Checker + * + * @group WikibaseQualityConstraints + * + * @uses \WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult + * + * @author YOUR NAME HERE + * @license GNU GPL v2+ + */ + ``` + * It should have at least one test for compliance with a constraint, + one test for a constraint violation, + one test for behavior on a deprecated statement, + and one test for the `checkConstraintParameters` method. + * Use the `ResultAssertions` trait’s methods to check constraint check results. + * Use the `NewItem` and `NewStatement` builders to construct test data. + (You might see `JsonFileEntityLookup` and separate JSON files used in some existing tests, + but that’s a lot less readable.) + * If the checker uses a `Config`, use the `DefaultConfig` trait. + * If the constraint has parameters, + add methods for them to the `ConstraintParameterns` trait and use it in the tests. + * You can copy+paste a `getConstraintMock` function from one of the existing tests, + adjusting the `getConstraintTypeItemId` mocked return value. + (Hopefully we’ll improve this in the future.) + +An example commit that performs all of these steps is [Change Id45d80e7a0](https://gerrit.wikimedia.org/r/381005). diff --git a/extensions/Constraints/extension.json b/extensions/Constraints/extension.json index f48a3f0..e550c7a 100644 --- a/extensions/Constraints/extension.json +++ b/extensions/Constraints/extension.json @@ -121,6 +121,16 @@ "description": "Whether to use the new API output format, based on the Wikibase entity JSON format, which can accommodate constraint results on qualifiers and references.", "public": true }, + "WBQualityConstraintsCheckQualifiers": { + "value": false, + "description": "Whether to check constraints on qualifiers. Requires the new API output format (otherwise ignored).", + "public": true + }, + "WBQualityConstraintsCheckReferences": { + "value": false, + "description": "Whether to check constraints on references. Requires the new API output format (otherwise ignored).", + "public": true + }, "WBQualityConstraintsSparqlEndpoint": { "value": "", "description": "The URL of the SPARQL endpoint. Should accept the URL parameters 'query', 'format' and 'maxQueryTimeMillis'. Set to '' (empty string, default) to disable SPARQL functionality.", @@ -269,6 +279,11 @@ "description": "The item ID of the 'format constraint' item, which, when used in a 'property constraint' statement on a property, indicates that the value of a given statement should conform to a given pattern.", "public": true }, + "WBQualityConstraintsUsedForValuesOnlyConstraintId": { + "value": "Q21528958", + "description": "The item ID of the 'used for values only constraint' item, which, when used in a 'property constraint' statement on a property, indicates that the property should only be used for the main value of a statement, not for qualifiers or references.", + "public": true + }, "WBQualityConstraintsClassId": { "value": "P2308", "description": "The property ID of the 'relation' property (data type: item), which specifies the class/type of a 'type' or 'value type' constraint.", diff --git a/extensions/Constraints/i18n/en.json b/extensions/Constraints/i18n/en.json index 2b9c2cf..265731a 100644 --- a/extensions/Constraints/i18n/en.json +++ b/extensions/Constraints/i18n/en.json @@ -124,6 +124,7 @@ "wbqc-violation-message-valueType-subclass": "Values of $1 statements should be subclasses of {{PLURAL:$3|1=$5|2=$5 or $6|one of the following classes}} (or of {{PLURAL:$3|1=a subclass of it|2=a subclass of them|one of their subclasses}}), but $2 currently {{PLURAL:$3|1=isn't.|2=isn't.|isn't: $4}}", "wbqc-violation-message-target-required-claim": "$1 should have {{PLURAL:$3|0=a statement $2.|1=a statement $2 $5.|a statement for $2 with one of the following values:$4}}", "wbqc-violation-message-unique-value": "This property's value must not be present on any other item, but is also present on {{PLURAL:$1|1=$3.|2=$3 and $4.|the following items: $2}}", + "wbqc-violation-message-valueOnly": "This property should only be used for the main value of a statement, not for qualifiers or references.", "wbqc-exception-message": "This entity is a known exception for this constraint and has been marked as such." } diff --git a/extensions/Constraints/i18n/qqq.json b/extensions/Constraints/i18n/qqq.json index f31c8b1..3d169ce 100644 --- a/extensions/Constraints/i18n/qqq.json +++ b/extensions/Constraints/i18n/qqq.json @@ -120,5 +120,6 @@ "wbqc-violation-message-valueType-subclass": "Message for a violation of the “Value type” constraint, when the value of a statement should have be a subclass of a certain type but isn't. $1 is the property of the statement, $2 is the value of the statement, $3 is the number of classes, $4 is an HTML list of all classes, and $5, $6 etc. are the individual classes.\n{{Related|wbqc-violation-message-valueType-instance}}", "wbqc-violation-message-target-required-claim": "Message for a violation of the “Target required claim” constraint, when the target entity of a statement is missing an expected statement. Parameters:\n* $1 is the subject entity of the missing statement, i. e. the target entity of the statement that has the constraint.\n* $2 is the property of the missing statement.\n* $3 is the number of values permitted for the missing statement (or 0, in which case the constraint only specifies that there should be a statement but not the values it should have).\n* $4 is an HTML list of all values permitted for the missing statement.\n* $5, $6 etc. are the individual values permitted for the missing statement.\n{{Related|wbqc-violation-message-item}}", "wbqc-violation-message-unique-value": "Message for violation of the Unique Value constraint, when other items are found. Parameters:\n* $1 is the number of other items with the same value.\n* $2 is an HTML list of all other items found with the same value.\n* $3, $4 etc. are the individual other items with the same value.", + "wbqc-violation-message-valueOnly": "Message for a violation of the “used for values only” constraint, when a property intended for the main value only was used in a qualifier or reference.", "wbqc-exception-message": "Message for a constraint check result on an entity that has been marked as an exception to the constraint. This message only appears on [[Special:ConstraintReport]]; the gadget does not show exception reports." } diff --git a/extensions/Constraints/includes/ConstraintCheck/Checker/ValueOnlyChecker.php b/extensions/Constraints/includes/ConstraintCheck/Checker/ValueOnlyChecker.php new file mode 100644 index 0000000..03c8adf --- /dev/null +++ b/extensions/Constraints/includes/ConstraintCheck/Checker/ValueOnlyChecker.php @@ -0,0 +1,31 @@ +<?php + +namespace WikibaseQuality\ConstraintReport\ConstraintCheck\Checker; + +use WikibaseQuality\ConstraintReport\Constraint; +use WikibaseQuality\ConstraintReport\ConstraintCheck\ConstraintChecker; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\Context; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult; + +/** + * @package WikibaseQuality\ConstraintReport\ConstraintCheck\Checker + * @author Lucas Werkmeister + * @license GNU GPL v2+ + */ +class ValueOnlyChecker implements ConstraintChecker { + + public function checkConstraint( Context $context, Constraint $constraint ) { + if ( $context->getType() === Context::TYPE_STATEMENT ) { + return new CheckResult( $context, $constraint, [], CheckResult::STATUS_COMPLIANCE, '' ); + } else { + $message = wfMessage( 'wbqc-violation-message-valueOnly' )->escaped(); + return new CheckResult( $context, $constraint, [], CheckResult::STATUS_VIOLATION, $message ); + } + } + + public function checkConstraintParameters( Constraint $constraint ) { + // no parameters + return []; + } + +} diff --git a/extensions/Constraints/includes/ConstraintCheck/DelegatingConstraintChecker.php b/extensions/Constraints/includes/ConstraintCheck/DelegatingConstraintChecker.php index 7514830..887fc1c 100644 --- a/extensions/Constraints/includes/ConstraintCheck/DelegatingConstraintChecker.php +++ b/extensions/Constraints/includes/ConstraintCheck/DelegatingConstraintChecker.php @@ -13,6 +13,8 @@ use Wikibase\DataModel\Statement\StatementListProvider; use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\Context; use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\MainSnakContext; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\QualifierContext; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\ReferenceContext; use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\StatementContext; use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterException; use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterParser; @@ -71,6 +73,16 @@ private $apiV2; /** + * @var bool + */ + private $checkQualifiers; + + /** + * @var bool + */ + private $checkReferences; + + /** * @param EntityLookup $lookup * @param ConstraintChecker[] $checkerMap * @param ConstraintLookup $constraintRepository @@ -78,6 +90,8 @@ * @param StatementGuidParser $statementGuidParser * @param LoggingHelper $loggingHelper * @param bool $apiV2 whether to use the new API output format + * @param bool $checkQualifiers whether to check qualifiers + * @param bool $checkReferences whether to check references */ public function __construct( EntityLookup $lookup, @@ -86,7 +100,9 @@ ConstraintParameterParser $constraintParameterParser, StatementGuidParser $statementGuidParser, LoggingHelper $loggingHelper, - $apiV2 + $apiV2, + $checkQualifiers, + $checkReferences ) { $this->entityLookup = $lookup; $this->checkerMap = $checkerMap; @@ -95,6 +111,8 @@ $this->statementGuidParser = $statementGuidParser; $this->loggingHelper = $loggingHelper; $this->apiV2 = $apiV2; + $this->checkQualifiers = $apiV2 && $checkQualifiers; + $this->checkReferences = $apiV2 && $checkReferences; } /** @@ -254,9 +272,33 @@ private function checkStatement( EntityDocument $entity, Statement $statement, $constraintIds = null ) { $result = []; - $constraints = $this->constraintLookup->queryConstraintsForProperty( - $statement->getPropertyId() - ); + $result = array_merge( $result, + $this->checkConstraintsForMainSnak( $entity, $statement, $constraintIds ) ); + + if ( $this->checkQualifiers ) { + $result = array_merge( $result, + $this->checkConstraintsForQualifiers( $entity, $statement, $constraintIds ) ); + } + + if ( $this->checkReferences ) { + $result = array_merge( $result, + $this->checkConstraintsForReferences( $entity, $statement, $constraintIds ) ); + } + + return $result; + } + + /** + * Get the constraints to actually check for a given property ID. + * If $constraintIds is not null, only check constraints with those constraint IDs, + * otherwise check all constraints for that property. + * + * @param PropertyId $propertyId + * @param string[]|null $constraintIds + * @return Constraint[] + */ + private function getConstraintsToUse( PropertyId $propertyId, array $constraintIds = null ) { + $constraints = $this->constraintLookup->queryConstraintsForProperty( $propertyId ); if ( $constraintIds !== null ) { $constraintsToUse = []; foreach ( $constraints as $constraint ) { @@ -264,30 +306,31 @@ $constraintsToUse[] = $constraint; } } + return $constraintsToUse; } else { - $constraintsToUse = $constraints; + return $constraints; } - $result = array_merge( - $result, - $this->checkConstraintsForStatementOnEntity( $constraintsToUse, $entity, $statement ) - ); - - return $result; } /** - * @param Constraint[] $constraints - * @param EntityDocument|StatementListProvider $entity + * @param EntityDocument $entity * @param Statement $statement - * + * @param string[]|null $constraintIds list of constraints to check (if null: all constraints) * @return CheckResult[] */ - private function checkConstraintsForStatementOnEntity( array $constraints, EntityDocument $entity, $statement ) { - $entityId = $entity->getId(); + private function checkConstraintsForMainSnak( + EntityDocument $entity, + Statement $statement, + array $constraintIds = null + ) { $result = []; $context = $this->apiV2 ? new MainSnakContext( $entity, $statement ) : new StatementContext( $entity, $statement ); + $constraints = $this->getConstraintsToUse( + $statement->getPropertyId(), + $constraintIds + ); foreach ( $constraints as $constraint ) { $parameters = $constraint->getConstraintParameters(); @@ -298,13 +341,74 @@ continue; } - if ( in_array( $entityId, $exceptions ) ) { + if ( in_array( $entity->getId(), $exceptions ) ) { $message = wfMessage( 'wbqc-exception-message' )->escaped(); $result[] = new CheckResult( $context, $constraint, [], CheckResult::STATUS_EXCEPTION, $message ); continue; } - $result[ ] = $this->getCheckResultFor( $context, $constraint ); + $result[] = $this->getCheckResultFor( $context, $constraint ); + } + + return $result; + } + + /** + * @param EntityDocument $entity + * @param Statement $statement + * @param string[]|null $constraintIds list of constraints to check (if null: all constraints) + * @return CheckResult[] + */ + private function checkConstraintsForQualifiers( + EntityDocument $entity, + Statement $statement, + array $constraintIds = null + ) { + $result = []; + + foreach ( $statement->getQualifiers() as $qualifier ) { + $qualifierContext = new QualifierContext( $entity, $statement, $qualifier ); + $qualifierConstraints = $this->getConstraintsToUse( + $qualifierContext->getSnak()->getPropertyId(), + $constraintIds + ); + foreach ( $qualifierConstraints as $qualifierConstraint ) { + $result[] = $this->getCheckResultFor( $qualifierContext, $qualifierConstraint ); + } + } + + return $result; + } + + /** + * @param EntityDocument $entity + * @param Statement $statement + * @param string[]|null $constraintIds list of constraints to check (if null: all constraints) + * @return CheckResult[] + */ + private function checkConstraintsForReferences( + EntityDocument $entity, + Statement $statement, + array $constraintIds = null + ) { + $result = []; + + foreach ( $statement->getReferences() as $reference ) { + foreach ( $reference->getSnaks() as $snak ) { + $referenceContext = new ReferenceContext( + $entity, $statement, $reference, $snak + ); + $referenceConstraints = $this->getConstraintsToUse( + $referenceContext->getSnak()->getPropertyId(), + $constraintIds + ); + foreach ( $referenceConstraints as $referenceConstraint ) { + $result[] = $this->getCheckResultFor( + $referenceContext, + $referenceConstraint + ); + } + } } return $result; diff --git a/extensions/Constraints/includes/ConstraintReportFactory.php b/extensions/Constraints/includes/ConstraintReportFactory.php index dfe82d5..7750506 100644 --- a/extensions/Constraints/includes/ConstraintReportFactory.php +++ b/extensions/Constraints/includes/ConstraintReportFactory.php @@ -35,6 +35,7 @@ use WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\SingleValueChecker; use WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\MultiValueChecker; use WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\UniqueValueChecker; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\ValueOnlyChecker; use WikibaseQuality\ConstraintReport\ConstraintCheck\ConstraintChecker; use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConnectionCheckerHelper; use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\LoggingHelper; @@ -193,7 +194,9 @@ LoggerFactory::getInstance( 'WikibaseQualityConstraints' ), $this->config ), - $this->config->get( 'WBQualityConstraintsNewApiOutputFormat' ) + $this->config->get( 'WBQualityConstraintsNewApiOutputFormat' ), + $this->config->get( 'WBQualityConstraintsCheckQualifiers' ), + $this->config->get( 'WBQualityConstraintsCheckReferences' ) ); } @@ -326,6 +329,8 @@ $this->constraintParameterParser, $this->constraintParameterRenderer ), + $this->config->get( 'WBQualityConstraintsUsedForValuesOnlyConstraintId' ) + => new ValueOnlyChecker(), ]; } diff --git a/extensions/Constraints/tests/phpunit/Api/CheckConstraintsTest.php b/extensions/Constraints/tests/phpunit/Api/CheckConstraintsTest.php index a59d405..63cf1a9 100644 --- a/extensions/Constraints/tests/phpunit/Api/CheckConstraintsTest.php +++ b/extensions/Constraints/tests/phpunit/Api/CheckConstraintsTest.php @@ -131,6 +131,8 @@ LoggerFactory::getInstance( 'WikibaseQualityConstraints' ), $config ), + false, + false, false ); diff --git a/extensions/Constraints/tests/phpunit/Checker/ValueOnlyCheckerTest.php b/extensions/Constraints/tests/phpunit/Checker/ValueOnlyCheckerTest.php new file mode 100644 index 0000000..56c43d5 --- /dev/null +++ b/extensions/Constraints/tests/phpunit/Checker/ValueOnlyCheckerTest.php @@ -0,0 +1,97 @@ +<?php + +namespace WikibaseQuality\ConstraintReport\Test; + +use Wikibase\Repo\Tests\NewItem; +use Wikibase\Repo\Tests\NewStatement; +use WikibaseQuality\ConstraintReport\Constraint; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\ValueOnlyChecker; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\Context; +use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\StatementContext; +use WikibaseQuality\ConstraintReport\Tests\ResultAssertions; + +/** + * @covers \WikibaseQuality\ConstraintReport\ConstraintCheck\Checker\ValueOnlyChecker + * + * @group WikibaseQualityConstraints + * + * @uses \WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult + * + * @author Lucas Werkmeister + * @license GNU GPL v2+ + */ +class ValueOnlyCheckerTest extends \PHPUnit_Framework_TestCase { + + use ResultAssertions; + + /** + * @param string $type context type + * @param string|null $messageKey key of violation message, or null if compliance is expected + * @dataProvider contextTypes + */ + public function testQualifierConstraint( $type, $messageKey ) { + $context = $this->getMock( Context::class ); + $context->method( 'getType' )->willReturn( $type ); + $checker = new ValueOnlyChecker(); + $constraint = $this->getConstraintMock( [] ); + + $checkResult = $checker->checkConstraint( $context, $constraint ); + + if ( $messageKey === null ) { + $this->assertCompliance( $checkResult ); + } else { + $this->assertViolation( $checkResult, $messageKey ); + } + } + + public function contextTypes() { + return [ + [ Context::TYPE_STATEMENT, null ], + [ Context::TYPE_QUALIFIER, 'wbqc-violation-message-valueOnly' ], + [ Context::TYPE_REFERENCE, 'wbqc-violation-message-valueOnly' ], + ]; + } + + public function testQualifierConstraintDeprecatedStatement() { + $checker = new ValueOnlyChecker(); + $statement = NewStatement::noValueFor( 'P1' ) + ->withDeprecatedRank() + ->build(); + $constraint = $this->getConstraintMock( [] ); + $entity = NewItem::withId( 'Q1' ) + ->build(); + + $checkResult = $checker->checkConstraint( new StatementContext( $entity, $statement ), $constraint ); + + // this constraint is still checked on deprecated statements + $this->assertCompliance( $checkResult ); + } + + public function testCheckConstraintParameters() { + $checker = new ValueOnlyChecker(); + $constraint = $this->getConstraintMock( [] ); + + $result = $checker->checkConstraintParameters( $constraint ); + + $this->assertCount( 0, $result ); + } + + /** + * @return Constraint + */ + private function getConstraintMock() { + $mock = $this + ->getMockBuilder( Constraint::class ) + ->disableOriginalConstructor() + ->getMock(); + $mock->expects( $this->any() ) + ->method( 'getConstraintParameters' ) + ->will( $this->returnValue( [] ) ); + $mock->expects( $this->any() ) + ->method( 'getConstraintTypeItemId' ) + ->will( $this->returnValue( 'ValueOnly' ) ); + + return $mock; + } + +} diff --git a/extensions/Wikibase/client/WikibaseClient.php b/extensions/Wikibase/client/WikibaseClient.php index baf0bec..cae926c 100644 --- a/extensions/Wikibase/client/WikibaseClient.php +++ b/extensions/Wikibase/client/WikibaseClient.php @@ -70,6 +70,7 @@ global $wgAPIListModules, $wgAPIMetaModules, $wgAPIPropModules, + $wgAPIUselessQueryPages, $wgExtensionCredits, $wgExtensionFunctions, $wgExtensionMessagesFiles, @@ -267,6 +268,7 @@ ); } ]; + $wgAPIUselessQueryPages[] = 'PagesWithBadges'; // Special page registration $wgSpecialPages['UnconnectedPages'] = Wikibase\Client\Specials\SpecialUnconnectedPages::class; diff --git a/extensions/Wikibase/lib/includes/Formatters/EntityIdHtmlLinkFormatter.php b/extensions/Wikibase/lib/includes/Formatters/EntityIdHtmlLinkFormatter.php index 2377f1b..2066f6c 100644 --- a/extensions/Wikibase/lib/includes/Formatters/EntityIdHtmlLinkFormatter.php +++ b/extensions/Wikibase/lib/includes/Formatters/EntityIdHtmlLinkFormatter.php @@ -3,6 +3,7 @@ namespace Wikibase\Lib; use Html; +use Title; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Services\EntityId\EntityIdLabelFormatter; use Wikibase\DataModel\Services\Lookup\LabelDescriptionLookup; @@ -20,14 +21,14 @@ class EntityIdHtmlLinkFormatter extends EntityIdLabelFormatter { /** - * @var LanguageFallbackIndicator - */ - private $languageFallbackIndicator; - - /** * @var EntityTitleLookup */ protected $entityTitleLookup; + + /** + * @var LanguageFallbackIndicator + */ + private $languageFallbackIndicator; public function __construct( LabelDescriptionLookup $labelDescriptionLookup, @@ -56,60 +57,48 @@ $term = $this->lookupEntityLabel( $entityId ); - $url = $title->isLocal() ? $title->getLocalURL() : $title->getFullURL(); - $isRedirect = $title->isLocal() && $title->isRedirect(); - - if ( $term ) { - return $this->getHtmlForTerm( $url, $term, $title->getPrefixedText(), $isRedirect ); + // We can skip the expensive exists() check if we found a term. + if ( $term !== null ) { + $label = $term->getText(); } elseif ( $title->isLocal() && !$title->exists() ) { return $this->getHtmlForNonExistent( $entityId ); + } else { + $label = $entityId->getSerialization(); } - $attributes = [ - 'title' => $title->getPrefixedText(), - 'href' => $url - ]; - if ( $isRedirect ) { - $attributes['class'] = 'mw-redirect'; - } + $html = Html::element( 'a', $this->getAttributes( $title, $term ), $label ); - $html = Html::element( 'a', $attributes, $entityId->getSerialization() ); + if ( $term instanceof TermFallback ) { + $html .= $this->languageFallbackIndicator->getHtml( $term ); + } return $html; } /** - * @param string $targetUrl - * @param Term $term - * @param string $titleText - * @param bool $isRedirect + * @param Title $title + * @param Term|null $term * - * @return string HTML + * @return string[] */ - private function getHtmlForTerm( $targetUrl, Term $term, $titleText = '', $isRedirect = false ) { - $fallbackIndicatorHtml = ''; - + private function getAttributes( Title $title, Term $term = null ) { $attributes = [ - 'title' => $titleText, - 'href' => $targetUrl + 'title' => $title->getPrefixedText(), + 'href' => $title->isLocal() ? $title->getLocalURL() : $title->getFullURL() ]; - if ( $term instanceof TermFallback ) { - $fallbackIndicatorHtml = $this->languageFallbackIndicator->getHtml( $term ); - - if ( $term->getActualLanguageCode() !== $term->getLanguageCode() ) { - $attributes['lang'] = $term->getActualLanguageCode(); - //TODO: mark as rtl/ltr if appropriate. - } + if ( $term instanceof TermFallback + && $term->getActualLanguageCode() !== $term->getLanguageCode() + ) { + $attributes['lang'] = $term->getActualLanguageCode(); + // TODO: Mark as RTL/LTR if appropriate. } - if ( $isRedirect ) { + if ( $title->isLocal() && $title->isRedirect() ) { $attributes['class'] = 'mw-redirect'; } - $html = Html::element( 'a', $attributes, $term->getText() ); - - return $html . $fallbackIndicatorHtml; + return $attributes; } /** diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index fd16fec..3a442e1 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -270,6 +270,7 @@ 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\TargetRequiredClaimChecker' => $baseDir . '/extensions/Constraints/includes/ConstraintCheck/Checker/TargetRequiredClaimChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\TypeChecker' => $baseDir . '/extensions/Constraints/includes/ConstraintCheck/Checker/TypeChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\UniqueValueChecker' => $baseDir . '/extensions/Constraints/includes/ConstraintCheck/Checker/UniqueValueChecker.php', + 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\ValueOnlyChecker' => $baseDir . '/extensions/Constraints/includes/ConstraintCheck/Checker/ValueOnlyChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\ValueTypeChecker' => $baseDir . '/extensions/Constraints/includes/ConstraintCheck/Checker/ValueTypeChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\ConstraintChecker' => $baseDir . '/extensions/Constraints/includes/ConstraintCheck/ConstraintChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Context\\AbstractContext' => $baseDir . '/extensions/Constraints/includes/ConstraintCheck/Context/AbstractContext.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 1011b6d..6ccb2b1 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -574,6 +574,7 @@ 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\TargetRequiredClaimChecker' => __DIR__ . '/../..' . '/extensions/Constraints/includes/ConstraintCheck/Checker/TargetRequiredClaimChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\TypeChecker' => __DIR__ . '/../..' . '/extensions/Constraints/includes/ConstraintCheck/Checker/TypeChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\UniqueValueChecker' => __DIR__ . '/../..' . '/extensions/Constraints/includes/ConstraintCheck/Checker/UniqueValueChecker.php', + 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\ValueOnlyChecker' => __DIR__ . '/../..' . '/extensions/Constraints/includes/ConstraintCheck/Checker/ValueOnlyChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Checker\\ValueTypeChecker' => __DIR__ . '/../..' . '/extensions/Constraints/includes/ConstraintCheck/Checker/ValueTypeChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\ConstraintChecker' => __DIR__ . '/../..' . '/extensions/Constraints/includes/ConstraintCheck/ConstraintChecker.php', 'WikibaseQuality\\ConstraintReport\\ConstraintCheck\\Context\\AbstractContext' => __DIR__ . '/../..' . '/extensions/Constraints/includes/ConstraintCheck/Context/AbstractContext.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 16b4245..8f580d7 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1389,12 +1389,12 @@ "source": { "type": "git", "url": "https://github.com/wikimedia/mediawiki-extensions-Wikibase.git", - "reference": "79f95b564f54ae5499e665a75ffa24860abb9f4b" + "reference": "151dde0e4154467a0195a468ef2468daed1c88ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/79f95b564f54ae5499e665a75ffa24860abb9f4b", - "reference": "79f95b564f54ae5499e665a75ffa24860abb9f4b", + "url": "https://api.github.com/repos/wikimedia/mediawiki-extensions-Wikibase/zipball/151dde0e4154467a0195a468ef2468daed1c88ee", + "reference": "151dde0e4154467a0195a468ef2468daed1c88ee", "shasum": "" }, "require": { @@ -1429,7 +1429,7 @@ "mediawiki/minus-x": "0.1.0", "wikibase/wikibase-codesniffer": "^0.1.0" }, - "time": "2017-09-29 09:36:10", + "time": "2017-09-29 15:47:38", "type": "mediawiki-extension", "installation-source": "dist", "autoload": { @@ -1780,7 +1780,7 @@ "source": { "type": "git", "url": "https://gerrit.wikimedia.org/r/mediawiki/extensions/WikibaseQualityConstraints", - "reference": "0a46d56c378cd40d15bc4e0e479f1588261648b1" + "reference": "0d4d91f03dafd535e231900ae510c92634682b3e" }, "require": { "php": ">=5.5.9", @@ -1796,7 +1796,7 @@ "satooshi/php-coveralls": "master-dev", "wikibase/wikibase-codesniffer": "^0.1.0" }, - "time": "2017-09-29 09:37:36", + "time": "2017-09-29 10:04:34", "type": "mediawiki-extension", "installation-source": "source", "autoload": { -- To view, visit https://gerrit.wikimedia.org/r/381526 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ia73eb3a326437b3bd906acb53297c8090e395c3c Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikidata Gerrit-Branch: master Gerrit-Owner: WikidataBuilder <wikidata-servi...@wikimedia.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits