Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
66.67% |
6 / 9 |
CRAP | |
86.51% |
109 / 126 |
EntitySchema\DataAccess\MediaWikiRevisionSchemaUpdater | |
0.00% |
0 / 1 |
|
66.67% |
6 / 9 |
22.08 | |
86.51% |
109 / 126 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
truncateSchemaTextForCommentData | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
overwriteWholeSchema | |
0.00% |
0 / 1 |
3.24 | |
70.00% |
14 / 20 |
|||
updateSchemaNameBadge | |
0.00% |
0 / 1 |
3.14 | |
75.00% |
6 / 8 |
|||
anonymousFunction:121#613 | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
getUpdateNameBadgeAutocomment | |
100.00% |
1 / 1 |
5 | |
100.00% |
27 / 27 |
|||
updateSchemaText | |
0.00% |
0 / 1 |
4.13 | |
80.00% |
8 / 10 |
|||
anonymousFunction:243#1404 | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
checkSchemaExists | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
<?php | |
namespace EntitySchema\DataAccess; | |
use CommentStoreComment; | |
use InvalidArgumentException; | |
use Language; | |
use MediaWiki\Revision\RevisionRecord; | |
use MediaWiki\Revision\RevisionLookup; | |
use MediaWiki\Revision\SlotRecord; | |
use RuntimeException; | |
use EntitySchema\Domain\Model\SchemaId; | |
use EntitySchema\MediaWiki\Content\EntitySchemaContent; | |
use EntitySchema\Services\SchemaConverter\FullArraySchemaData; | |
use EntitySchema\Services\SchemaConverter\SchemaConverter; | |
/** | |
* @license GPL-2.0-or-later | |
*/ | |
class MediaWikiRevisionSchemaUpdater implements SchemaUpdater { | |
const AUTOCOMMENT_UPDATED_SCHEMATEXT = 'entityschema-summary-update-schema-text'; | |
const AUTOCOMMENT_UPDATED_NAMEBADGE = 'entityschema-summary-update-schema-namebadge'; | |
const AUTOCOMMENT_UPDATED_LABEL = 'entityschema-summary-update-schema-label'; | |
const AUTOCOMMENT_UPDATED_DESCRIPTION = 'entityschema-summary-update-schema-description'; | |
const AUTOCOMMENT_UPDATED_ALIASES = 'entityschema-summary-update-schema-aliases'; | |
/* public */ const AUTOCOMMENT_RESTORE = 'entityschema-summary-restore'; | |
/* public */ const AUTOCOMMENT_UNDO = 'entityschema-summary-undo'; | |
private $pageUpdaterFactory; | |
private $watchListUpdater; | |
private $revisionLookup; | |
public function __construct( | |
MediaWikiPageUpdaterFactory $pageUpdaterFactory, | |
WatchlistUpdater $watchListUpdater, | |
RevisionLookup $revisionLookup | |
) { | |
$this->pageUpdaterFactory = $pageUpdaterFactory; | |
$this->watchListUpdater = $watchListUpdater; | |
$this->revisionLookup = $revisionLookup; | |
} | |
private function truncateSchemaTextForCommentData( $schemaText ) { | |
$language = Language::factory( 'en' ); | |
return $language->truncateForVisual( $schemaText, 5000 ); | |
} | |
/** | |
* Update a Schema with new content. This will remove existing schema content. | |
* | |
* @param SchemaId $id | |
* @param string[] $labels | |
* @param string[] $descriptions | |
* @param string[] $aliasGroups | |
* @param string $schemaText | |
* @param int $baseRevId | |
* @param CommentStoreComment $summary | |
* | |
* @throws InvalidArgumentException if bad parameters are passed | |
* @throws RuntimeException if Schema to update does not exist or saving fails | |
*/ | |
public function overwriteWholeSchema( | |
SchemaId $id, | |
array $labels, | |
array $descriptions, | |
array $aliasGroups, | |
$schemaText, | |
$baseRevId, | |
CommentStoreComment $summary | |
) { | |
$updater = $this->pageUpdaterFactory->getPageUpdater( $id->getId() ); | |
$this->checkSchemaExists( $updater->grabParentRevision() ); | |
if ( $updater->hasEditConflict( $baseRevId ) ) { | |
throw new EditConflict(); | |
} | |
$updater->setContent( | |
SlotRecord::MAIN, | |
new EntitySchemaContent( | |
SchemaEncoder::getPersistentRepresentation( | |
$id, | |
$labels, | |
$descriptions, | |
$aliasGroups, | |
$schemaText | |
) | |
) | |
); | |
$updater->saveRevision( | |
$summary, | |
EDIT_UPDATE | EDIT_INTERNAL | |
); | |
if ( !$updater->wasSuccessful() ) { | |
throw new RuntimeException( 'The revision could not be saved' ); | |
} | |
$this->watchListUpdater->optionallyWatchEditedSchema( $id ); | |
} | |
public function updateSchemaNameBadge( | |
SchemaId $id, | |
$langCode, | |
$label, | |
$description, | |
array $aliases, | |
$baseRevId | |
) { | |
$updater = $this->pageUpdaterFactory->getPageUpdater( $id->getId() ); | |
$parentRevision = $updater->grabParentRevision(); | |
$this->checkSchemaExists( $parentRevision ); | |
$baseRevision = $this->revisionLookup->getRevisionById( $baseRevId ); | |
$updateGuard = new SchemaUpdateGuard(); | |
$schemaData = $updateGuard->guardSchemaUpdate( | |
$baseRevision, | |
$parentRevision, | |
function ( FullArraySchemaData $schemaData ) use ( $langCode, $label, $description, $aliases ) { | |
$schemaData->data['labels'][$langCode] = $label; | |
$schemaData->data['descriptions'][$langCode] = $description; | |
$schemaData->data['aliases'][$langCode] = $aliases; | |
} | |
); | |
if ( $schemaData === null ) { | |
return; | |
} | |
$autoComment = $this->getUpdateNameBadgeAutocomment( | |
$baseRevision, | |
$langCode, | |
$label, | |
$description, | |
$aliases | |
); | |
$updater->setContent( | |
SlotRecord::MAIN, | |
new EntitySchemaContent( | |
SchemaEncoder::getPersistentRepresentation( | |
$id, | |
$schemaData->labels, | |
$schemaData->descriptions, | |
$schemaData->aliases, | |
$schemaData->schemaText | |
) | |
) | |
); | |
$updater->saveRevision( $autoComment, EDIT_UPDATE | EDIT_INTERNAL ); | |
if ( !$updater->wasSuccessful() ) { | |
throw new RuntimeException( 'The revision could not be saved' ); | |
} | |
$this->watchListUpdater->optionallyWatchEditedSchema( $id ); | |
} | |
private function getUpdateNameBadgeAutocomment( | |
RevisionRecord $baseRevision, | |
$langCode, | |
$label, | |
$description, | |
array $aliases | |
): CommentStoreComment { | |
$schemaConverter = new SchemaConverter(); | |
$schemaData = $schemaConverter->getPersistenceSchemaData( | |
// @phan-suppress-next-line PhanUndeclaredMethod | |
$baseRevision->getContent( SlotRecord::MAIN )->getText() | |
); | |
$label = SchemaCleaner::trimWhitespaceAndControlChars( $label ); | |
$description = SchemaCleaner::trimWhitespaceAndControlChars( $description ); | |
$aliases = SchemaCleaner::cleanupArrayOfStrings( $aliases ); | |
$language = Language::factory( $langCode ); | |
$typeOfChange = []; | |
if ( ( $schemaData->labels[$langCode] ?? '' ) !== $label ) { | |
$typeOfChange[self::AUTOCOMMENT_UPDATED_LABEL] = $label; | |
} | |
if ( ( $schemaData->descriptions[$langCode] ?? '' ) !== $description ) { | |
$typeOfChange[self::AUTOCOMMENT_UPDATED_DESCRIPTION] = $description; | |
} | |
if ( ( $schemaData->aliases[$langCode] ?? [] ) !== $aliases ) { | |
$typeOfChange[self::AUTOCOMMENT_UPDATED_ALIASES] = $language->commaList( $aliases ); | |
} | |
if ( count( $typeOfChange ) === 1 ) { // TODO what if it’s 0? | |
$autocommentKey = key( $typeOfChange ); | |
$autosummary = $typeOfChange[$autocommentKey]; | |
} else { | |
$autocommentKey = self::AUTOCOMMENT_UPDATED_NAMEBADGE; | |
$autosummary = ''; | |
} | |
$autocomment = $autocommentKey . ':' . $langCode; | |
return CommentStoreComment::newUnsavedComment( | |
'/* ' . $autocomment . ' */' . $autosummary, | |
[ | |
'key' => $autocommentKey, | |
'language' => $langCode, | |
'label' => $label, | |
'description' => $description, | |
'aliases' => $aliases, | |
] | |
); | |
} | |
/** | |
* @param SchemaId $id | |
* @param string $schemaText | |
* @param int $baseRevId | |
* @param string|null $userSummary | |
* | |
* @throws InvalidArgumentException if bad parameters are passed | |
* @throws EditConflict if another revision has been saved after $baseRevId | |
* @throws RuntimeException if Schema to update does not exist or saving fails | |
*/ | |
public function updateSchemaText( | |
SchemaId $id, | |
$schemaText, | |
$baseRevId, | |
$userSummary = null | |
) { | |
if ( !is_string( $schemaText ) ) { | |
throw new InvalidArgumentException( 'schema text must be a string' ); | |
} | |
$updater = $this->pageUpdaterFactory->getPageUpdater( $id->getId() ); | |
$parentRevision = $updater->grabParentRevision(); | |
$this->checkSchemaExists( $parentRevision ); | |
$baseRevision = $this->revisionLookup->getRevisionById( $baseRevId ); | |
$updateGuard = new SchemaUpdateGuard(); | |
$schemaData = $updateGuard->guardSchemaUpdate( | |
$baseRevision, | |
$parentRevision, | |
function ( FullArraySchemaData $schemaData ) use ( $schemaText ) { | |
$schemaData->data['schemaText'] = $schemaText; | |
} | |
); | |
if ( $schemaData === null ) { | |
return; | |
} | |
$persistentRepresentation = SchemaEncoder::getPersistentRepresentation( | |
$id, | |
$schemaData->labels, | |
$schemaData->descriptions, | |
$schemaData->aliases, | |
$schemaData->schemaText | |
); | |
$updater->setContent( | |
SlotRecord::MAIN, | |
new EntitySchemaContent( $persistentRepresentation ) | |
); | |
$commentText = '/* ' . self::AUTOCOMMENT_UPDATED_SCHEMATEXT . ' */' . $userSummary; | |
$updater->saveRevision( | |
CommentStoreComment::newUnsavedComment( | |
$commentText, | |
[ | |
'key' => self::AUTOCOMMENT_UPDATED_SCHEMATEXT, | |
'userSummary' => $userSummary, | |
'schemaText_truncated' => $this->truncateSchemaTextForCommentData( | |
// TODO use unpatched $schemaText or patched $schemaData->schemaText here? | |
$schemaData->schemaText | |
), | |
] | |
), | |
EDIT_UPDATE | EDIT_INTERNAL | |
); | |
if ( !$updater->wasSuccessful() ) { | |
throw new RuntimeException( 'The revision could not be saved' ); | |
} | |
$this->watchListUpdater->optionallyWatchEditedSchema( $id ); | |
} | |
/** | |
* @param RevisionRecord|null $parentRevision if null, an exception will be thrown | |
* | |
* @throws RuntimeException | |
*/ | |
private function checkSchemaExists( RevisionRecord $parentRevision = null ) { | |
if ( $parentRevision === null ) { | |
throw new RuntimeException( 'Schema to update does not exist' ); | |
} | |
} | |
} |