Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.02% covered (success)
93.02%
40 / 43
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
UniqueValueChecker
93.02% covered (success)
93.02%
40 / 43
33.33% covered (danger)
33.33%
1 / 3
12.05
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getSupportedContextTypes
n/a
0 / 0
n/a
0 / 0
1
 getDefaultContextTypes
n/a
0 / 0
n/a
0 / 0
1
 getSupportedEntityTypes
n/a
0 / 0
n/a
0 / 0
1
 checkConstraint
97.14% covered (success)
97.14%
34 / 35
0.00% covered (danger)
0.00%
0 / 1
6
 checkConstraintParameters
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
2.15
1<?php
2
3declare( strict_types = 1 );
4
5namespace WikibaseQuality\ConstraintReport\ConstraintCheck\Checker;
6
7use Wikibase\DataModel\Entity\ItemId;
8use Wikibase\DataModel\Snak\PropertyValueSnak;
9use Wikibase\DataModel\Statement\Statement;
10use WikibaseQuality\ConstraintReport\Constraint;
11use WikibaseQuality\ConstraintReport\ConstraintCheck\Cache\Metadata;
12use WikibaseQuality\ConstraintReport\ConstraintCheck\ConstraintChecker;
13use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\Context;
14use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterException;
15use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterParser;
16use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\DummySparqlHelper;
17use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\SparqlHelper;
18use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\SparqlHelperException;
19use WikibaseQuality\ConstraintReport\ConstraintCheck\Message\ViolationMessage;
20use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult;
21use WikibaseQuality\ConstraintReport\Role;
22
23/**
24 * @author BP2014N1
25 * @license GPL-2.0-or-later
26 */
27class UniqueValueChecker implements ConstraintChecker {
28
29    private SparqlHelper $sparqlHelper;
30
31    private ConstraintParameterParser $constraintParameterParser;
32
33    public function __construct(
34        SparqlHelper $sparqlHelper,
35        ConstraintParameterParser $constraintParameterParser
36    ) {
37        $this->sparqlHelper = $sparqlHelper;
38        $this->constraintParameterParser = $constraintParameterParser;
39    }
40
41    /**
42     * @codeCoverageIgnore This method is purely declarative.
43     */
44    public function getSupportedContextTypes(): array {
45        return self::ALL_CONTEXT_TYPES_SUPPORTED;
46    }
47
48    /**
49     * @codeCoverageIgnore This method is purely declarative.
50     */
51    public function getDefaultContextTypes(): array {
52        return [
53            Context::TYPE_STATEMENT,
54        ];
55    }
56
57    /** @codeCoverageIgnore This method is purely declarative. */
58    public function getSupportedEntityTypes(): array {
59        return self::ALL_ENTITY_TYPES_SUPPORTED;
60    }
61
62    /**
63     * Checks 'Unique value' constraint.
64     *
65     * @throws SparqlHelperException if the checker uses SPARQL and the query times out or some other error occurs
66     */
67    public function checkConstraint( Context $context, Constraint $constraint ): CheckResult {
68        if ( $context->getSnakRank() === Statement::RANK_DEPRECATED ) {
69            return new CheckResult( $context, $constraint, CheckResult::STATUS_DEPRECATED );
70        }
71
72        if ( !( $this->sparqlHelper instanceof DummySparqlHelper ) ) {
73
74            $separators = $this->constraintParameterParser->parseSeparatorsParameter(
75                $constraint->getConstraintParameters()
76            );
77
78            if ( $context->getType() === 'statement' ) {
79                $statement = $context->getSnakStatement();
80                '@phan-var Statement $statement';
81                $result = $this->sparqlHelper->findEntitiesWithSameStatement(
82                    $statement,
83                    $separators
84                );
85            } else {
86                $snak = $context->getSnak();
87                if ( !$snak instanceof PropertyValueSnak ) {
88                    // nothing to check
89                    return new CheckResult( $context, $constraint, CheckResult::STATUS_COMPLIANCE );
90                }
91                $result = $this->sparqlHelper->findEntitiesWithSameQualifierOrReference(
92                    $context->getEntity()->getId(),
93                    $snak,
94                    $context->getType(),
95                    // ignore qualifiers of deprecated statements but still check their references
96                    $context->getType() === 'qualifier'
97                );
98            }
99            $otherEntities = $result->getArray();
100            $metadata = $result->getMetadata();
101
102            if ( $otherEntities === [] ) {
103                $status = CheckResult::STATUS_COMPLIANCE;
104                $message = null;
105            } else {
106                $status = CheckResult::STATUS_VIOLATION;
107                $message = ( new ViolationMessage( 'wbqc-violation-message-unique-value' ) )
108                    ->withEntityIdList( $otherEntities, Role::SUBJECT );
109            }
110        } else {
111            $status = CheckResult::STATUS_TODO;
112            $message = ( new ViolationMessage( 'wbqc-violation-message-not-yet-implemented' ) )
113                ->withEntityId( new ItemId( $constraint->getConstraintTypeItemId() ), Role::CONSTRAINT_TYPE_ITEM );
114            $metadata = Metadata::blank();
115        }
116
117        return ( new CheckResult( $context, $constraint, $status, $message ) )
118            ->withMetadata( $metadata );
119    }
120
121    public function checkConstraintParameters( Constraint $constraint ): array {
122        $constraintParameters = $constraint->getConstraintParameters();
123        $exceptions = [];
124        try {
125            $this->constraintParameterParser->parseSeparatorsParameter( $constraintParameters );
126        } catch ( ConstraintParameterException $e ) {
127            $exceptions[] = $e;
128        }
129        return $exceptions;
130    }
131
132}