diff --git a/lib/internal/Magento/Framework/Module/Plugin/DbStatusValidator.php b/lib/internal/Magento/Framework/Module/Plugin/DbStatusValidator.php index bdaf59f02c300..30b2a370bcb42 100644 --- a/lib/internal/Magento/Framework/Module/Plugin/DbStatusValidator.php +++ b/lib/internal/Magento/Framework/Module/Plugin/DbStatusValidator.php @@ -50,14 +50,22 @@ public function __construct(FrontendCacheInterface $cache, DbVersionInfo $dbVers public function beforeDispatch(FrontController $subject, RequestInterface $request) { if (!$this->cache->load('db_is_up_to_date')) { - $errors = $this->dbVersionInfo->getDbVersionErrors(); - - if ($errors) { + list($versionTooLowErrors, $versionTooHighErrors) = array_values($this->getGroupedDbVersionErrors()); + if ($versionTooHighErrors) { + $message = 'Please update your modules: ' + . "Run \"composer install\" from the Magento root directory.\n" + . "The following modules are outdated:\n%1"; + throw new LocalizedException( + new Phrase($message, [implode("\n", $this->formatVersionTooHighErrors($versionTooHighErrors))]) + ); + } elseif ($versionTooLowErrors) { $message = 'Please upgrade your database: ' . "Run \"bin/magento setup:upgrade\" from the Magento root directory.\n" . "The following modules are outdated:\n%1"; - throw new LocalizedException(new Phrase($message, [implode("\n", $this->formatErrors($errors))])); + throw new LocalizedException( + new Phrase($message, [implode("\n", $this->formatVersionTooLowErrors($versionTooLowErrors))]) + ); } else { $this->cache->save('true', 'db_is_up_to_date'); } @@ -70,7 +78,7 @@ public function beforeDispatch(FrontController $subject, RequestInterface $reque * @param array $errorsData array of error data from getOutOfDateDbErrors * @return array Messages that can be used to log the error */ - private function formatErrors($errorsData) + private function formatVersionTooLowErrors($errorsData) { $formattedErrors = []; @@ -82,4 +90,49 @@ private function formatErrors($errorsData) return $formattedErrors; } + + /** + * Format each error in the error data from getOutOfDataDbErrors into a single message + * + * @param array $errorsData array of error data from getOutOfDateDbErrors + * @return array Messages that can be used to log the error + */ + private function formatVersionTooHighErrors($errorsData) + { + $formattedErrors = []; + foreach ($errorsData as $error) { + $formattedErrors[] = $error[DbVersionInfo::KEY_MODULE] . ' ' . $error[DbVersionInfo::KEY_TYPE] + . ': code version - ' . $error[DbVersionInfo::KEY_REQUIRED] + . ', database version - ' . $error[DbVersionInfo::KEY_CURRENT]; + } + + return $formattedErrors; + } + + /** + * Return DB version errors grouped by 'version_too_low' and 'version_too_high' + * + * @return mixed + */ + private function getGroupedDbVersionErrors() + { + $allDbVersionErrors = $this->dbVersionInfo->getDbVersionErrors(); + return array_reduce( + (array)$allDbVersionErrors, + function ($carry, $item) { + if ($item[DbVersionInfo::KEY_CURRENT] === 'none' + || $item[DbVersionInfo::KEY_CURRENT] < $item[DbVersionInfo::KEY_REQUIRED] + ) { + $carry['version_too_low'][] = $item; + } else { + $carry['version_too_high'][] = $item; + } + return $carry; + }, + [ + 'version_too_low' => [], + 'version_too_high' => [], + ] + ); + } } diff --git a/lib/internal/Magento/Framework/Test/Unit/Module/Plugin/DbStatusValidatorTest.php b/lib/internal/Magento/Framework/Test/Unit/Module/Plugin/DbStatusValidatorTest.php index 3e739c3688694..4968e41613dd5 100644 --- a/lib/internal/Magento/Framework/Test/Unit/Module/Plugin/DbStatusValidatorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/Module/Plugin/DbStatusValidatorTest.php @@ -99,28 +99,11 @@ public function testBeforeDispatchOutOfDateNoErrors() $this->plugin->beforeDispatch($this->frontControllerMock, $this->requestMock); } - public function testBeforeDispatchOutOfDateWithErrors() + /** + * @dataProvider beforeDispatchOutOfDateWithErrorsDataProvider + */ + public function testBeforeDispatchOutOfDateWithErrors(array $errors, string $expectedMessage) { - $errors = [ - [ - DbVersionInfo::KEY_MODULE => 'Magento_Module1', - DbVersionInfo::KEY_TYPE => 'schema', - DbVersionInfo::KEY_CURRENT => '3.3.3', - DbVersionInfo::KEY_REQUIRED => '4.4.4' - ], - [ - DbVersionInfo::KEY_MODULE => 'Magento_Module2', - DbVersionInfo::KEY_TYPE => 'data', - DbVersionInfo::KEY_CURRENT => '2.8.7', - DbVersionInfo::KEY_REQUIRED => '5.1.6' - ] - ]; - $message = 'Please upgrade your database: ' - . "Run \"bin/magento setup:upgrade\" from the Magento root directory.\n" - . "The following modules are outdated:\n" - . "Magento_Module1 schema: current version - 3.3.3, required version - 4.4.4\n" - . "Magento_Module2 data: current version - 2.8.7, required version - 5.1.6"; - $this->cacheMock->expects(static::any()) ->method('load') ->with('db_is_up_to_date') @@ -131,7 +114,76 @@ public function testBeforeDispatchOutOfDateWithErrors() $this->cacheMock->expects(static::never()) ->method('save'); - $this->expectException(LocalizedException::class, $message); + $this->expectException(LocalizedException::class, $expectedMessage); + $this->expectExceptionMessage($expectedMessage); $this->plugin->beforeDispatch($this->frontControllerMock, $this->requestMock); } + + public static function beforeDispatchOutOfDateWithErrorsDataProvider() + { + return [ + 'module versions too low' => [ + 'errors' => [ + [ + DbVersionInfo::KEY_MODULE => 'Magento_Module1', + DbVersionInfo::KEY_TYPE => 'schema', + DbVersionInfo::KEY_CURRENT => 'none', + DbVersionInfo::KEY_REQUIRED => '4.4.4' + ], + [ + DbVersionInfo::KEY_MODULE => 'Magento_Module2', + DbVersionInfo::KEY_TYPE => 'data', + DbVersionInfo::KEY_CURRENT => '2.8.7', + DbVersionInfo::KEY_REQUIRED => '5.1.6' + ], + ], + 'expectedMessage' => 'Please upgrade your database: ' + . "Run \"bin/magento setup:upgrade\" from the Magento root directory.\n" + . "The following modules are outdated:\n" + . "Magento_Module1 schema: current version - none, required version - 4.4.4\n" + . "Magento_Module2 data: current version - 2.8.7, required version - 5.1.6" + ], + 'module versions too high' => [ + 'errors' => [ + [ + DbVersionInfo::KEY_MODULE => 'Magento_Module3', + DbVersionInfo::KEY_TYPE => 'schema', + DbVersionInfo::KEY_CURRENT => '2.0.0', + DbVersionInfo::KEY_REQUIRED => '1.0.0' + ], + [ + DbVersionInfo::KEY_MODULE => 'Magento_Module4', + DbVersionInfo::KEY_TYPE => 'data', + DbVersionInfo::KEY_CURRENT => '1.0.1', + DbVersionInfo::KEY_REQUIRED => '1.0.0' + ], + ], + 'expectedMessage' => "Please update your modules: " + . "Run \"composer install\" from the Magento root directory.\n" + . "The following modules are outdated:\n" + . "Magento_Module3 schema: code version - 1.0.0, database version - 2.0.0\n" + . "Magento_Module4 data: code version - 1.0.0, database version - 1.0.1", + ], + 'some versions too high, some too low' => [ + 'errors' => [ + [ + DbVersionInfo::KEY_MODULE => 'Magento_Module1', + DbVersionInfo::KEY_TYPE => 'schema', + DbVersionInfo::KEY_CURRENT => '2.0.0', + DbVersionInfo::KEY_REQUIRED => '1.0.0' + ], + [ + DbVersionInfo::KEY_MODULE => 'Magento_Module2', + DbVersionInfo::KEY_TYPE => 'schema', + DbVersionInfo::KEY_CURRENT => '1.0.0', + DbVersionInfo::KEY_REQUIRED => '2.0.0' + ], + ], + 'expectedMessage' => "Please update your modules: " + . "Run \"composer install\" from the Magento root directory.\n" + . "The following modules are outdated:\n" + . "Magento_Module1 schema: code version - 1.0.0, database version - 2.0.0" + ] + ]; + } }