Completed
Push — master ( 57d748...8786f4 )
by
unknown
02:30
created

RangeChecker::checkConstraintParameters()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 17
Code Lines 12

Duplication

Lines 17
Ratio 100 %

Importance

Changes 0
Metric Value
dl 17
loc 17
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 12
nc 3
nop 1
1
<?php
2
3
namespace WikibaseQuality\ConstraintReport\ConstraintCheck\Checker;
4
5
use DataValues\DataValue;
6
use Wikibase\DataModel\Entity\PropertyId;
7
use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup;
8
use Wikibase\DataModel\Snak\PropertyValueSnak;
9
use WikibaseQuality\ConstraintReport\Constraint;
10
use WikibaseQuality\ConstraintReport\ConstraintCheck\ConstraintChecker;
11
use WikibaseQuality\ConstraintReport\ConstraintCheck\Context\Context;
12
use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterException;
13
use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\ConstraintParameterParser;
14
use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\NowValue;
15
use WikibaseQuality\ConstraintReport\ConstraintCheck\Helper\RangeCheckerHelper;
16
use WikibaseQuality\ConstraintReport\ConstraintCheck\Message\ViolationMessage;
17
use WikibaseQuality\ConstraintReport\ConstraintCheck\Result\CheckResult;
18
use WikibaseQuality\ConstraintReport\ConstraintParameterRenderer;
19
use WikibaseQuality\ConstraintReport\Role;
20
use Wikibase\DataModel\Statement\Statement;
21
22
/**
23
 * @author BP2014N1
24
 * @license GNU GPL v2+
25
 */
26
class RangeChecker implements ConstraintChecker {
27
28
	/**
29
	 * @var PropertyDataTypeLookup
30
	 */
31
	private $propertyDataTypeLookup;
32
33
	/**
34
	 * @var ConstraintParameterParser
35
	 */
36
	private $constraintParameterParser;
37
38
	/**
39
	 * @var RangeCheckerHelper
40
	 */
41
	private $rangeCheckerHelper;
42
43
	/**
44
	 * @var ConstraintParameterRenderer
45
	 */
46
	private $constraintParameterRenderer;
47
48
	public function __construct(
49
		PropertyDataTypeLookup $propertyDataTypeLookup,
50
		ConstraintParameterParser $constraintParameterParser,
51
		RangeCheckerHelper $rangeCheckerHelper,
52
		ConstraintParameterRenderer $constraintParameterRenderer
53
	) {
54
		$this->propertyDataTypeLookup = $propertyDataTypeLookup;
55
		$this->constraintParameterParser = $constraintParameterParser;
56
		$this->rangeCheckerHelper = $rangeCheckerHelper;
57
		$this->constraintParameterRenderer = $constraintParameterRenderer;
58
	}
59
60
	/**
61
	 * @codeCoverageIgnore This method is purely declarative.
62
	 */
63
	public function getSupportedContextTypes() {
64
		return [
65
			Context::TYPE_STATEMENT => CheckResult::STATUS_COMPLIANCE,
66
			Context::TYPE_QUALIFIER => CheckResult::STATUS_COMPLIANCE,
67
			Context::TYPE_REFERENCE => CheckResult::STATUS_COMPLIANCE,
68
		];
69
	}
70
71
	/**
72
	 * @codeCoverageIgnore This method is purely declarative.
73
	 */
74
	public function getDefaultContextTypes() {
75
		return [
76
			Context::TYPE_STATEMENT,
77
			Context::TYPE_QUALIFIER,
78
			Context::TYPE_REFERENCE,
79
		];
80
	}
81
82
	/**
83
	 * Checks 'Range' constraint.
84
	 *
85
	 * @param Context $context
86
	 * @param Constraint $constraint
87
	 *
88
	 * @throws ConstraintParameterException
89
	 * @return CheckResult
90
	 */
91
	public function checkConstraint( Context $context, Constraint $constraint ) {
92
		if ( $context->getSnakRank() === Statement::RANK_DEPRECATED ) {
93
			return new CheckResult( $context, $constraint, [], CheckResult::STATUS_DEPRECATED );
94
		}
95
96
		$parameters = [];
97
		$constraintParameters = $constraint->getConstraintParameters();
98
99
		$snak = $context->getSnak();
100
101
		if ( !$snak instanceof PropertyValueSnak ) {
102
			// nothing to check
103
			return new CheckResult( $context, $constraint, $parameters, CheckResult::STATUS_COMPLIANCE );
104
		}
105
106
		$dataValue = $snak->getDataValue();
107
108
		list( $min, $max ) = $this->constraintParameterParser->parseRangeParameter(
109
			$constraintParameters,
110
			$constraint->getConstraintTypeItemId(),
111
			$dataValue->getType()
112
		);
113
		$parameterKey = $dataValue->getType() === 'quantity' ? 'quantity' : 'date';
114
		if ( $min !== null ) {
115
			$parameters['minimum_' . $parameterKey] = [ $min ];
116
		}
117
		if ( $max !== null ) {
118
			$parameters['maximum_' . $parameterKey] = [ $max ];
119
		}
120
121
		if ( $this->rangeCheckerHelper->getComparison( $min, $dataValue ) > 0 ||
122
			 $this->rangeCheckerHelper->getComparison( $dataValue, $max ) > 0
123
		) {
124
			$message = $this->getViolationMessage(
125
				$context->getSnak()->getPropertyId(),
126
				$dataValue,
127
				$min,
128
				$max
129
			);
130
			$status = CheckResult::STATUS_VIOLATION;
131
		} else {
132
			$message = null;
133
			$status = CheckResult::STATUS_COMPLIANCE;
134
		}
135
136
		return new CheckResult( $context, $constraint, $parameters, $status, $message );
137
	}
138
139
	/**
140
	 * @param PropertyId $predicate
141
	 * @param DataValue $value
142
	 * @param DataValue|null $min
143
	 * @param DataValue|null $max
144
	 *
145
	 * @return ViolationMessage
146
	 */
147
	private function getViolationMessage( PropertyId $predicate, DataValue $value, $min, $max ) {
148
		// possible message keys:
149
		// wbqc-violation-message-range-quantity-closed
150
		// wbqc-violation-message-range-quantity-leftopen
151
		// wbqc-violation-message-range-quantity-rightopen
152
		// wbqc-violation-message-range-time-closed
153
		// wbqc-violation-message-range-time-closed-leftnow
154
		// wbqc-violation-message-range-time-closed-rightnow
155
		// wbqc-violation-message-range-time-leftopen
156
		// wbqc-violation-message-range-time-leftopen-rightnow
157
		// wbqc-violation-message-range-time-rightopen
158
		// wbqc-violation-message-range-time-rightopen-leftnow
159
		$messageKey = 'wbqc-violation-message-range';
160
		$messageKey .= '-' . $value->getType();
161
		// at least one of $min, $max is set, otherwise there could be no violation
162
		$messageKey .= '-' . ( $min !== null ? ( $max !== null ? 'closed' : 'rightopen' ) : 'leftopen' );
163
		if ( $min instanceof NowValue ) {
164
			$messageKey .= '-leftnow';
165
		} elseif ( $max instanceof  NowValue ) {
166
			$messageKey .= '-rightnow';
167
		}
168
		$message = ( new ViolationMessage( $messageKey ) )
169
			->withEntityId( $predicate, Role::PREDICATE )
170
			->withDataValue( $value, Role::OBJECT );
171 View Code Duplication
		if ( $min !== null && !( $min instanceof NowValue ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
172
			$message = $message->withDataValue( $min, Role::OBJECT );
173
		}
174 View Code Duplication
		if ( $max !== null && !( $max instanceof  NowValue ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175
			$message = $message->withDataValue( $max, Role::OBJECT );
176
		}
177
		return $message;
178
	}
179
180 View Code Duplication
	public function checkConstraintParameters( Constraint $constraint ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
		$constraintParameters = $constraint->getConstraintParameters();
182
		$exceptions = [];
183
		try {
184
			// we don’t have a data value here, so get the type from the property instead
185
			// (the distinction between data type and data value type is irrelevant for 'quantity' and 'time')
186
			$type = $this->propertyDataTypeLookup->getDataTypeIdForProperty( $constraint->getPropertyId() );
187
			$this->constraintParameterParser->parseRangeParameter(
188
				$constraintParameters,
189
				$constraint->getConstraintTypeItemId(),
190
				$type
191
			);
192
		} catch ( ConstraintParameterException $e ) {
193
			$exceptions[] = $e;
194
		}
195
		return $exceptions;
196
	}
197
198
}
199