Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
70.93% |
61 / 86 |
|
37.50% |
3 / 8 |
CRAP | |
0.00% |
0 / 1 |
LexemePatcher | |
70.93% |
61 / 86 |
|
37.50% |
3 / 8 |
57.16 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
canPatchEntityType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
patchEntity | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 | |||
getPatchedItemId | |
60.00% |
6 / 10 |
|
0.00% |
0 / 1 |
6.60 | |||
patchNextFormId | |
87.50% |
7 / 8 |
|
0.00% |
0 / 1 |
4.03 | |||
patchNextSenseId | |
12.50% |
1 / 8 |
|
0.00% |
0 / 1 |
14.72 | |||
patchForms | |
94.74% |
18 / 19 |
|
0.00% |
0 / 1 |
7.01 | |||
patchSenses | |
36.84% |
7 / 19 |
|
0.00% |
0 / 1 |
19.34 |
1 | <?php |
2 | |
3 | namespace Wikibase\Lexeme\Domain\Diff; |
4 | |
5 | use Diff\DiffOp\Diff\Diff; |
6 | use Diff\DiffOp\DiffOpAdd; |
7 | use Diff\DiffOp\DiffOpChange; |
8 | use Diff\DiffOp\DiffOpRemove; |
9 | use Diff\Patcher\PatcherException; |
10 | use InvalidArgumentException; |
11 | use Wikibase\DataModel\Entity\EntityDocument; |
12 | use Wikibase\DataModel\Entity\ItemId; |
13 | use Wikibase\DataModel\Services\Diff\EntityDiff; |
14 | use Wikibase\DataModel\Services\Diff\EntityPatcherStrategy; |
15 | use Wikibase\DataModel\Services\Diff\StatementListPatcher; |
16 | use Wikibase\DataModel\Services\Diff\TermListPatcher; |
17 | use Wikibase\Lexeme\Domain\Model\Lexeme; |
18 | use Wikibase\Lexeme\Domain\Model\LexemePatchAccess; |
19 | use Wikimedia\Assert\Assert; |
20 | |
21 | /** |
22 | * @license GPL-2.0-or-later |
23 | * @author Amir Sarabadani <ladsgroup@gmail.com> |
24 | * @author Thiemo Kreuz |
25 | */ |
26 | class LexemePatcher implements EntityPatcherStrategy { |
27 | |
28 | /** |
29 | * @var TermListPatcher |
30 | */ |
31 | private $termListPatcher; |
32 | |
33 | /** |
34 | * @var StatementListPatcher |
35 | */ |
36 | private $statementListPatcher; |
37 | |
38 | /** |
39 | * @var FormPatcher |
40 | */ |
41 | private $formPatcher; |
42 | |
43 | /** |
44 | * @var SensePatcher |
45 | */ |
46 | private $sensePatcher; |
47 | |
48 | public function __construct() { |
49 | $this->termListPatcher = new TermListPatcher(); |
50 | $this->statementListPatcher = new StatementListPatcher(); |
51 | $this->formPatcher = new FormPatcher(); |
52 | $this->sensePatcher = new SensePatcher(); |
53 | } |
54 | |
55 | /** |
56 | * @param string $entityType |
57 | * |
58 | * @return bool |
59 | */ |
60 | public function canPatchEntityType( $entityType ) { |
61 | return $entityType === Lexeme::ENTITY_TYPE; |
62 | } |
63 | |
64 | /** |
65 | * @param Lexeme $lexeme |
66 | * @param LexemeDiff $patch |
67 | * |
68 | * @throws InvalidArgumentException |
69 | */ |
70 | public function patchEntity( EntityDocument $lexeme, EntityDiff $patch ) { |
71 | Assert::parameterType( Lexeme::class, $lexeme, '$lexeme' ); |
72 | Assert::parameterType( LexemeDiff::class, $patch, '$patch' ); |
73 | |
74 | $this->termListPatcher->patchTermList( $lexeme->getLemmas(), $patch->getLemmasDiff() ); |
75 | |
76 | $this->statementListPatcher->patchStatementList( |
77 | $lexeme->getStatements(), |
78 | $patch->getClaimsDiff() |
79 | ); |
80 | |
81 | $itemId = $this->getPatchedItemId( $patch->getLexicalCategoryDiff() ); |
82 | if ( $itemId !== false ) { |
83 | $lexeme->setLexicalCategory( $itemId ); |
84 | } |
85 | |
86 | $itemId = $this->getPatchedItemId( $patch->getLanguageDiff() ); |
87 | if ( $itemId !== false ) { |
88 | $lexeme->setLanguage( $itemId ); |
89 | } |
90 | |
91 | $this->patchNextFormId( $lexeme, $patch ); |
92 | $this->patchForms( $lexeme, $patch ); |
93 | |
94 | $this->patchNextSenseId( $lexeme, $patch ); |
95 | $this->patchSenses( $lexeme, $patch ); |
96 | } |
97 | |
98 | /** |
99 | * @param Diff $patch |
100 | * |
101 | * @throws PatcherException |
102 | * @return ItemId|null|false False in case the diff is valid, but does not contain a change. |
103 | */ |
104 | private function getPatchedItemId( Diff $patch ) { |
105 | if ( $patch->isEmpty() ) { |
106 | return false; |
107 | } |
108 | |
109 | $diffOp = $patch['id']; |
110 | |
111 | switch ( true ) { |
112 | case $diffOp instanceof DiffOpAdd: |
113 | return $diffOp->getNewValue(); |
114 | |
115 | case $diffOp instanceof DiffOpChange: |
116 | return $diffOp->getNewValue(); |
117 | |
118 | case $diffOp instanceof DiffOpRemove: |
119 | return null; |
120 | } |
121 | |
122 | throw new PatcherException( 'Invalid ItemId diff' ); |
123 | } |
124 | |
125 | private function patchNextFormId( Lexeme $entity, LexemeDiff $patch ) { |
126 | // FIXME: Why is this a loop? The nextFormId field is not an array! |
127 | foreach ( $patch->getNextFormIdDiff() as $nextFormIdDiff ) { |
128 | if ( !( $nextFormIdDiff instanceof DiffOpChange ) ) { |
129 | throw new PatcherException( 'Invalid forms list diff' ); |
130 | } |
131 | |
132 | $newNumber = $nextFormIdDiff->getNewValue(); |
133 | if ( $newNumber > $entity->getNextFormId() ) { |
134 | $entity->patch( static function ( LexemePatchAccess $patchAccess ) use ( $newNumber ) { |
135 | $patchAccess->increaseNextFormIdTo( $newNumber ); |
136 | } ); |
137 | } |
138 | } |
139 | } |
140 | |
141 | private function patchNextSenseId( Lexeme $entity, LexemeDiff $patch ) { |
142 | // FIXME: Same as above |
143 | foreach ( $patch->getNextSenseIdDiff() as $nextSenseIdDiff ) { |
144 | if ( !( $nextSenseIdDiff instanceof DiffOpChange ) ) { |
145 | throw new PatcherException( 'Invalid senses list diff' ); |
146 | } |
147 | |
148 | $newNumber = $nextSenseIdDiff->getNewValue(); |
149 | if ( $newNumber > $entity->getNextSenseId() ) { |
150 | $entity->patch( static function ( LexemePatchAccess $patchAccess ) use ( $newNumber ) { |
151 | $patchAccess->increaseNextSenseIdTo( $newNumber ); |
152 | } ); |
153 | } |
154 | } |
155 | } |
156 | |
157 | private function patchForms( Lexeme $lexeme, LexemeDiff $patch ) { |
158 | foreach ( $patch->getFormsDiff() as $formDiff ) { |
159 | switch ( true ) { |
160 | case $formDiff instanceof AddFormDiff: |
161 | $form = $formDiff->getAddedForm(); |
162 | $lexeme->patch( |
163 | static function ( LexemePatchAccess $patchAccess ) use ( $form ) { |
164 | $patchAccess->addForm( $form ); |
165 | } |
166 | ); |
167 | break; |
168 | |
169 | case $formDiff instanceof RemoveFormDiff: |
170 | $lexeme->removeForm( $formDiff->getRemovedFormId() ); |
171 | break; |
172 | |
173 | case $formDiff instanceof ChangeFormDiffOp: |
174 | try { |
175 | $form = $lexeme->getForm( $formDiff->getFormId() ); |
176 | } catch ( \OutOfRangeException $e ) { |
177 | // form does not exist (anymore? may have been removed), nothing to patch (T326768) |
178 | break; |
179 | } |
180 | $this->formPatcher->patch( $form, $formDiff ); |
181 | break; |
182 | |
183 | default: |
184 | throw new PatcherException( 'Invalid forms list diff: ' . get_class( $formDiff ) ); |
185 | } |
186 | } |
187 | } |
188 | |
189 | private function patchSenses( Lexeme $lexeme, LexemeDiff $patch ) { |
190 | foreach ( $patch->getSensesDiff() as $senseDiff ) { |
191 | switch ( true ) { |
192 | case $senseDiff instanceof AddSenseDiff: |
193 | $sense = $senseDiff->getAddedSense(); |
194 | $lexeme->patch( |
195 | static function ( LexemePatchAccess $patchAccess ) use ( $sense ) { |
196 | $patchAccess->addSense( $sense ); |
197 | } |
198 | ); |
199 | break; |
200 | |
201 | case $senseDiff instanceof RemoveSenseDiff: |
202 | $lexeme->removeSense( $senseDiff->getRemovedSenseId() ); |
203 | break; |
204 | |
205 | case $senseDiff instanceof ChangeSenseDiffOp: |
206 | try { |
207 | $sense = $lexeme->getSense( $senseDiff->getSenseId() ); |
208 | } catch ( \OutOfRangeException $e ) { |
209 | // sense does not exist (anymore? may have been removed), nothing to patch (T284061) |
210 | break; |
211 | } |
212 | $this->sensePatcher->patchEntity( $sense, $senseDiff ); |
213 | break; |
214 | |
215 | default: |
216 | throw new PatcherException( 'Invalid senses list diff: ' . get_class( $senseDiff ) ); |
217 | } |
218 | } |
219 | } |
220 | |
221 | } |