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