jenkins-bot has submitted this change and it was merged. Change subject: Factor EntitySaveHelper out of ApiWikibase ......................................................................
Factor EntitySaveHelper out of ApiWikibase This moves the logic of an API saving pages out of the base class and into a helper class. This was essentially a Copy & Paste move of the methods. This means it can be tested seperatly and injected where needed. I have also introduced some basic tests for the class and method. These are only basic currently. A convenience method has also been added to the api helper factory. Change-Id: Ie426c1828a69623c9cced688eb7bf7992a8b437f --- M repo/includes/WikibaseRepo.php M repo/includes/api/ApiHelperFactory.php M repo/includes/api/ApiWikibase.php M repo/includes/api/CreateRedirect.php A repo/includes/api/EntitySaveHelper.php M repo/includes/api/FormatSnakValue.php M repo/includes/api/MergeItems.php M repo/includes/api/ParseValue.php M repo/tests/phpunit/includes/WikibaseRepoTest.php M repo/tests/phpunit/includes/api/ApiHelperFactoryTest.php A repo/tests/phpunit/includes/api/EntitySaverHelperTest.php M repo/tests/phpunit/includes/api/MergeItemsTest.php 12 files changed, 547 insertions(+), 181 deletions(-) Approvals: Jeroen De Dauw: Looks good to me, approved jenkins-bot: Verified diff --git a/repo/includes/WikibaseRepo.php b/repo/includes/WikibaseRepo.php index 1d091a1..5767a1e 100644 --- a/repo/includes/WikibaseRepo.php +++ b/repo/includes/WikibaseRepo.php @@ -330,12 +330,21 @@ $this->getEntityPermissionChecker(), $this->getSummaryFormatter(), $user, - new EditFilterHookRunner( - $this->getEntityTitleLookup(), - $this->getEntityContentFactory(), - $context - ), + $this->newEditFilterHookRunner( $context ), $this->getStore()->getEntityRedirectLookup() + ); + } + + /** + * @param IContextSource $context + * + * @return EditFilterHookRunner + */ + private function newEditFilterHookRunner( IContextSource $context ) { + return new EditFilterHookRunner( + $this->getEntityTitleLookup(), + $this->getEntityContentFactory(), + $context ); } @@ -1060,14 +1069,21 @@ } /** + * @param IContextSource $context + * * @return ApiHelperFactory */ - public function getApiHelperFactory() { + public function getApiHelperFactory( $context ) { return new ApiHelperFactory( $this->getEntityTitleLookup(), $this->getExceptionLocalizer(), $this->getPropertyDataTypeLookup(), - $this->getEntityFactory() + $this->getEntityFactory(), + $this->getSummaryFormatter(), + $this->getEntityRevisionLookup(), + $this->getEntityStore(), + $this->getEntityPermissionChecker(), + $this->newEditFilterHookRunner( $context ) ); } diff --git a/repo/includes/api/ApiHelperFactory.php b/repo/includes/api/ApiHelperFactory.php index d9bf807..3a6a83b 100644 --- a/repo/includes/api/ApiHelperFactory.php +++ b/repo/includes/api/ApiHelperFactory.php @@ -8,7 +8,12 @@ use Wikibase\Lib\Localizer\ExceptionLocalizer; use Wikibase\Lib\Serializers\SerializationOptions; use Wikibase\Lib\Serializers\SerializerFactory; +use Wikibase\Lib\Store\EntityRevisionLookup; +use Wikibase\Lib\Store\EntityStore; use Wikibase\Lib\Store\EntityTitleLookup; +use Wikibase\Repo\Hooks\EditFilterHookRunner; +use Wikibase\Repo\Store\EntityPermissionChecker; +use Wikibase\SummaryFormatter; /** * A factory class for API helper objects. @@ -44,17 +49,51 @@ */ private $entityFactory; + /** + * @var SummaryFormatter + */ + private $summaryFormatter; + + /** + * @var EntityRevisionLookup + */ + private $entityRevisionLookup; + + /** + * @var EntityStore + */ + private $entityStore; + + /** + * @var EntityPermissionChecker + */ + private $entityPermissionChecker; + + /** + * @var EditFilterHookRunner + */ + private $editFilterHookRunner; + public function __construct( EntityTitleLookup $titleLookup, ExceptionLocalizer $exceptionLocalizer, PropertyDataTypeLookup $dataTypeLookup, - EntityFactory $entityFactory + EntityFactory $entityFactory, + SummaryFormatter $summaryFormatter, + EntityRevisionLookup $entityRevisionLookup, + EntityStore $entityStore, + EntityPermissionChecker $entityPermissionChecker, + EditFilterHookRunner $editFilterHookRunner ) { - $this->titleLookup = $titleLookup; $this->exceptionLocalizer = $exceptionLocalizer; $this->dataTypeLookup = $dataTypeLookup; $this->entityFactory = $entityFactory; + $this->summaryFormatter = $summaryFormatter; + $this->entityRevisionLookup = $entityRevisionLookup; + $this->entityStore = $entityStore; + $this->entityPermissionChecker = $entityPermissionChecker; + $this->editFilterHookRunner = $editFilterHookRunner; } /** @@ -102,4 +141,24 @@ ); } + /** + * Return an EntitySaveHelper object for use in Api modules + * + * @param ApiBase $apiBase + * + * @return EntitySaveHelper + */ + public function getEntitySaveHelper( ApiBase $apiBase ) { + return new EntitySaveHelper( + $apiBase, + $this->getErrorReporter( $apiBase ), + $this->summaryFormatter, + $this->titleLookup, + $this->entityRevisionLookup, + $this->entityStore, + $this->entityPermissionChecker, + $this->editFilterHookRunner + ); + } + } diff --git a/repo/includes/api/ApiWikibase.php b/repo/includes/api/ApiWikibase.php index ebd6b63..fa78f53 100644 --- a/repo/includes/api/ApiWikibase.php +++ b/repo/includes/api/ApiWikibase.php @@ -13,7 +13,6 @@ use Wikibase\DataModel\Entity\EntityDocument; use Wikibase\DataModel\Entity\EntityId; use Wikibase\DataModel\Entity\EntityIdParser; -use Wikibase\EditEntity; use Wikibase\EntityRevision; use Wikibase\Lib\Localizer\ExceptionLocalizer; use Wikibase\Lib\Store\BadRevisionException; @@ -25,7 +24,6 @@ use Wikibase\Repo\Hooks\EditFilterHookRunner; use Wikibase\Repo\Store\EntityPermissionChecker; use Wikibase\Repo\WikibaseRepo; -use Wikibase\Summary; use Wikibase\SummaryFormatter; /** @@ -91,6 +89,11 @@ private $editFilterHookRunner; /** + * @var EntitySaveHelper + */ + private $entitySaveHelper; + + /** * @param ApiMain $mainModule * @param string $moduleName * @param string $modulePrefix @@ -100,27 +103,30 @@ public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) { parent::__construct( $mainModule, $moduleName, $modulePrefix ); - $this->titleLookup = WikibaseRepo::getDefaultInstance()->getEntityTitleLookup(); - $this->idParser = WikibaseRepo::getDefaultInstance()->getEntityIdParser(); + $wikibaseRepo = WikibaseRepo::getDefaultInstance(); + + $this->titleLookup = $wikibaseRepo->getEntityTitleLookup(); + $this->idParser = $wikibaseRepo->getEntityIdParser(); // NOTE: use uncached lookup for write mode! $uncached = $this->isWriteMode() ? 'uncached' : ''; - $this->entityRevisionLookup = WikibaseRepo::getDefaultInstance()->getEntityRevisionLookup( $uncached ); - $this->entityStore = WikibaseRepo::getDefaultInstance()->getEntityStore(); + $this->entityRevisionLookup = $wikibaseRepo->getEntityRevisionLookup( $uncached ); + $this->entityStore = $wikibaseRepo->getEntityStore(); - $this->summaryFormatter = WikibaseRepo::getDefaultInstance()->getSummaryFormatter(); + $this->summaryFormatter = $wikibaseRepo->getSummaryFormatter(); - $this->permissionChecker = WikibaseRepo::getDefaultInstance()->getEntityPermissionChecker(); + $this->permissionChecker = $wikibaseRepo->getEntityPermissionChecker(); - $this->exceptionLocalizer = WikibaseRepo::getDefaultInstance()->getExceptionLocalizer(); + $this->exceptionLocalizer = $wikibaseRepo->getExceptionLocalizer(); - $this->errorReporter = WikibaseRepo::getDefaultInstance()->getApiHelperFactory()->getErrorReporter( $this ); - - $this->resultBuilder = WikibaseRepo::getDefaultInstance()->getApiHelperFactory()->getResultBuilder( $this ); + $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $this->getContext() ); + $this->errorReporter = $apiHelperFactory->getErrorReporter( $this ); + $this->resultBuilder = $apiHelperFactory->getResultBuilder( $this ); + $this->entitySaveHelper = $apiHelperFactory->getEntitySaveHelper( $this ); $this->editFilterHookRunner = new EditFilterHookRunner( $this->titleLookup, - WikibaseRepo::getDefaultInstance()->getEntityContentFactory(), + $wikibaseRepo->getEntityContentFactory(), $this->getContext() ); } @@ -287,152 +293,10 @@ } /** - * Signal errors and warnings from a save operation to the API call's output. - * This is much like handleStatus(), but specialized for Status objects returned by - * EditEntity::attemptSave(). In particular, the 'errorFlags' and 'errorCode' fields - * from the status value are used to determine the error code to return to the caller. - * - * @note: this function may or may not return normally, depending on whether - * the status is fatal or not. - * - * @see handleStatus(). - * - * @param Status $status The status to report - */ - private function handleSaveStatus( Status $status ) { - $value = $status->getValue(); - $errorCode = null; - - if ( is_array( $value ) && isset( $value['errorCode'] ) ) { - $errorCode = $value['errorCode']; - } else { - $editError = 0; - - if ( is_array( $value ) && isset( $value['errorFlags'] ) ) { - $editError = $value['errorFlags']; - } - - if ( ( $editError & EditEntity::TOKEN_ERROR ) > 0 ) { - $errorCode = 'badtoken'; - } elseif ( ( $editError & EditEntity::EDIT_CONFLICT_ERROR ) > 0 ) { - $errorCode = 'editconflict'; - } elseif ( ( $editError & EditEntity::ANY_ERROR ) > 0 ) { - $errorCode = 'failed-save'; - } - } - - //NOTE: will just add warnings or do nothing if there's no error - $this->handleStatus( $status, $errorCode ); - } - - /** - * Include messages from a Status object in the API call's output. - * - * An ApiErrorHandler is used to report the status, if necessary. - * If $status->isOK() is false, this method will terminate with a UsageException. - * - * @param Status $status The status to report - * @param string $errorCode The API error code to use in case $status->isOK() returns false - * @param array $extradata Additional data to include the the error report, - * if $status->isOK() returns false - * @param int $httpRespCode the HTTP response code to use in case - * $status->isOK() returns false.+ - * - * @throws UsageException If $status->isOK() returns false. - */ - private function handleStatus( Status $status, $errorCode, array $extradata = array(), $httpRespCode = 0 ) { - if ( $status->isGood() ) { - return; - } elseif ( $status->isOK() ) { - $this->errorReporter->reportStatusWarnings( $status ); - } else { - $this->errorReporter->reportStatusWarnings( $status ); - $this->errorReporter->dieStatus( $status, $errorCode, $httpRespCode, $extradata ); - } - } - - /** - * Attempts to save the new entity content, chile first checking for permissions, - * edit conflicts, etc. Saving is done via EditEntity::attemptSave(). - * - * This method automatically takes into account several parameters: - * * 'bot' for setting the bot flag - * * 'baserevid' for determining the edit's base revision for conflict resolution - * * 'token' for the edit token - * - * If an error occurs, it is automatically reported and execution of the API module - * is terminated using the ApiErrorReporter (via handleStatus()). If there were any - * warnings, they will automatically be included in the API call's output (again, via - * handleStatus()). - * - * @param Entity $entity The entity to save - * @param string|Summary $summary The edit summary - * @param int $flags The edit flags (see WikiPage::doEditContent) - * - * @throws LogicException if not in write mode - * @return Status the status of the save operation, as returned by EditEntity::attemptSave() - * @see EditEntity::attemptSave() - * - * @todo: this could be factored out into a controller-like class, but that controller - * would still need knowledge of the API module to be useful. We'll put it here - * for now pending further discussion. + * @see EntitySaveHelper::attemptSaveEntity */ protected function attemptSaveEntity( Entity $entity, $summary, $flags = 0 ) { - if ( !$this->isWriteMode() ) { - // sanity/safety check - throw new LogicException( 'attemptSaveEntity() cannot be used by API modules that do not return true from isWriteMode()!' ); - } - - if ( $summary instanceof Summary ) { - $summary = $this->summaryFormatter->formatSummary( $summary ); - } - - $params = $this->extractRequestParams(); - $user = $this->getUser(); - - if ( isset( $params['bot'] ) && $params['bot'] && $user->isAllowed( 'bot' ) ) { - $flags |= EDIT_FORCE_BOT; - } - - $baseRevisionId = isset( $params['baserevid'] ) ? (int)$params['baserevid'] : null; - - $editEntity = new EditEntity( - $this->titleLookup, - $this->entityRevisionLookup, - $this->entityStore, - $this->permissionChecker, - $entity, - $user, - $this->editFilterHookRunner, - $baseRevisionId, - $this->getContext() - ); - - $token = $this->evaluateTokenParam( $params ); - - $status = $editEntity->attemptSave( - $summary, - $flags, - $token - ); - - $this->handleSaveStatus( $status ); - return $status; - } - - /** - * @param array $params - * - * @return string|bool|null Token string, or false if not needed, or null if not set. - */ - private function evaluateTokenParam( array $params ) { - if ( !$this->needsToken() ) { - // False disables the token check. - return false; - } - - // Null fails the token check. - return isset( $params['token'] ) ? $params['token'] : null; + return $this->entitySaveHelper->attemptSaveEntity( $entity, $summary, $flags ); } /** diff --git a/repo/includes/api/CreateRedirect.php b/repo/includes/api/CreateRedirect.php index 7866aee..43c29c5 100644 --- a/repo/includes/api/CreateRedirect.php +++ b/repo/includes/api/CreateRedirect.php @@ -48,10 +48,12 @@ public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) { parent::__construct( $mainModule, $moduleName, $modulePrefix ); + $wikibaseRepo = WikibaseRepo::getDefaultInstance(); + $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $this->getContext() ); $this->setServices( - WikibaseRepo::getDefaultInstance()->getEntityIdParser(), - WikibaseRepo::getDefaultInstance()->getApiHelperFactory()->getErrorReporter( $this ), - WikibaseRepo::getDefaultInstance()->newRedirectCreationInteractor( $this->getUser(), $this->getContext() ) + $wikibaseRepo->getEntityIdParser(), + $apiHelperFactory->getErrorReporter( $this ), + $wikibaseRepo->newRedirectCreationInteractor( $this->getUser(), $this->getContext() ) ); } diff --git a/repo/includes/api/EntitySaveHelper.php b/repo/includes/api/EntitySaveHelper.php new file mode 100644 index 0000000..f60b45c --- /dev/null +++ b/repo/includes/api/EntitySaveHelper.php @@ -0,0 +1,240 @@ +<?php + +namespace Wikibase\Api; + +use ApiBase; +use LogicException; +use Status; +use UsageException; +use Wikibase\DataModel\Entity\Entity; +use Wikibase\EditEntity as EditEntityHandler; +use Wikibase\Lib\Store\EntityRevisionLookup; +use Wikibase\Lib\Store\EntityStore; +use Wikibase\Lib\Store\EntityTitleLookup; +use Wikibase\Repo\Hooks\EditFilterHookRunner; +use Wikibase\Repo\Store\EntityPermissionChecker; +use Wikibase\Summary; +use Wikibase\SummaryFormatter; + +/** + * Helper class for api modules to save entities. + * + * @since 0.5 + * @licence GNU GPL v2+ + * @author Adam Shorland + */ +class EntitySaveHelper { + + /** + * @var ApiBase + */ + private $apiBase; + + /** + * @var ApiErrorReporter + */ + private $errorReporter; + + /** + * @var SummaryFormatter + */ + private $summaryFormatter; + + /** + * @var EntityTitleLookup + */ + private $titleLookup; + + /** + * @var EntityRevisionLookup + */ + private $entityRevisionLookup; + + /** + * @var EntityStore + */ + private $entityStore; + + /** + * @var EntityPermissionChecker + */ + private $permissionChecker; + + /** + * @var EditFilterHookRunner + */ + private $editFilterHookRunner; + + public function __construct( + ApiBase $apiBase, + ApiErrorReporter $errorReporter, + SummaryFormatter $summaryFormatter, + EntityTitleLookup $entityTitleLookup, + EntityRevisionLookup $entityRevisionLookup, + EntityStore $entityStore, + EntityPermissionChecker $entityPermissionChecker, + EditFilterHookRunner $editFilterHookRunner + ) { + $this->apiBase = $apiBase; + $this->errorReporter = $errorReporter; + $this->summaryFormatter = $summaryFormatter; + $this->titleLookup = $entityTitleLookup; + $this->entityRevisionLookup = $entityRevisionLookup; + $this->entityStore = $entityStore; + $this->permissionChecker = $entityPermissionChecker; + $this->editFilterHookRunner = $editFilterHookRunner; + } + + /** + * Attempts to save the new entity content, chile first checking for permissions, + * edit conflicts, etc. Saving is done via EditEntityHandler::attemptSave(). + * + * This method automatically takes into account several parameters: + * * 'bot' for setting the bot flag + * * 'baserevid' for determining the edit's base revision for conflict resolution + * * 'token' for the edit token + * + * If an error occurs, it is automatically reported and execution of the API module + * is terminated using the ApiErrorReporter (via handleStatus()). If there were any + * warnings, they will automatically be included in the API call's output (again, via + * handleStatus()). + * + * @param Entity $entity The entity to save + * @param string|Summary $summary The edit summary + * @param int $flags The edit flags (see WikiPage::doEditContent) + * + * @throws LogicException if not in write mode + * @return Status the status of the save operation, as returned by EditEntityHandler::attemptSave() + * @see EditEntityHandler::attemptSave() + */ + public function attemptSaveEntity( Entity $entity, $summary, $flags = 0 ) { + if ( !$this->apiBase->isWriteMode() ) { + // sanity/safety check + throw new LogicException( + 'attemptSaveEntity() cannot be used by API modules that do not return true from isWriteMode()!' + ); + } + + if ( $summary instanceof Summary ) { + $summary = $this->summaryFormatter->formatSummary( $summary ); + } + + $params = $this->apiBase->extractRequestParams(); + $user = $this->apiBase->getContext()->getUser(); + + if ( isset( $params['bot'] ) && $params['bot'] && $user->isAllowed( 'bot' ) ) { + $flags |= EDIT_FORCE_BOT; + } + + $baseRevisionId = isset( $params['baserevid'] ) ? (int)$params['baserevid'] : null; + + $editEntityHandler = new EditEntityHandler( + $this->titleLookup, + $this->entityRevisionLookup, + $this->entityStore, + $this->permissionChecker, + $entity, + $user, + $this->editFilterHookRunner, + $baseRevisionId, + $this->apiBase->getContext() + ); + + $token = $this->evaluateTokenParam( $params ); + + $status = $editEntityHandler->attemptSave( + $summary, + $flags, + $token + ); + + $this->handleSaveStatus( $status ); + return $status; + } + + /** + * @param array $params + * + * @return string|bool|null Token string, or false if not needed, or null if not set. + */ + private function evaluateTokenParam( array $params ) { + if ( !$this->apiBase->needsToken() ) { + // False disables the token check. + return false; + } + + // Null fails the token check. + return isset( $params['token'] ) ? $params['token'] : null; + } + + /** + * Signal errors and warnings from a save operation to the API call's output. + * This is much like handleStatus(), but specialized for Status objects returned by + * EditEntityHandler::attemptSave(). In particular, the 'errorFlags' and 'errorCode' fields + * from the status value are used to determine the error code to return to the caller. + * + * @note: this function may or may not return normally, depending on whether + * the status is fatal or not. + * + * @see handleStatus(). + * + * @param Status $status The status to report + */ + private function handleSaveStatus( Status $status ) { + $value = $status->getValue(); + $errorCode = null; + + if ( is_array( $value ) && isset( $value['errorCode'] ) ) { + $errorCode = $value['errorCode']; + } else { + $editError = 0; + + if ( is_array( $value ) && isset( $value['errorFlags'] ) ) { + $editError = $value['errorFlags']; + } + + if ( ( $editError & EditEntityHandler::TOKEN_ERROR ) > 0 ) { + $errorCode = 'badtoken'; + } elseif ( ( $editError & EditEntityHandler::EDIT_CONFLICT_ERROR ) > 0 ) { + $errorCode = 'editconflict'; + } elseif ( ( $editError & EditEntityHandler::ANY_ERROR ) > 0 ) { + $errorCode = 'failed-save'; + } + } + + //NOTE: will just add warnings or do nothing if there's no error + $this->handleStatus( $status, $errorCode ); + } + + /** + * Include messages from a Status object in the API call's output. + * + * An ApiErrorHandler is used to report the status, if necessary. + * If $status->isOK() is false, this method will terminate with a UsageException. + * + * @param Status $status The status to report + * @param string $errorCode The API error code to use in case $status->isOK() returns false + * @param array $extradata Additional data to include the the error report, + * if $status->isOK() returns false + * @param int $httpRespCode the HTTP response code to use in case + * $status->isOK() returns false.+ + * + * @throws UsageException If $status->isOK() returns false. + */ + private function handleStatus( + Status $status, + $errorCode, + array $extradata = array(), + $httpRespCode = 0 + ) { + if ( $status->isGood() ) { + return; + } elseif ( $status->isOK() ) { + $this->errorReporter->reportStatusWarnings( $status ); + } else { + $this->errorReporter->reportStatusWarnings( $status ); + $this->errorReporter->dieStatus( $status, $errorCode, $httpRespCode, $extradata ); + } + } + +} diff --git a/repo/includes/api/FormatSnakValue.php b/repo/includes/api/FormatSnakValue.php index 4027434..3aa93f9 100644 --- a/repo/includes/api/FormatSnakValue.php +++ b/repo/includes/api/FormatSnakValue.php @@ -53,11 +53,12 @@ public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) { parent::__construct( $mainModule, $moduleName, $modulePrefix ); - $apiHelperFactory = WikibaseRepo::getDefaultInstance()->getApiHelperFactory(); + $wikibaseRepo = WikibaseRepo::getDefaultInstance(); + $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $this->getContext() ); $this->setServices( - WikibaseRepo::getDefaultInstance()->getValueFormatterFactory(), - WikibaseRepo::getDefaultInstance()->getDataValueFactory(), + $wikibaseRepo->getValueFormatterFactory(), + $wikibaseRepo->getDataValueFactory(), $apiHelperFactory->getErrorReporter( $this ) ); } diff --git a/repo/includes/api/MergeItems.php b/repo/includes/api/MergeItems.php index e61f53c..860992c 100644 --- a/repo/includes/api/MergeItems.php +++ b/repo/includes/api/MergeItems.php @@ -56,11 +56,12 @@ parent::__construct( $mainModule, $moduleName, $modulePrefix ); $wikibaseRepo = WikibaseRepo::getDefaultInstance(); + $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $this->getContext() ); $this->setServices( $wikibaseRepo->getEntityIdParser(), - $wikibaseRepo->getApiHelperFactory()->getErrorReporter( $this ), - $wikibaseRepo->getApiHelperFactory()->getResultBuilder( $this ), + $apiHelperFactory->getErrorReporter( $this ), + $apiHelperFactory->getResultBuilder( $this ), new ItemMergeInteractor( $wikibaseRepo->getChangeOpFactoryProvider()->getMergeChangeOpFactory(), $wikibaseRepo->getEntityRevisionLookup( 'uncached' ), diff --git a/repo/includes/api/ParseValue.php b/repo/includes/api/ParseValue.php index 369f843..ba99186 100644 --- a/repo/includes/api/ParseValue.php +++ b/repo/includes/api/ParseValue.php @@ -54,10 +54,13 @@ public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) { parent::__construct( $mainModule, $moduleName, $modulePrefix ); + $wikibaseRepo = WikibaseRepo::getDefaultInstance(); + $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $this->getContext() ); + $this->setServices( new ValueParserFactory( $GLOBALS['wgValueParsers'] ), - WikibaseRepo::getDefaultInstance()->getExceptionLocalizer(), - WikibaseRepo::getDefaultInstance()->getApiHelperFactory()->getErrorReporter( $this ) + $wikibaseRepo->getExceptionLocalizer(), + $apiHelperFactory->getErrorReporter( $this ) ); } diff --git a/repo/tests/phpunit/includes/WikibaseRepoTest.php b/repo/tests/phpunit/includes/WikibaseRepoTest.php index 5d88e42..659ff62 100644 --- a/repo/tests/phpunit/includes/WikibaseRepoTest.php +++ b/repo/tests/phpunit/includes/WikibaseRepoTest.php @@ -238,7 +238,8 @@ } public function testGetApiHelperFactory() { - $factory = $this->getWikibaseRepo()->getApiHelperFactory(); + $mockContext = $this->getMock( 'RequestContext' ); + $factory = $this->getWikibaseRepo()->getApiHelperFactory( $mockContext ); $this->assertInstanceOf( 'Wikibase\Api\ApiHelperFactory', $factory ); } diff --git a/repo/tests/phpunit/includes/api/ApiHelperFactoryTest.php b/repo/tests/phpunit/includes/api/ApiHelperFactoryTest.php index e87d84c..690c929 100644 --- a/repo/tests/phpunit/includes/api/ApiHelperFactoryTest.php +++ b/repo/tests/phpunit/includes/api/ApiHelperFactoryTest.php @@ -23,12 +23,24 @@ $exceptionLocalizer = $this->getMock( 'Wikibase\Lib\Localizer\ExceptionLocalizer' ); $dataTypeLookup = $this->getMock( 'Wikibase\DataModel\Entity\PropertyDataTypeLookup' ); $entityFactory = WikibaseRepo::getDefaultInstance()->getEntityFactory(); + $summaryFormatter = $this->getMockBuilder( 'Wikibase\SummaryFormatter' ) + ->disableOriginalConstructor()->getMock(); + $entityRevisionLookup = $this->getMock( 'Wikibase\Lib\Store\EntityRevisionLookup' ); + $entityStore = $this->getMock( 'Wikibase\Lib\Store\EntityStore' ); + $entityPermissionChecker = $this->getMock( 'Wikibase\Repo\Store\EntityPermissionChecker' ); + $editFilterHookRunner = $this->getMockBuilder( 'Wikibase\Repo\Hooks\EditFilterHookRunner' ) + ->disableOriginalConstructor()->getMock(); return new ApiHelperFactory( $titleLookup, $exceptionLocalizer, $dataTypeLookup, - $entityFactory + $entityFactory, + $summaryFormatter, + $entityRevisionLookup, + $entityStore, + $entityPermissionChecker, + $editFilterHookRunner ); } @@ -81,4 +93,11 @@ $this->assertInstanceOf( 'Wikibase\Lib\Serializers\SerializerFactory', $serializerFactory ); } + public function testGetEntitySaveHelper() { + $factory = $this->newApiHelperFactory(); + + $helper = $factory->getEntitySaveHelper( $this->newApiModule() ); + $this->assertInstanceOf( 'Wikibase\Api\EntitySaveHelper', $helper ); + } + } diff --git a/repo/tests/phpunit/includes/api/EntitySaverHelperTest.php b/repo/tests/phpunit/includes/api/EntitySaverHelperTest.php new file mode 100644 index 0000000..887174a --- /dev/null +++ b/repo/tests/phpunit/includes/api/EntitySaverHelperTest.php @@ -0,0 +1,156 @@ +<?php + +namespace Wikibase\Test\Api; + +use Status; +use TestUser; +use Title; +use Wikibase\Api\EntitySaveHelper; +use Wikibase\DataModel\Entity\Item; +use Wikibase\DataModel\Entity\ItemId; +use Wikibase\DataModel\Entity\PropertyId; +use Wikibase\DataModel\SiteLink; +use Wikibase\DataModel\Snak\PropertyNoValueSnak; + +/** + * @covers Wikibase\Test\Api\EntitySaverHelper + * + * @group Database + * @group Wikibase + * @group WikibaseAPI + * @group WikibaseRepo + * + * @licence GNU GPL v2+ + * @author Adam Shorland + */ +class EntitySaverHelperTest extends \MediaWikiTestCase { + + private function getMockApiBase() { + return $this->getMockBuilder( 'ApiBase' ) + ->disableOriginalConstructor() + ->getMock(); + } + + private function getMockErrorReporter() { + return $this->getMockBuilder( 'Wikibase\Api\ApiErrorReporter' ) + ->disableOriginalConstructor() + ->getMock(); + } + + private function getMockSummaryFormatter() { + return $this->getMockBuilder( 'Wikibase\SummaryFormatter' ) + ->disableOriginalConstructor() + ->getMock(); + } + + private function getMockEntityTitleLookup() { + return $this->getMock( 'Wikibase\Lib\Store\EntityTitleLookup' ); + } + + private function getMockEntityRevisionLookup() { + return $this->getMock( 'Wikibase\Lib\Store\EntityRevisionLookup' ); + } + + private function getMockEntityStore() { + return $this->getMock( 'Wikibase\Lib\Store\EntityStore' ); + } + + private function getMockEntityPermissionChecker() { + return $this->getMock( 'Wikibase\Repo\Store\EntityPermissionChecker' ); + } + + private function getMockEditFilterHookRunner() { + return $this->getMockBuilder( 'Wikibase\Repo\Hooks\EditFilterHookRunner' ) + ->disableOriginalConstructor() + ->getMock(); + } + + private function getMockContext() { + return $this->getMock( 'RequestContext' ); + } + + public function testAttemptSave() { + $testUser = new TestUser( 'aUser' ); + + $mockContext = $this->getMockContext(); + $mockContext->expects( $this->once() ) + ->method( 'getUser' ) + ->will( $this->returnValue( $testUser->getUser() ) ); + + $mockApiBase = $this->getMockApiBase(); + $mockApiBase->expects( $this->once() ) + ->method( 'isWriteMode' ) + ->will( $this->returnValue( true ) ); + $mockApiBase->expects( $this->atLeastOnce() ) + ->method( 'getContext' ) + ->will( $this->returnValue( $mockContext ) ); + $mockApiBase->expects( $this->atLeastOnce() ) + ->method( 'extractRequestParams' ) + ->will( $this->returnValue( array() ) ); + + $mockTitleLookup = $this->getMockEntityTitleLookup(); + $mockTitleLookup->expects( $this->atLeastOnce() ) + ->method( 'getTitleForId' ) + ->will( $this->returnValue( Title::newFromText( 'Title' ) ) ); + + $mockEntityStore = $this->getMockEntityStore(); + $mockEntityStore->expects( $this->once() ) + ->method( 'updateWatchlist' ); + + $mockEntityPermissionChecker = $this->getMockEntityPermissionChecker(); + $mockEntityPermissionChecker->expects( $this->atLeastOnce() ) + ->method( 'getPermissionStatusForEntity' ) + ->will( $this->returnValue( Status::newGood() ) ); + + $mockEditFilterHookRunner = $this->getMockEditFilterHookRunner(); + $mockEditFilterHookRunner->expects( $this->atLeastOnce() ) + ->method( 'run' ) + ->will( $this->returnValue( Status::newGood() ) ); + + $helper = new EntitySaveHelper( + $mockApiBase, + $this->getMockErrorReporter(), + $this->getMockSummaryFormatter(), + $mockTitleLookup, + $this->getMockEntityRevisionLookup(), + $mockEntityStore, + $mockEntityPermissionChecker, + $mockEditFilterHookRunner + ); + + $entity = new Item(); + $entity->setId( new ItemId( 'Q444' ) ); + $entity->getFingerprint()->setLabel( 'en', 'Foo' ); + $entity->getSiteLinkList()->addSiteLink( new SiteLink( 'enwiki', 'APage' ) ); + $entity->getStatements()->addNewStatement( new PropertyNoValueSnak( new PropertyId( 'P8' ) ) ); + + $summary = 'A String Summary'; + $flags = 0; + + $status = $helper->attemptSaveEntity( $entity, $summary, $flags ); + + $this->assertTrue( $status->isGood() ); + } + + public function testSaveThrowsException_onNonWriteMode() { + $mockApiBase = $this->getMockApiBase(); + $mockApiBase->expects( $this->once() ) + ->method( 'isWriteMode' ) + ->will( $this->returnValue( false ) ); + + $helper = new EntitySaveHelper( + $mockApiBase, + $this->getMockErrorReporter(), + $this->getMockSummaryFormatter(), + $this->getMockEntityTitleLookup(), + $this->getMockEntityRevisionLookup(), + $this->getMockEntityStore(), + $this->getMockEntityPermissionChecker(), + $this->getMockEditFilterHookRunner() + ); + + $this->setExpectedException( 'LogicException' ); + $helper->attemptSaveEntity( new Item(), '' ); + } + +} diff --git a/repo/tests/phpunit/includes/api/MergeItemsTest.php b/repo/tests/phpunit/includes/api/MergeItemsTest.php index c187f6e..06fde18 100644 --- a/repo/tests/phpunit/includes/api/MergeItemsTest.php +++ b/repo/tests/phpunit/includes/api/MergeItemsTest.php @@ -93,10 +93,14 @@ Language::factory( 'en' ) ); - $resultBuilder = WikibaseRepo::getDefaultInstance()->getApiHelperFactory()->getResultBuilder( $module ); - $summaryFormatter = WikibaseRepo::getDefaultInstance()->getSummaryFormatter(); + $mockContext = $this->getMock( 'RequestContext' ); + $wikibaseRepo = WikibaseRepo::getDefaultInstance(); + $apiHelperFactory = $wikibaseRepo->getApiHelperFactory( $mockContext ); - $changeOpsFactory = WikibaseRepo::getDefaultInstance()->getChangeOpFactoryProvider()->getMergeChangeOpFactory(); + $resultBuilder = $apiHelperFactory->getResultBuilder( $module ); + $summaryFormatter = $wikibaseRepo->getSummaryFormatter(); + + $changeOpsFactory = $wikibaseRepo->getChangeOpFactoryProvider()->getMergeChangeOpFactory(); $module->setServices( $idParser, -- To view, visit https://gerrit.wikimedia.org/r/222772 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie426c1828a69623c9cced688eb7bf7992a8b437f Gerrit-PatchSet: 12 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Jeroen De Dauw <jeroended...@gmail.com> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits