Completed
Push — master ( 896ba9...cef96e )
by
unknown
01:45
created

extractConstraintFromStatement()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.6333
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace WikibaseQuality\ConstraintReport\Job;
4
5
use Config;
6
use Job;
7
use JobQueueGroup;
8
use Serializers\Serializer;
9
use Title;
10
use MediaWiki\MediaWikiServices;
11
use Wikibase\DataModel\Entity\Property;
12
use Wikibase\DataModel\Entity\PropertyId;
13
use Wikibase\DataModel\Snak\SnakList;
14
use Wikibase\DataModel\Statement\Statement;
15
use Wikibase\Lib\Store\EntityRevisionLookup;
16
use Wikibase\Repo\WikibaseRepo;
17
use Wikibase\Store;
18
use WikibaseQuality\ConstraintReport\Constraint;
19
use WikibaseQuality\ConstraintReport\ConstraintRepository;
20
use WikibaseQuality\ConstraintReport\ConstraintsServices;
21
use Wikimedia\Assert\Assert;
22
23
/**
24
 * A job that updates the constraints table
25
 * when changes were made on a property.
26
 *
27
 * @author Lucas Werkmeister
28
 * @license GPL-2.0-or-later
29
 */
30
class UpdateConstraintsTableJob extends Job {
31
32
	const BATCH_SIZE = 10;
33
34
	public static function newFromGlobalState( Title $title, array $params ) {
35
		Assert::parameterType( 'string', $params['propertyId'], '$params["propertyId"]' );
36
		$repo = WikibaseRepo::getDefaultInstance();
37
		return new UpdateConstraintsTableJob(
38
			$title,
39
			$params,
40
			$params['propertyId'],
41
			$params['revisionId'] ?? null,
42
			MediaWikiServices::getInstance()->getMainConfig(),
43
			ConstraintsServices::getConstraintRepository(),
44
			$repo->getEntityRevisionLookup( Store::LOOKUP_CACHING_DISABLED ),
45
			$repo->getBaseDataModelSerializerFactory()->newSnakSerializer()
46
		);
47
	}
48
49
	/**
50
	 * @var string
51
	 */
52
	private $propertyId;
53
54
	/**
55
	 * @var int|null
56
	 */
57
	private $revisionId;
58
59
	/**
60
	 * @var Config
61
	 */
62
	private $config;
63
64
	/**
65
	 * @var ConstraintRepository
66
	 */
67
	private $constraintRepo;
68
69
	/**
70
	 * @var EntityRevisionLookup
71
	 */
72
	private $entityRevisionLookup;
73
74
	/**
75
	 * @var Serializer
76
	 */
77
	private $snakSerializer;
78
79
	/**
80
	 * @param Title $title
81
	 * @param string[] $params should contain 'propertyId' => 'P...'
82
	 * @param string $propertyId property ID of the property for this job (which has the constraint statements)
83
	 * @param int|null $revisionId revision ID that triggered this job, if any
84
	 * @param Config $config
85
	 * @param ConstraintRepository $constraintRepo
86
	 * @param EntityRevisionLookup $entityRevisionLookup
87
	 * @param Serializer $snakSerializer
88
	 */
89
	public function __construct(
90
		Title $title,
91
		array $params,
92
		$propertyId,
93
		$revisionId,
94
		Config $config,
95
		ConstraintRepository $constraintRepo,
96
		EntityRevisionLookup $entityRevisionLookup,
97
		Serializer $snakSerializer
98
	) {
99
		parent::__construct( 'constraintsTableUpdate', $title, $params );
100
101
		$this->propertyId = $propertyId;
102
		$this->revisionId = $revisionId;
103
		$this->config = $config;
104
		$this->constraintRepo = $constraintRepo;
105
		$this->entityRevisionLookup = $entityRevisionLookup;
106
		$this->snakSerializer = $snakSerializer;
107
	}
108
109
	public function extractParametersFromQualifiers( SnakList $qualifiers ) {
110
		$parameters = [];
111
		foreach ( $qualifiers as $qualifier ) {
112
			$qualifierId = $qualifier->getPropertyId()->getSerialization();
113
			$paramSerialization = $this->snakSerializer->serialize( $qualifier );
114
			$parameters[$qualifierId][] = $paramSerialization;
115
		}
116
		return $parameters;
117
	}
118
119
	public function extractConstraintFromStatement(
120
		PropertyId $propertyId,
121
		Statement $constraintStatement
122
	) {
123
		$constraintId = $constraintStatement->getGuid();
124
		$snak = $constraintStatement->getMainSnak();
125
		'@phan-var \Wikibase\DataModel\Snak\PropertyValueSnak $snak';
126
		$dataValue = $snak->getDataValue();
127
		'@phan-var \Wikibase\DataModel\Entity\EntityIdValue $dataValue';
128
		$entityId = $dataValue->getEntityId();
129
		$constraintTypeQid = $entityId->getSerialization();
130
		$parameters = $this->extractParametersFromQualifiers( $constraintStatement->getQualifiers() );
131
		return new Constraint(
132
			$constraintId,
133
			$propertyId,
134
			$constraintTypeQid,
135
			$parameters
136
		);
137
	}
138
139
	public function importConstraintsForProperty(
140
		Property $property,
141
		ConstraintRepository $constraintRepo,
142
		PropertyId $propertyConstraintPropertyId
143
	) {
144
		$constraintsStatements = $property->getStatements()
145
			->getByPropertyId( $propertyConstraintPropertyId )
146
			->getByRank( [ Statement::RANK_PREFERRED, Statement::RANK_NORMAL ] );
147
		$constraints = [];
148
		foreach ( $constraintsStatements->getIterator() as $constraintStatement ) {
149
			$constraints[] = $this->extractConstraintFromStatement( $property->getId(), $constraintStatement );
150
			if ( count( $constraints ) >= self::BATCH_SIZE ) {
151
				$constraintRepo->insertBatch( $constraints );
152
				$constraints = [];
153
			}
154
		}
155
		$constraintRepo->insertBatch( $constraints );
156
	}
157
158
	/**
159
	 * @see Job::run
160
	 *
161
	 * @return bool
162
	 */
163
	public function run() {
164
		// TODO in the future: only touch constraints affected by the edit (requires T163465)
165
166
		$propertyId = new PropertyId( $this->propertyId );
167
		$propertyRevision = $this->entityRevisionLookup->getEntityRevision(
168
			$propertyId,
169
			0, // latest
170
			EntityRevisionLookup::LATEST_FROM_REPLICA
171
		);
172
173
		if ( $this->revisionId !== null && $propertyRevision->getRevisionId() < $this->revisionId ) {
174
			JobQueueGroup::singleton()->push( $this );
175
			return true;
176
		}
177
178
		$this->constraintRepo->deleteForProperty( $propertyId );
179
180
		/** @var Property $property */
181
		$property = $propertyRevision->getEntity();
182
		'@phan-var Property $property';
183
		$this->importConstraintsForProperty(
184
			$property,
185
			$this->constraintRepo,
186
			new PropertyId( $this->config->get( 'WBQualityConstraintsPropertyConstraintId' ) )
187
		);
188
189
		return true;
190
	}
191
192
}
193