Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.02% covered (success)
93.02%
40 / 43
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SingleBestValueChecker
93.02% covered (success)
93.02%
40 / 43
50.00% covered (danger)
50.00%
2 / 4
13.06
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
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
3
 checkConstraintParameters
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
2.15
 getViolationMessage
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
4.02
1<?php
2
3namespace WikibaseQuality\ConstraintReport\ConstraintCheck\Checker;
4
5use Wikibase\DataModel\Entity\PropertyId;
6use Wikibase\DataModel\Statement\Statement;
7use WikibaseQuality\ConstraintReport\Constraint;
8use WikibaseQuality\ConstraintReport\ConstraintCheck\ConstraintChecker;
9use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\Context;
10use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterException;
11use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterParser;
12use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ValueCountCheckerHelper;
13use WikibaseQuality\ConstraintReport\ConstraintCheck\Message\ViolationMessage;
14use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult;
15
16/**
17 * @author Lucas Werkmeister
18 * @license GPL-2.0-or-later
19 */
20class SingleBestValueChecker implements ConstraintChecker {
21
22    /**
23     * @var ConstraintParameterParser
24     */
25    private $constraintParameterParser;
26
27    /**
28     * @var ValueCountCheckerHelper
29     */
30    private $valueCountCheckerHelper;
31
32    public function __construct(
33        ConstraintParameterParser $constraintParameterParser
34    ) {
35        $this->constraintParameterParser = $constraintParameterParser;
36        $this->valueCountCheckerHelper = new ValueCountCheckerHelper();
37    }
38
39    /**
40     * @codeCoverageIgnore This method is purely declarative.
41     */
42    public function getSupportedContextTypes() {
43        return self::ALL_CONTEXT_TYPES_SUPPORTED;
44    }
45
46    /**
47     * @codeCoverageIgnore This method is purely declarative.
48     */
49    public function getDefaultContextTypes() {
50        return Context::ALL_CONTEXT_TYPES;
51    }
52
53    /** @codeCoverageIgnore This method is purely declarative. */
54    public function getSupportedEntityTypes() {
55        return self::ALL_ENTITY_TYPES_SUPPORTED;
56    }
57
58    /**
59     * Checks 'Single best value' constraint.
60     *
61     * @param Context $context
62     * @param Constraint $constraint
63     *
64     * @return CheckResult
65     */
66    public function checkConstraint( Context $context, Constraint $constraint ) {
67        if ( $context->getSnakRank() === Statement::RANK_DEPRECATED ) {
68            return new CheckResult( $context, $constraint, CheckResult::STATUS_DEPRECATED );
69        }
70
71        $separators = $this->constraintParameterParser->parseSeparatorsParameter(
72            $constraint->getConstraintParameters()
73        );
74
75        $propertyId = $context->getSnak()->getPropertyId();
76        $bestRankCount = $this->valueCountCheckerHelper->getPropertyCount(
77            $context->getSnakGroup( Context::GROUP_BEST_RANK, $separators ),
78            $propertyId
79        );
80
81        if ( $bestRankCount > 1 ) {
82            $nonDeprecatedCount = $this->valueCountCheckerHelper->getPropertyCount(
83                $context->getSnakGroup( Context::GROUP_NON_DEPRECATED ),
84                $propertyId
85            );
86            $message = $this->getViolationMessage(
87                $bestRankCount,
88                $nonDeprecatedCount,
89                $separators,
90                $propertyId
91            );
92            $status = CheckResult::STATUS_VIOLATION;
93        } else {
94            $message = null;
95            $status = CheckResult::STATUS_COMPLIANCE;
96        }
97
98        return new CheckResult( $context, $constraint, $status, $message );
99    }
100
101    public function checkConstraintParameters( Constraint $constraint ) {
102        $constraintParameters = $constraint->getConstraintParameters();
103        $exceptions = [];
104        try {
105            $this->constraintParameterParser->parseSeparatorsParameter( $constraintParameters );
106        } catch ( ConstraintParameterException $e ) {
107            $exceptions[] = $e;
108        }
109        return $exceptions;
110    }
111
112    /**
113     * @param int $bestRankCount
114     * @param int $nonDeprecatedCount
115     * @param PropertyId[] $separators
116     * @param PropertyId $propertyId
117     * @return ViolationMessage
118     */
119    private function getViolationMessage(
120        $bestRankCount,
121        $nonDeprecatedCount,
122        $separators,
123        $propertyId
124    ) {
125        if ( $bestRankCount === $nonDeprecatedCount ) {
126            if ( $separators === [] ) {
127                $messageKey = 'wbqc-violation-message-single-best-value-no-preferred';
128            } else {
129                $messageKey = 'wbqc-violation-message-single-best-value-no-preferred-separators';
130            }
131        } else {
132            if ( $separators === [] ) {
133                $messageKey = 'wbqc-violation-message-single-best-value-multi-preferred';
134            } else {
135                $messageKey = 'wbqc-violation-message-single-best-value-multi-preferred-separators';
136            }
137        }
138
139        return ( new ViolationMessage( $messageKey ) )
140            ->withEntityId( $propertyId )
141            ->withEntityIdList( $separators );
142    }
143
144}