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

Reply via email to