Completed
Push — master ( db78bd...e9e3e0 )
by
unknown
02:32
created

getStatementsWithSameQualifiersForProperties()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
c 0
b 0
f 0
rs 8.5906
cc 5
eloc 14
nc 5
nop 3
1
<?php
2
3
namespace WikibaseQuality\ConstraintReport\ConstraintCheck\Context;
4
5
use LogicException;
6
use Wikibase\DataModel\Entity\EntityDocument;
7
use Wikibase\DataModel\Entity\PropertyId;
8
use Wikibase\DataModel\Snak\Snak;
9
use Wikibase\DataModel\Snak\SnakList;
10
use Wikibase\DataModel\Statement\Statement;
11
use Wikibase\DataModel\Statement\StatementList;
12
use Wikibase\DataModel\Statement\StatementListProvider;
13
use Wikimedia\Assert\Assert;
14
15
/**
16
 * A constraint check context for the main snak of a statement.
17
 *
18
 * @license GPL-2.0-or-later
19
 */
20
class MainSnakContext extends AbstractContext {
21
22
	/**
23
	 * @var Statement
24
	 */
25
	private $statement;
26
27
	public function __construct( EntityDocument $entity, Statement $statement ) {
28
		Assert::parameterType( StatementListProvider::class, $entity, '$entity' );
29
		parent::__construct( $entity, $statement->getMainSnak() );
30
31
		$this->statement = $statement;
32
	}
33
34
	public function getType() {
35
		return self::TYPE_STATEMENT;
36
	}
37
38
	public function getSnakRank() {
39
		return $this->statement->getRank();
40
	}
41
42
	public function getSnakStatement() {
43
		return $this->statement;
44
	}
45
46
	public function getSnakGroup( $groupingMode, array $separators = [] ) {
47
		/** @var StatementList $statements */
48
		$statements = $this->entity->getStatements();
49
		switch ( $groupingMode ) {
50
			case Context::GROUP_NON_DEPRECATED:
51
				$statements = $statements->getByRank( [
52
					Statement::RANK_NORMAL,
53
					Statement::RANK_PREFERRED,
54
				] );
55
				break;
56
			case Context::GROUP_BEST_RANK:
57
				$statements = $this->getBestStatementsPerPropertyId( $statements );
58
				break;
59
			default:
60
				throw new LogicException( 'Unknown $groupingMode ' . $groupingMode );
61
		}
62
		return $this->getStatementsWithSameQualifiersForProperties(
63
			$this->statement,
64
			$statements,
65
			$separators
66
		)->getMainSnaks();
67
	}
68
69
	private function getBestStatementsPerPropertyId( StatementList $statements ) {
70
		$allBestStatements = new StatementList();
71
		foreach ( $statements->getPropertyIds() as $propertyId ) {
72
			$bestStatements = $statements->getByPropertyId( $propertyId )
73
				->getBestStatements();
74
			foreach ( $bestStatements as $bestStatement ) {
75
				$allBestStatements->addStatement( $bestStatement );
76
			}
77
		}
78
		return $allBestStatements;
79
	}
80
81
	/**
82
	 * Returns the statements of a statement list
83
	 * which for a set of propert IDs have the same qualifiers as a certain statement.
84
	 * “unknown value” qualifiers are considered different from each other.
85
	 *
86
	 * @param Statement $currentStatement
87
	 * @param StatementList $allStatements
88
	 * @param PropertyId[] $qualifierPropertyIds
89
	 * @return StatementList
90
	 */
91
	private function getStatementsWithSameQualifiersForProperties(
92
		Statement $currentStatement,
93
		StatementList $allStatements,
94
		array $qualifierPropertyIds
95
	) {
96
		$similarStatements = new StatementList();
97
		foreach ( $allStatements as $statement ) {
98
			if ( $statement === $currentStatement ) {
99
				// if the statement has an “unknown value” qualifier,
100
				// it might be considered different from itself,
101
				// so add it explicitly to ensure it’s always included
102
				$similarStatements->addStatement( $statement );
103
				continue;
104
			}
105
			foreach ( $qualifierPropertyIds as $qualifierPropertyId ) {
106
				if ( !$this->haveSameQualifiers( $currentStatement, $statement, $qualifierPropertyId ) ) {
107
					continue 2;
108
				}
109
			}
110
			$similarStatements->addStatement( $statement );
111
		}
112
		return $similarStatements;
113
	}
114
115
	/**
116
	 * Tests whether two statements have the same qualifiers with a certain property ID.
117
	 * “unknown value” qualifiers are considered different from each other.
118
	 *
119
	 * @param Statement $s1
120
	 * @param Statement $s2
121
	 * @param PropertyId $propertyId
122
	 * @return bool
123
	 */
124
	private function haveSameQualifiers( Statement $s1, Statement $s2, PropertyId $propertyId ) {
125
		$q1 = $this->getSnaksWithPropertyId( $s1->getQualifiers(), $propertyId );
126
		$q2 = $this->getSnaksWithPropertyId( $s2->getQualifiers(), $propertyId );
127
128
		if ( $q1->count() !== $q2->count() ) {
129
			return false;
130
		}
131
132
		foreach ( $q1 as $qualifier ) {
133
			switch ( $qualifier->getType() ) {
134
				case 'value':
135
				case 'novalue':
136
					if ( !$q2->hasSnak( $qualifier ) ) {
137
						return false;
138
					}
139
					break;
140
				case 'somevalue':
141
					return false; // all “unknown value”s are considered different from each other
142
			}
143
		}
144
145
		// a SnakList cannot contain the same snak more than once,
146
		// so if every snak of q1 is also in q2 and their cardinality is identical,
147
		// then they must be entirely identical
148
		return true;
149
	}
150
151
	/**
152
	 * Returns the snaks of the given snak list with the specified property ID.
153
	 *
154
	 * @param SnakList $allSnaks
155
	 * @param PropertyId $propertyId
156
	 * @return SnakList
157
	 */
158
	private function getSnaksWithPropertyId( SnakList $allSnaks, PropertyId $propertyId ) {
159
		$snaks = new SnakList();
160
		/** @var Snak $snak */
161
		foreach ( $allSnaks as $snak ) {
162
			if ( $snak->getPropertyId()->equals( $propertyId ) ) {
163
				$snaks->addSnak( $snak );
164
			}
165
		}
166
		return $snaks;
167
	}
168
169
	public function getCursor() {
170
		return new MainSnakContextCursor(
171
			$this->entity->getId()->getSerialization(),
172
			$this->statement->getPropertyId()->getSerialization(),
173
			$this->statement->getGuid(),
174
			$this->statement->getMainSnak()->getHash()
175
		);
176
	}
177
178
}
179