Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
60.00% |
3 / 5 |
CRAP | |
87.69% |
57 / 65 |
EntitySchema\Services\Diff\SchemaPatcher | |
0.00% |
0 / 1 |
|
60.00% |
3 / 5 |
26.17 | |
87.69% |
57 / 65 |
patchSchema | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
patchFingerprint | |
100.00% |
1 / 1 |
4 | |
100.00% |
11 / 11 |
|||
patchTermlist | |
100.00% |
1 / 1 |
3 | |
100.00% |
5 / 5 |
|||
patchTerm | |
0.00% |
0 / 1 |
9.32 | |
84.21% |
16 / 19 |
|||
patchString | |
0.00% |
0 / 1 |
7.39 | |
80.00% |
20 / 25 |
<?php | |
namespace EntitySchema\Services\Diff; | |
use Diff\DiffOp\AtomicDiffOp; | |
use Diff\DiffOp\Diff\Diff; | |
use Diff\DiffOp\DiffOp; | |
use Diff\DiffOp\DiffOpAdd; | |
use Diff\DiffOp\DiffOpChange; | |
use Diff\DiffOp\DiffOpRemove; | |
use Diff\Patcher\PatcherException; | |
use EntitySchema\Services\SchemaConverter\FullArraySchemaData; | |
/** | |
* @license GPL-2.0-or-later | |
*/ | |
class SchemaPatcher { | |
/** | |
* @param FullArraySchemaData $baseSchema | |
* @param Diff $patch | |
* | |
* @return FullArraySchemaData | |
* | |
* @throws PatcherException throws exception if patch cannot be applied | |
* @suppress PhanPluginDuplicateConditionalNullCoalescing | |
*/ | |
public function patchSchema( FullArraySchemaData $baseSchema, Diff $patch ): FullArraySchemaData { | |
$patchedSchema = $this->patchFingerprint( $baseSchema->data, $patch ); | |
$patchedSchema['schemaText'] = $this->patchString( | |
$baseSchema->data['schemaText'] ?? '', | |
isset( $patch['schemaText'] ) ? $patch['schemaText'] : null | |
); | |
return new FullArraySchemaData( $patchedSchema ); | |
} | |
/** @suppress PhanPluginDuplicateConditionalNullCoalescing */ | |
private function patchFingerprint( array $baseSchema, Diff $patch ): array { | |
$aliasGroupPatcher = new AliasGroupListPatcher(); | |
$patchedSchema = [ | |
'labels' => $this->patchTermlist( | |
$baseSchema['labels'] ?? [], | |
isset( $patch['labels'] ) ? $patch['labels'] : null | |
), | |
'descriptions' => $this->patchTermlist( | |
$baseSchema['descriptions'] ?? [], | |
isset( $patch['descriptions'] ) ? $patch['descriptions'] : null | |
), | |
'aliases' => $aliasGroupPatcher->patchAliasGroupList( | |
$baseSchema['aliases'] ?? [], | |
isset( $patch['aliases'] ) ? $patch['aliases'] : null | |
), | |
]; | |
return $patchedSchema; | |
} | |
private function patchTermlist( array $terms, Diff $patch = null ): array { | |
if ( $patch === null ) { | |
return $terms; | |
} | |
foreach ( $patch as $lang => $diffOp ) { | |
$terms = $this->patchTerm( $terms, $lang, $diffOp ); | |
} | |
return $terms; | |
} | |
/** | |
* @suppress PhanUndeclaredMethod | |
*/ | |
private function patchTerm( $terms, $lang, AtomicDiffOp $diffOp ) { | |
switch ( true ) { | |
case $diffOp instanceof DiffOpAdd: | |
if ( !empty( $terms[$lang] ) ) { | |
throw new PatcherException( 'Term already exists' ); | |
} | |
$terms[$lang] = $diffOp->getNewValue(); | |
break; | |
case $diffOp instanceof DiffOpChange: | |
if ( empty( $terms[$lang] ) | |
|| $terms[$lang] !== $diffOp->getOldValue() | |
) { | |
throw new PatcherException( 'Term had been changed' ); | |
} | |
$terms[$lang] = $diffOp->getNewValue(); | |
break; | |
case $diffOp instanceof DiffOpRemove: | |
if ( !empty( $terms[$lang] ) | |
&& $terms[$lang] !== $diffOp->getOldValue() | |
) { | |
throw new PatcherException( 'Term had been changed' ); | |
} | |
unset( $terms[$lang] ); | |
break; | |
default: | |
throw new PatcherException( 'Invalid terms diff' ); | |
} | |
return $terms; | |
} | |
/** | |
* @param string $base | |
* @param DiffOp|null $diffOp | |
* | |
* @return string | |
* | |
* @suppress PhanUndeclaredMethod | |
*/ | |
private function patchString( $base, DiffOp $diffOp = null ) { | |
switch ( true ) { | |
case $diffOp instanceof DiffOpAdd: | |
$from = ''; | |
$to = $diffOp->getNewValue(); | |
break; | |
case $diffOp instanceof DiffOpRemove: | |
$from = $diffOp->getOldValue(); | |
$to = ''; | |
break; | |
case $diffOp instanceof DiffOpChange: | |
$from = $diffOp->getOldValue(); | |
$to = $diffOp->getNewValue(); | |
break; | |
case $diffOp === null; | |
$from = $to = null; | |
break; | |
} | |
if ( $from !== $to ) { | |
$ok = wfMerge( | |
$from, | |
$to, | |
$base, | |
$result | |
); | |
if ( !$ok ) { | |
throw new PatcherException( 'Patching the Schema failed because it has been changed.' ); | |
} | |
return trim( $result ); | |
} | |
return $base; | |
} | |
} |