diff --git a/app/code/Magento/Catalog/Api/ProductRepositoryInterface.php b/app/code/Magento/Catalog/Api/ProductRepositoryInterface.php
index 6fddee979e07f..0f9b9c2589fa5 100644
--- a/app/code/Magento/Catalog/Api/ProductRepositoryInterface.php
+++ b/app/code/Magento/Catalog/Api/ProductRepositoryInterface.php
@@ -41,7 +41,7 @@ public function get($sku, $editMode = false, $storeId = null, $forceReload = fal
*
* @param int $productId
* @param bool $editMode
- * @param null|int $storeId
+ * @param int|null $storeId
* @param bool $forceReload
* @return \Magento\Catalog\Api\Data\ProductInterface
* @throws \Magento\Framework\Exception\NoSuchEntityException
diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php
index 161b72ada2c70..a498d464eaf94 100644
--- a/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php
+++ b/app/code/Magento/Newsletter/Test/Unit/Model/Queue/TransportBuilderTest.php
@@ -8,7 +8,7 @@
use Magento\Framework\App\TemplateTypesInterface;
use Magento\Framework\Mail\MessageInterface;
-class TransportBuilderTest extends \Magento\Framework\Mail\Test\Unit\Template\TransportBuilderTest
+class TransportBuilderTest extends \PHPUnit_Framework_TestCase
{
/**
* @var string
@@ -20,20 +20,68 @@ class TransportBuilderTest extends \Magento\Framework\Mail\Test\Unit\Template\Tr
*/
protected $builder;
+ /**
+ * @var \Magento\Framework\Mail\Template\FactoryInterface | \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $templateFactoryMock;
+
+ /**
+ * @var \Magento\Framework\Mail\Message | \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $messageMock;
+
+ /**
+ * @var \Magento\Framework\ObjectManagerInterface | \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $objectManagerMock;
+
+ /**
+ * @var \Magento\Framework\Mail\Template\SenderResolverInterface | \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $senderResolverMock;
+
+ /**
+ * @var \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $mailTransportFactoryMock;
+
+ /**
+ * @return void
+ */
+ public function setUp()
+ {
+ $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+ $this->templateFactoryMock = $this->getMock('Magento\Framework\Mail\Template\FactoryInterface');
+ $this->messageMock = $this->getMock('Magento\Framework\Mail\Message');
+ $this->objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface');
+ $this->senderResolverMock = $this->getMock('Magento\Framework\Mail\Template\SenderResolverInterface');
+ $this->mailTransportFactoryMock = $this->getMockBuilder('Magento\Framework\Mail\TransportInterfaceFactory')
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $this->builder = $objectManagerHelper->getObject(
+ $this->builderClassName,
+ [
+ 'templateFactory' => $this->templateFactoryMock,
+ 'message' => $this->messageMock,
+ 'objectManager' => $this->objectManagerMock,
+ 'senderResolver' => $this->senderResolverMock,
+ 'mailTransportFactory' => $this->mailTransportFactoryMock
+ ]
+ );
+ }
+
/**
* @param int $templateType
* @param string $messageType
* @param string $bodyText
- * @param string $templateNamespace
* @return void
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function testGetTransport(
$templateType = TemplateTypesInterface::TYPE_HTML,
$messageType = MessageInterface::TYPE_HTML,
- $bodyText = '
Html message
',
- $templateNamespace = ''
+ $bodyText = 'Html message
'
) {
$filter = $this->getMock('Magento\Email\Model\Template\Filter', [], [], '', false);
$data = [
diff --git a/app/code/Magento/Store/Model/Plugin/StoreCookie.php b/app/code/Magento/Store/Model/Plugin/StoreCookie.php
index cb4ec64e03a2f..b42e645799867 100644
--- a/app/code/Magento/Store/Model/Plugin/StoreCookie.php
+++ b/app/code/Magento/Store/Model/Plugin/StoreCookie.php
@@ -52,29 +52,25 @@ public function __construct(
* Delete cookie "store" if the store (a value in the cookie) does not exist or is inactive
*
* @param \Magento\Framework\App\FrontController $subject
- * @param callable $proceed
* @param \Magento\Framework\App\RequestInterface $request
- * @return mixed
+ * @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
- public function aroundDispatch(
+ public function beforeDispatch(
\Magento\Framework\App\FrontController $subject,
- \Closure $proceed,
\Magento\Framework\App\RequestInterface $request
) {
- $defaultStore = $this->storeManager->getDefaultStoreView();
$storeCodeFromCookie = $this->storeCookieManager->getStoreCodeFromCookie();
if ($storeCodeFromCookie) {
try {
$this->storeRepository->getActiveStoreByCode($storeCodeFromCookie);
} catch (StoreIsInactiveException $e) {
- $this->storeCookieManager->deleteStoreCookie($defaultStore);
+ $this->storeCookieManager->deleteStoreCookie($this->storeManager->getDefaultStoreView());
} catch (NoSuchEntityException $e) {
- $this->storeCookieManager->deleteStoreCookie($defaultStore);
+ $this->storeCookieManager->deleteStoreCookie($this->storeManager->getDefaultStoreView());
} catch (InvalidArgumentException $e) {
- $this->storeCookieManager->deleteStoreCookie($defaultStore);
+ $this->storeCookieManager->deleteStoreCookie($this->storeManager->getDefaultStoreView());
}
}
- return $proceed($request);
}
}
diff --git a/app/code/Magento/Store/Model/StoreResolver.php b/app/code/Magento/Store/Model/StoreResolver.php
index f609e271ffd6c..b87a5aabf6f71 100644
--- a/app/code/Magento/Store/Model/StoreResolver.php
+++ b/app/code/Magento/Store/Model/StoreResolver.php
@@ -45,6 +45,11 @@ class StoreResolver implements \Magento\Store\Api\StoreResolverInterface
*/
protected $scopeCode;
+ /*
+ * @var \Magento\Framework\App\RequestInterface
+ */
+ protected $request;
+
/**
* @param \Magento\Store\Api\StoreRepositoryInterface $storeRepository
* @param StoreCookieManagerInterface $storeCookieManager
diff --git a/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php b/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php
index 3b2197494bef8..43a471fba9ffc 100644
--- a/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php
+++ b/app/code/Magento/Store/Test/Unit/Model/Plugin/StoreCookieTest.php
@@ -37,11 +37,6 @@ class StoreCookieTest extends \PHPUnit_Framework_TestCase
*/
protected $storeMock;
- /**
- * @var \Closure
- */
- protected $closureMock;
-
/**
* @var \Magento\Framework\App\FrontController|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -77,10 +72,6 @@ public function setUp()
->setMethods([])
->getMock();
- $this->closureMock = function () {
- return 'ExpectedValue';
- };
-
$this->subjectMock = $this->getMockBuilder('Magento\Framework\App\FrontController')
->disableOriginalConstructor()
->setMethods([])
@@ -106,7 +97,7 @@ public function setUp()
);
}
- public function testAroundDispatchNoSuchEntity()
+ public function testBeforeDispatchNoSuchEntity()
{
$storeCode = 'store';
$this->storeManagerMock->expects($this->once())->method('getDefaultStoreView')->willReturn($this->storeMock);
@@ -115,13 +106,10 @@ public function testAroundDispatchNoSuchEntity()
->method('getActiveStoreByCode')
->willThrowException(new NoSuchEntityException);
$this->storeCookieManagerMock->expects($this->once())->method('deleteStoreCookie')->with($this->storeMock);
- $this->assertEquals(
- 'ExpectedValue',
- $this->plugin->aroundDispatch($this->subjectMock, $this->closureMock, $this->requestMock)
- );
+ $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock);
}
- public function testAroundDispatchStoreIsInactive()
+ public function testBeforeDispatchStoreIsInactive()
{
$storeCode = 'store';
$this->storeManagerMock->expects($this->once())->method('getDefaultStoreView')->willReturn($this->storeMock);
@@ -130,13 +118,10 @@ public function testAroundDispatchStoreIsInactive()
->method('getActiveStoreByCode')
->willThrowException(new StoreIsInactiveException);
$this->storeCookieManagerMock->expects($this->once())->method('deleteStoreCookie')->with($this->storeMock);
- $this->assertEquals(
- 'ExpectedValue',
- $this->plugin->aroundDispatch($this->subjectMock, $this->closureMock, $this->requestMock)
- );
+ $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock);
}
- public function testAroundDispatchInvalidArgument()
+ public function testBeforeDispatchInvalidArgument()
{
$storeCode = 'store';
$this->storeManagerMock->expects($this->once())->method('getDefaultStoreView')->willReturn($this->storeMock);
@@ -145,22 +130,16 @@ public function testAroundDispatchInvalidArgument()
->method('getActiveStoreByCode')
->willThrowException(new InvalidArgumentException);
$this->storeCookieManagerMock->expects($this->once())->method('deleteStoreCookie')->with($this->storeMock);
- $this->assertEquals(
- 'ExpectedValue',
- $this->plugin->aroundDispatch($this->subjectMock, $this->closureMock, $this->requestMock)
- );
+ $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock);
}
- public function testAroundDispatchNoStoreCookie()
+ public function testBeforeDispatchNoStoreCookie()
{
$storeCode = null;
- $this->storeManagerMock->expects($this->once())->method('getDefaultStoreView')->willReturn($this->storeMock);
$this->storeCookieManagerMock->expects($this->once())->method('getStoreCodeFromCookie')->willReturn($storeCode);
+ $this->storeManagerMock->expects($this->never())->method('getDefaultStoreView')->willReturn($this->storeMock);
$this->storeRepositoryMock->expects($this->never())->method('getActiveStoreByCode');
$this->storeCookieManagerMock->expects($this->never())->method('deleteStoreCookie')->with($this->storeMock);
- $this->assertEquals(
- 'ExpectedValue',
- $this->plugin->aroundDispatch($this->subjectMock, $this->closureMock, $this->requestMock)
- );
+ $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock);
}
}
diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml
index b72ef3a7b1676..3b8d21188b28f 100644
--- a/app/code/Magento/Store/etc/di.xml
+++ b/app/code/Magento/Store/etc/di.xml
@@ -281,6 +281,11 @@
+
+
+ Magento\Store\Model\StoreManagerInterface\Proxy
+
+
Magento\Framework\App\Cache\Type\Config
diff --git a/app/code/Magento/User/Model/ResourceModel/User.php b/app/code/Magento/User/Model/ResourceModel/User.php
index 1c87be70f24ef..6f782c75f3108 100644
--- a/app/code/Magento/User/Model/ResourceModel/User.php
+++ b/app/code/Magento/User/Model/ResourceModel/User.php
@@ -539,7 +539,7 @@ public function getOldPasswords($user, $retainLimit = 4)
$userId = (int)$user->getId();
$table = $this->getTable('admin_passwords');
- // purge expired passwords, except that should retain
+ // purge expired passwords, except those which should be retained
$retainPasswordIds = $this->getConnection()->fetchCol(
$this->getConnection()
->select()
@@ -556,7 +556,7 @@ public function getOldPasswords($user, $retainLimit = 4)
}
$this->getConnection()->delete($table, $where);
- // now get all remained passwords
+ // get all remaining passwords
return $this->getConnection()->fetchCol(
$this->getConnection()
->select()
diff --git a/app/code/Magento/User/Model/User.php b/app/code/Magento/User/Model/User.php
index b9573b4f76e30..c5d38e8b98e25 100644
--- a/app/code/Magento/User/Model/User.php
+++ b/app/code/Magento/User/Model/User.php
@@ -256,9 +256,9 @@ protected function _getValidationRulesBeforeSave()
}
/**
- * Validate customer attribute values.
- * For existing customer password + confirmation will be validated only when password is set
- * (i.e. its change is requested)
+ * Validate admin user data.
+ *
+ * Existing user password confirmation will be validated only when password is set
*
* @return bool|string[]
*/
@@ -272,8 +272,35 @@ public function validate()
return $validator->getMessages();
}
- return true;
+ return $this->validatePasswordChange();
+ }
+
+ /**
+ * Make sure admin password was changed.
+ *
+ * New password is compared to at least 4 previous passwords to prevent setting them again
+ *
+ * @return bool|string[]
+ */
+ protected function validatePasswordChange()
+ {
+ $password = $this->getPassword();
+ if ($password && !$this->getForceNewPassword() && $this->getId()) {
+ $errorMessage = __('Sorry, but this password has already been used. Please create another.');
+ // Check if password is equal to the current one
+ if ($this->_encryptor->isValidHash($password, $this->getOrigData('password'))) {
+ return [$errorMessage];
+ }
+ // Check whether password was used before
+ $passwordHash = $this->_encryptor->getHash($password, false);
+ foreach ($this->getResource()->getOldPasswords($this) as $oldPasswordHash) {
+ if ($passwordHash === $oldPasswordHash) {
+ return [$errorMessage];
+ }
+ }
+ }
+ return true;
}
/**
diff --git a/app/code/Magento/User/Observer/Backend/CheckAdminPasswordChangeObserver.php b/app/code/Magento/User/Observer/Backend/CheckAdminPasswordChangeObserver.php
deleted file mode 100644
index 3bf06a441e248..0000000000000
--- a/app/code/Magento/User/Observer/Backend/CheckAdminPasswordChangeObserver.php
+++ /dev/null
@@ -1,82 +0,0 @@
-userResource = $userResource;
- $this->encryptor = $encryptor;
- }
-
- /**
- * Harden admin password change.
- *
- * New password must be minimum 7 chars length and include alphanumeric characters
- * The password is compared to at least last 4 previous passwords to prevent setting them again
- *
- * @param EventObserver $observer
- * @return void
- * @throws \Magento\Framework\Exception\LocalizedException
- */
- public function execute(EventObserver $observer)
- {
- /* @var $user \Magento\User\Model\User */
- $user = $observer->getEvent()->getObject();
-
- if ($user->getNewPassword()) {
- $password = $user->getNewPassword();
- } else {
- $password = $user->getPassword();
- }
-
- if ($password && !$user->getForceNewPassword() && $user->getId()) {
- if ($this->encryptor->isValidHash($password, $user->getOrigData('password'))) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('Sorry, but this password has already been used. Please create another.')
- );
- }
-
- // check whether password was used before
- $passwordHash = $this->encryptor->getHash($password, false);
- foreach ($this->userResource->getOldPasswords($user) as $oldPasswordHash) {
- if ($passwordHash === $oldPasswordHash) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('Sorry, but this password has already been used. Please create another.')
- );
- }
- }
- }
- }
-}
diff --git a/app/code/Magento/User/Observer/Backend/TrackAdminNewPasswordObserver.php b/app/code/Magento/User/Observer/Backend/TrackAdminNewPasswordObserver.php
index 790d78301f058..0f33107ac0173 100644
--- a/app/code/Magento/User/Observer/Backend/TrackAdminNewPasswordObserver.php
+++ b/app/code/Magento/User/Observer/Backend/TrackAdminNewPasswordObserver.php
@@ -71,7 +71,7 @@ public function __construct(
}
/**
- * Save new admin password
+ * Save current admin password to prevent its usage when changed in the future.
*
* @param EventObserver $observer
* @return void
@@ -81,7 +81,7 @@ public function execute(EventObserver $observer)
/* @var $user \Magento\User\Model\User */
$user = $observer->getEvent()->getObject();
if ($user->getId()) {
- $password = $user->getNewPassword();
+ $password = $user->getCurrentPassword();
$passwordLifetime = $this->observerConfig->getAdminPasswordLifetime();
if ($passwordLifetime && $password && !$user->getForceNewPassword()) {
$passwordHash = $this->encryptor->getHash($password, false);
diff --git a/app/code/Magento/User/Test/Unit/Model/UserTest.php b/app/code/Magento/User/Test/Unit/Model/UserTest.php
index ed495d41e369d..d2f89414527de 100644
--- a/app/code/Magento/User/Test/Unit/Model/UserTest.php
+++ b/app/code/Magento/User/Test/Unit/Model/UserTest.php
@@ -610,4 +610,104 @@ public function testIsResetPasswordLinkTokenExpiredIsNotExpiredToken()
$this->userDataMock->expects($this->once())->method('getResetPasswordLinkExpirationPeriod')->willReturn(1);
$this->assertFalse($this->model->isResetPasswordLinkTokenExpired());
}
+
+ public function testCheckPasswordChangeEqualToCurrent()
+ {
+ /** @var $validatorMock \Magento\Framework\Validator\DataObject|\PHPUnit_Framework_MockObject_MockObject */
+ $validatorMock = $this->getMockBuilder('Magento\Framework\Validator\DataObject')
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMock();
+ $this->validatorObjectFactoryMock->expects($this->once())->method('create')->willReturn($validatorMock);
+ $this->validationRulesMock->expects($this->once())
+ ->method('addUserInfoRules')
+ ->with($validatorMock);
+ $validatorMock->expects($this->once())->method('isValid')->willReturn(true);
+
+ $newPassword = "NEWmYn3wpassw0rd";
+ $oldPassword = "OLDmYn3wpassw0rd";
+ $this->model->setPassword($newPassword)
+ ->setId(1)
+ ->setOrigData('password', $oldPassword);
+ $this->encryptorMock->expects($this->once())
+ ->method('isValidHash')
+ ->with($newPassword, $oldPassword)
+ ->willReturn(true);
+ $result = $this->model->validate();
+ $this->assertInternalType('array', $result);
+ $this->assertCount(1, $result);
+ $this->assertContains("Sorry, but this password has already been used.", (string)$result[0]);
+ }
+
+ public function testCheckPasswordChangeEqualToPrevious()
+ {
+ /** @var $validatorMock \Magento\Framework\Validator\DataObject|\PHPUnit_Framework_MockObject_MockObject */
+ $validatorMock = $this->getMockBuilder('Magento\Framework\Validator\DataObject')
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMock();
+ $this->validatorObjectFactoryMock->expects($this->once())->method('create')->willReturn($validatorMock);
+ $this->validationRulesMock->expects($this->once())
+ ->method('addUserInfoRules')
+ ->with($validatorMock);
+ $validatorMock->expects($this->once())->method('isValid')->willReturn(true);
+
+ $newPassword = "NEWmYn3wpassw0rd";
+ $newPasswordHash = "new password hash";
+ $oldPassword = "OLDmYn3wpassw0rd";
+ $this->model->setPassword($newPassword)
+ ->setId(1)
+ ->setOrigData('password', $oldPassword);
+ $this->encryptorMock->expects($this->once())
+ ->method('isValidHash')
+ ->with($newPassword, $oldPassword)
+ ->willReturn(false);
+
+ $this->encryptorMock->expects($this->once())
+ ->method('getHash')
+ ->with($newPassword, false)
+ ->willReturn($newPasswordHash);
+
+ $this->resourceMock->expects($this->once())->method('getOldPasswords')->willReturn(['hash1', $newPasswordHash]);
+
+ $result = $this->model->validate();
+ $this->assertInternalType('array', $result);
+ $this->assertCount(1, $result);
+ $this->assertContains("Sorry, but this password has already been used.", (string)$result[0]);
+ }
+
+ public function testCheckPasswordChangeValid()
+ {
+ /** @var $validatorMock \Magento\Framework\Validator\DataObject|\PHPUnit_Framework_MockObject_MockObject */
+ $validatorMock = $this->getMockBuilder('Magento\Framework\Validator\DataObject')
+ ->disableOriginalConstructor()
+ ->setMethods([])
+ ->getMock();
+ $this->validatorObjectFactoryMock->expects($this->once())->method('create')->willReturn($validatorMock);
+ $this->validationRulesMock->expects($this->once())
+ ->method('addUserInfoRules')
+ ->with($validatorMock);
+ $validatorMock->expects($this->once())->method('isValid')->willReturn(true);
+
+ $newPassword = "NEWmYn3wpassw0rd";
+ $newPasswordHash = "new password hash";
+ $oldPassword = "OLDmYn3wpassw0rd";
+ $this->model->setPassword($newPassword)
+ ->setId(1)
+ ->setOrigData('password', $oldPassword);
+ $this->encryptorMock->expects($this->once())
+ ->method('isValidHash')
+ ->with($newPassword, $oldPassword)
+ ->willReturn(false);
+
+ $this->encryptorMock->expects($this->once())
+ ->method('getHash')
+ ->with($newPassword, false)
+ ->willReturn($newPasswordHash);
+
+ $this->resourceMock->expects($this->once())->method('getOldPasswords')->willReturn(['hash1', 'hash2']);
+
+ $result = $this->model->validate();
+ $this->assertTrue($result);
+ }
}
diff --git a/app/code/Magento/User/Test/Unit/Observer/Backend/CheckAdminPasswordChangeObserverTest.php b/app/code/Magento/User/Test/Unit/Observer/Backend/CheckAdminPasswordChangeObserverTest.php
deleted file mode 100644
index a4b9b37edbfa8..0000000000000
--- a/app/code/Magento/User/Test/Unit/Observer/Backend/CheckAdminPasswordChangeObserverTest.php
+++ /dev/null
@@ -1,126 +0,0 @@
-userMock = $this->getMockBuilder('Magento\User\Model\ResourceModel\User')
- ->disableOriginalConstructor()
- ->setMethods([])
- ->getMock();
-
- $this->encryptorMock = $this->getMockBuilder('\Magento\Framework\Encryption\EncryptorInterface')
- ->disableOriginalConstructor()
- ->setMethods([])
- ->getMock();
-
- $this->eventManagerMock = $this->getMockBuilder('Magento\Framework\Event\ManagerInterface')
- ->disableOriginalConstructor()
- ->setMethods([])
- ->getMockForAbstractClass();
-
- $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-
- $this->model = $helper->getObject(
- '\Magento\User\Observer\Backend\CheckAdminPasswordChangeObserver',
- [
- 'userResource' => $this->userMock,
- 'encryptor' => $this->encryptorMock,
- ]
- );
- }
-
- public function testCheckAdminPasswordChange()
- {
- $newPW = "mYn3wpassw0rd";
- $uid = 123;
- /** @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject $eventObserverMock */
- $eventObserverMock = $this->getMockBuilder('Magento\Framework\Event\Observer')
- ->disableOriginalConstructor()
- ->setMethods([])
- ->getMock();
-
- /** @var \Magento\Framework\Event|\PHPUnit_Framework_MockObject_MockObject */
- $eventMock = $this->getMockBuilder('Magento\Framework\Event')
- ->disableOriginalConstructor()
- ->setMethods(['getObject'])
- ->getMock();
-
- /** @var \Magento\User\Model\User|\PHPUnit_Framework_MockObject_MockObject $userMock */
- $userMock = $this->getMockBuilder('Magento\User\Model\User')
- ->disableOriginalConstructor()
- ->setMethods(['getId', 'getNewPassword', 'getForceNewPassword'])
- ->getMock();
-
- $eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock);
- $eventMock->expects($this->once())->method('getObject')->willReturn($userMock);
- $userMock->expects($this->atLeastOnce())->method('getNewPassword')->willReturn($newPW);
- $userMock->expects($this->once())->method('getForceNewPassword')->willReturn(false);
- $userMock->expects($this->once())->method('getId')->willReturn($uid);
- $this->encryptorMock->expects($this->once())->method('isValidHash')->willReturn(false);
- $this->encryptorMock->expects($this->once())->method('getHash')->willReturn(md5($newPW));
- $this->userMock->method('getOldPasswords')->willReturn([md5('pw1'), md5('pw2')]);
-
- $this->model->execute($eventObserverMock);
- }
-
- public function testCheckAdminPasswordChangeThrowsLocalizedExp()
- {
- $newPW = "mYn3wpassw0rd";
- $uid = 123;
- /** @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject $eventObserverMock */
- $eventObserverMock = $this->getMockBuilder('Magento\Framework\Event\Observer')
- ->disableOriginalConstructor()
- ->setMethods([])
- ->getMock();
-
- /** @var \Magento\Framework\Event|\PHPUnit_Framework_MockObject_MockObject */
- $eventMock = $this->getMockBuilder('Magento\Framework\Event')
- ->disableOriginalConstructor()
- ->setMethods(['getObject'])
- ->getMock();
-
- /** @var \Magento\User\Model\User|\PHPUnit_Framework_MockObject_MockObject $userMock */
- $userMock = $this->getMockBuilder('Magento\User\Model\User')
- ->disableOriginalConstructor()
- ->setMethods(['getId', 'getNewPassword', 'getForceNewPassword'])
- ->getMock();
-
- $eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock);
- $eventMock->expects($this->once())->method('getObject')->willReturn($userMock);
- $userMock->expects($this->atLeastOnce())->method('getNewPassword')->willReturn($newPW);
- $userMock->expects($this->once())->method('getForceNewPassword')->willReturn(false);
- $userMock->expects($this->once())->method('getId')->willReturn($uid);
- $this->encryptorMock->expects($this->once())->method('isValidHash')->willReturn(true);
- $this->userMock->method('getOldPasswords')->willReturn([md5('pw1'), md5('pw2')]);
-
- try {
- $this->model->execute($eventObserverMock);
- } catch (\Magento\Framework\Exception\LocalizedException $expected) {
- return;
- }
- $this->fail('An expected exception has not been raised.');
- }
-}
diff --git a/app/code/Magento/User/Test/Unit/Observer/Backend/TrackAdminNewPasswordObserverTest.php b/app/code/Magento/User/Test/Unit/Observer/Backend/TrackAdminNewPasswordObserverTest.php
index eb1b930771dd3..d6dc5ddde8dc6 100644
--- a/app/code/Magento/User/Test/Unit/Observer/Backend/TrackAdminNewPasswordObserverTest.php
+++ b/app/code/Magento/User/Test/Unit/Observer/Backend/TrackAdminNewPasswordObserverTest.php
@@ -108,13 +108,13 @@ public function testTrackAdminPassword()
/** @var \Magento\User\Model\User|\PHPUnit_Framework_MockObject_MockObject $userMock */
$userMock = $this->getMockBuilder('Magento\User\Model\User')
->disableOriginalConstructor()
- ->setMethods(['getId', 'getNewPassword', 'getForceNewPassword'])
+ ->setMethods(['getId', 'getCurrentPassword', 'getForceNewPassword'])
->getMock();
$eventObserverMock->expects($this->once())->method('getEvent')->willReturn($eventMock);
$eventMock->expects($this->once())->method('getObject')->willReturn($userMock);
$userMock->expects($this->once())->method('getId')->willReturn($uid);
- $userMock->expects($this->once())->method('getNewPassword')->willReturn($newPW);
+ $userMock->expects($this->once())->method('getCurrentPassword')->willReturn($newPW);
$this->configInterfaceMock
->expects($this->atLeastOnce())
->method('getValue')
diff --git a/app/code/Magento/User/etc/adminhtml/events.xml b/app/code/Magento/User/etc/adminhtml/events.xml
index 1bcdab99c7667..469c19b9c1b25 100755
--- a/app/code/Magento/User/etc/adminhtml/events.xml
+++ b/app/code/Magento/User/etc/adminhtml/events.xml
@@ -12,9 +12,6 @@
-
-
-
diff --git a/app/code/Magento/Webapi/Model/Config/ClassReflector.php b/app/code/Magento/Webapi/Model/Config/ClassReflector.php
index 2bd5ac75d0fc7..7aa85ed2732c9 100644
--- a/app/code/Magento/Webapi/Model/Config/ClassReflector.php
+++ b/app/code/Magento/Webapi/Model/Config/ClassReflector.php
@@ -98,7 +98,7 @@ public function extractMethodData(\Zend\Code\Reflection\MethodReflection $method
$methodData['interface']['in']['parameters'][$parameter->getName()] = $parameterData;
}
$returnType = $this->_typeProcessor->getGetterReturnType($method);
- if ($returnType != 'void' && $returnType != 'null') {
+ if ($returnType['type'] != 'void' && $returnType['type'] != 'null') {
$methodData['interface']['out']['parameters']['result'] = [
'type' => $this->_typeProcessor->register($returnType['type']),
'documentation' => $returnType['description'],
diff --git a/app/etc/di.xml b/app/etc/di.xml
index 256a424f14f93..bb0f0981894fd 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -128,7 +128,6 @@
-
@@ -155,6 +154,20 @@
Magento\Framework\Filesystem\Driver\File
+
+
+
+ -
+
- Magento\Framework\Communication\Config\Reader\XmlReader
+ - 10
+
+ -
+
- Magento\Framework\Communication\Config\Reader\EnvReader
+ - 20
+
+
+
+
main
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Application.php b/dev/tests/integration/framework/Magento/TestFramework/Application.php
index 067a539e0ac12..b87cea882de18 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Application.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Application.php
@@ -492,7 +492,7 @@ public function install()
private function copyAppConfigFiles()
{
$globalConfigFiles = glob(
- $this->_globalConfigDir . '/{di.xml,vendor_path.php}',
+ $this->_globalConfigDir . '/{di.xml,*/di.xml,vendor_path.php}',
GLOB_BRACE
);
foreach ($globalConfigFiles as $file) {
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/ConfigTest.php
index 8900e66587a5d..064884a54f9a1 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Communication/ConfigTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/ConfigTest.php
@@ -52,15 +52,6 @@ public function testGetTopicsExceptionMissingRequest()
$this->getConfigInstance(__DIR__ . '/_files/communication_missing_request.xml')->getTopics();
}
- /**
- * @expectedException \LogicException
- * @expectedExceptionMessage "handler" element must be declared for topic "customerUpdated", because it has
- */
- public function testGetTopicsExceptionMissingHandler()
- {
- $this->getConfigInstance(__DIR__ . '/_files/communication_missing_handler.xml')->getTopics();
- }
-
/**
* @expectedException \LogicException
* @expectedExceptionMessage Service method specified in the definition of topic "customerRetrieved" is not
@@ -304,12 +295,20 @@ protected function getConfigInstance($configFilePath, $envConfigFilePath = null)
'methodsMap' => $methodsMap
]
);
+ $readersConfig = [
+ 'xmlReader' => ['reader' => $xmlReader, 'sortOrder' => 10],
+ 'envReader' => ['reader' => $envReader, 'sortOrder' => 20]
+ ];
+ /** @var \Magento\Framework\Communication\Config\CompositeReader $reader */
+ $reader = $objectManager->create(
+ 'Magento\Framework\Communication\Config\CompositeReader',
+ ['readers' => $readersConfig]
+ );
/** @var \Magento\Framework\Communication\Config $config */
$configData = $objectManager->create(
'Magento\Framework\Communication\Config\Data',
[
- 'reader' => $xmlReader,
- 'envReader' => $envReader
+ 'reader' => $reader
]
);
return $objectManager->create(
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
index 6b8d0f843ebf4..04984323d7754 100755
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
@@ -3879,6 +3879,7 @@
'Magento\Framework\Component\ComponentRegistrar'
],
['Magento\Framework\App\Router\ActionList\Reader'],
+ ['Magento\User\Observer\Backend\CheckAdminPasswordChangeObserver'],
['Magento\Framework\View\File\AbstractCollector'],
['Magento\Tools\Migration\Acl\FileManager'],
['Magento\Tools\Migration\Acl\Formatter'],
diff --git a/lib/internal/Magento/Framework/App/ObjectManager/Environment/Compiled.php b/lib/internal/Magento/Framework/App/ObjectManager/Environment/Compiled.php
index 6718dc4d11830..ee02fd5afcc94 100644
--- a/lib/internal/Magento/Framework/App/ObjectManager/Environment/Compiled.php
+++ b/lib/internal/Magento/Framework/App/ObjectManager/Environment/Compiled.php
@@ -73,7 +73,7 @@ public function getDiConfig()
*/
protected function getConfigData()
{
- $this->getObjectManagerConfigLoader()->load(Area::AREA_GLOBAL);
+ return $this->getObjectManagerConfigLoader()->load(Area::AREA_GLOBAL);
}
/**
diff --git a/lib/internal/Magento/Framework/App/ObjectManagerFactory.php b/lib/internal/Magento/Framework/App/ObjectManagerFactory.php
index 0d482bf1599dd..a9f0b69e2f078 100644
--- a/lib/internal/Magento/Framework/App/ObjectManagerFactory.php
+++ b/lib/internal/Magento/Framework/App/ObjectManagerFactory.php
@@ -120,10 +120,10 @@ public function create(array $arguments)
$definitions = $definitionFactory->createClassDefinition($deploymentConfig->get('definitions'));
$relations = $definitionFactory->createRelations();
- /** @var EnvironmentFactory $enFactory */
- $enFactory = new $this->envFactoryClassName($relations, $definitions);
+ /** @var EnvironmentFactory $envFactory */
+ $envFactory = new $this->envFactoryClassName($relations, $definitions);
/** @var EnvironmentInterface $env */
- $env = $enFactory->createEnvironment();
+ $env = $envFactory->createEnvironment();
/** @var ConfigInterface $diConfig */
$diConfig = $env->getDiConfig();
@@ -176,7 +176,15 @@ public function create(array $arguments)
$this->factory->setObjectManager($objectManager);
ObjectManager::setInstance($objectManager);
- $definitionFactory->getCodeGenerator()->setObjectManager($objectManager);
+
+ $generatorParams = $diConfig->getArguments('Magento\Framework\Code\Generator');
+ /** Arguments are stored in different format when DI config is compiled, thus require custom processing */
+ $generatedEntities = isset($generatorParams['generatedEntities']['_v_'])
+ ? $generatorParams['generatedEntities']['_v_']
+ : (isset($generatorParams['generatedEntities']) ? $generatorParams['generatedEntities'] : []);
+ $definitionFactory->getCodeGenerator()
+ ->setObjectManager($objectManager)
+ ->setGeneratedEntities($generatedEntities);
$env->configureObjectManager($diConfig, $sharedInstances);
diff --git a/lib/internal/Magento/Framework/Code/Generator.php b/lib/internal/Magento/Framework/Code/Generator.php
index 2a572346e6a60..92057208769f7 100644
--- a/lib/internal/Magento/Framework/Code/Generator.php
+++ b/lib/internal/Magento/Framework/Code/Generator.php
@@ -22,7 +22,7 @@ class Generator
protected $_ioObject;
/**
- * @var string[] of EntityAbstract classes
+ * @var array
*/
protected $_generatedEntities;
@@ -57,13 +57,25 @@ public function __construct(
/**
* Get generated entities
*
- * @return string[]
+ * @return array
*/
public function getGeneratedEntities()
{
return $this->_generatedEntities;
}
+ /**
+ * Set entity-to-generator map
+ *
+ * @param array $generatedEntities
+ * @return $this
+ */
+ public function setGeneratedEntities($generatedEntities)
+ {
+ $this->_generatedEntities = $generatedEntities;
+ return $this;
+ }
+
/**
* Generate Class
*
diff --git a/lib/internal/Magento/Framework/Communication/Config/CompositeReader.php b/lib/internal/Magento/Framework/Communication/Config/CompositeReader.php
new file mode 100644
index 0000000000000..5033b7a7cd2cc
--- /dev/null
+++ b/lib/internal/Magento/Framework/Communication/Config/CompositeReader.php
@@ -0,0 +1,61 @@
+readers = [];
+ foreach ($readers as $readerInfo) {
+ if (!isset($readerInfo['reader'])) {
+ continue;
+ }
+ $this->readers[] = $readerInfo['reader'];
+ }
+ }
+
+ /**
+ * Read config.
+ *
+ * @param string|null $scope
+ * @return array
+ */
+ public function read($scope = null)
+ {
+ $result = [];
+ foreach ($this->readers as $reader) {
+ $result = array_replace_recursive($result, $reader->read($scope));
+ }
+ return $result;
+ }
+}
diff --git a/lib/internal/Magento/Framework/Communication/Config/Data.php b/lib/internal/Magento/Framework/Communication/Config/Data.php
index c8d9c560bff22..fda3ee8aadb30 100644
--- a/lib/internal/Magento/Framework/Communication/Config/Data.php
+++ b/lib/internal/Magento/Framework/Communication/Config/Data.php
@@ -13,18 +13,15 @@ class Data extends \Magento\Framework\Config\Data
/**
* Initialize dependencies.
*
- * @param \Magento\Framework\Communication\Config\Reader\XmlReader $reader
+ * @param \Magento\Framework\Communication\Config\CompositeReader $reader
* @param \Magento\Framework\Config\CacheInterface $cache
- * @param \Magento\Framework\Communication\Config\Reader\EnvReader $envReader
* @param string $cacheId
*/
public function __construct(
- \Magento\Framework\Communication\Config\Reader\XmlReader $reader,
+ \Magento\Framework\Communication\Config\CompositeReader $reader,
\Magento\Framework\Config\CacheInterface $cache,
- \Magento\Framework\Communication\Config\Reader\EnvReader $envReader,
$cacheId = 'communication_config_cache'
) {
parent::__construct($reader, $cache, $cacheId);
- $this->merge($envReader->read());
}
}
diff --git a/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Converter.php b/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Converter.php
index 3406614738aad..7633e660276c5 100644
--- a/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Converter.php
+++ b/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Converter.php
@@ -7,7 +7,7 @@
use Magento\Framework\Communication\ConfigInterface as Config;
use Magento\Framework\Phrase;
-use Magento\Framework\Reflection\MethodsMap;
+use Magento\Framework\Communication\Config\ReflectionGenerator;
use Magento\Framework\Stdlib\BooleanUtils;
use Magento\Framework\Communication\Config\Reader\XmlReader\Validator;
@@ -19,9 +19,9 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
const SERVICE_METHOD_NAME_PATTERN = '/^([a-zA-Z\\\\]+)::([a-zA-Z]+)$/';
/**
- * @var MethodsMap
+ * @var ReflectionGenerator
*/
- private $methodsMap;
+ private $reflectionGenerator;
/**
* @var BooleanUtils
@@ -36,16 +36,16 @@ class Converter implements \Magento\Framework\Config\ConverterInterface
/**
* Initialize dependencies
*
- * @param MethodsMap $methodsMap
+ * @param ReflectionGenerator $reflectionGenerator
* @param BooleanUtils $booleanUtils
* @param Validator $xmlValidator
*/
public function __construct(
- MethodsMap $methodsMap,
+ ReflectionGenerator $reflectionGenerator,
BooleanUtils $booleanUtils,
Validator $xmlValidator
) {
- $this->methodsMap = $methodsMap;
+ $this->reflectionGenerator = $reflectionGenerator;
$this->booleanUtils = $booleanUtils;
$this->xmlValidator = $xmlValidator;
}
@@ -78,7 +78,13 @@ protected function extractTopics($config)
$topicAttributes = $topicNode->attributes;
$topicName = $topicAttributes->getNamedItem('name')->nodeValue;
- $requestResponseSchema = $this->extractSchemaDefinedByServiceMethod($topicNode);
+ $serviceMethod = $this->getServiceMethodBySchema($topicNode);
+ $requestResponseSchema = $serviceMethod
+ ? $this->reflectionGenerator->extractMethodMetadata(
+ $serviceMethod['typeName'],
+ $serviceMethod['methodName']
+ )
+ : null;
$requestSchema = $this->extractTopicRequestSchema($topicNode);
$responseSchema = $this->extractTopicResponseSchema($topicNode);
$handlers = $this->extractTopicResponseHandlers($topicNode);
@@ -95,16 +101,13 @@ protected function extractTopics($config)
$requestSchema,
$responseSchema
);
- if ($requestResponseSchema) {
- $output[$topicName] = [
- Config::TOPIC_NAME => $topicName,
- Config::TOPIC_IS_SYNCHRONOUS => true,
- Config::TOPIC_REQUEST => $requestResponseSchema[Config::SCHEMA_METHOD_PARAMS],
- Config::TOPIC_REQUEST_TYPE => Config::TOPIC_REQUEST_TYPE_METHOD,
- Config::TOPIC_RESPONSE => $requestResponseSchema[Config::SCHEMA_METHOD_RETURN_TYPE],
- Config::TOPIC_HANDLERS => $handlers
- ?: ['defaultHandler' => $requestResponseSchema[Config::SCHEMA_METHOD_HANDLER]]
- ];
+ if ($serviceMethod) {
+ $output[$topicName] = $this->reflectionGenerator->generateTopicConfigForServiceMethod(
+ $topicName,
+ $serviceMethod['typeName'],
+ $serviceMethod['methodName'],
+ $handlers
+ );
} else if ($requestSchema && $responseSchema) {
$output[$topicName] = [
Config::TOPIC_NAME => $topicName,
@@ -149,11 +152,11 @@ protected function extractTopicResponseHandlers($topicNode)
continue;
}
$handlerName = $handlerAttributes->getNamedItem('name')->nodeValue;
- $serviceName = $handlerAttributes->getNamedItem('type')->nodeValue;
+ $serviceType = $handlerAttributes->getNamedItem('type')->nodeValue;
$methodName = $handlerAttributes->getNamedItem('method')->nodeValue;
- $this->xmlValidator->validateResponseHandlersType($serviceName, $methodName, $handlerName, $topicName);
+ $this->xmlValidator->validateResponseHandlersType($serviceType, $methodName, $handlerName, $topicName);
$handlerNodes[$handlerName] = [
- Config::HANDLER_TYPE => $serviceName,
+ Config::HANDLER_TYPE => $serviceType,
Config::HANDLER_METHOD => $methodName
];
}
@@ -198,37 +201,19 @@ protected function extractTopicResponseSchema($topicNode)
}
/**
- * Get message schema defined by service method signature.
+ * Get service class and method specified in schema attribute.
*
* @param \DOMNode $topicNode
- * @return array
+ * @return array|null Contains class name and method name
*/
- protected function extractSchemaDefinedByServiceMethod($topicNode)
+ protected function getServiceMethodBySchema($topicNode)
{
$topicAttributes = $topicNode->attributes;
if (!$topicAttributes->getNamedItem('schema')) {
return null;
}
$topicName = $topicAttributes->getNamedItem('name')->nodeValue;
- list($className, $methodName) = $this->parseServiceMethod(
- $topicAttributes->getNamedItem('schema')->nodeValue,
- $topicName
- );
- $result = [
- Config::SCHEMA_METHOD_PARAMS => [],
- Config::SCHEMA_METHOD_RETURN_TYPE => $this->methodsMap->getMethodReturnType($className, $methodName),
- Config::SCHEMA_METHOD_HANDLER => [Config::HANDLER_TYPE => $className, Config::HANDLER_METHOD => $methodName]
- ];
- $paramsMeta = $this->methodsMap->getMethodParams($className, $methodName);
- foreach ($paramsMeta as $paramPosition => $paramMeta) {
- $result[Config::SCHEMA_METHOD_PARAMS][] = [
- Config::SCHEMA_METHOD_PARAM_NAME => $paramMeta[MethodsMap::METHOD_META_NAME],
- Config::SCHEMA_METHOD_PARAM_POSITION => $paramPosition,
- Config::SCHEMA_METHOD_PARAM_IS_REQUIRED => !$paramMeta[MethodsMap::METHOD_META_HAS_DEFAULT_VALUE],
- Config::SCHEMA_METHOD_PARAM_TYPE => $paramMeta[MethodsMap::METHOD_META_TYPE],
- ];
- }
- return $result;
+ return $this->parseServiceMethod($topicAttributes->getNamedItem('schema')->nodeValue, $topicName);
}
/**
@@ -236,7 +221,7 @@ protected function extractSchemaDefinedByServiceMethod($topicNode)
*
* @param string $serviceMethod
* @param string $topicName
- * @return string[] Contains class name and method name, in a call-back compatible format
+ * @return array Contains class name and method name
*/
protected function parseServiceMethod($serviceMethod, $topicName)
{
@@ -244,6 +229,6 @@ protected function parseServiceMethod($serviceMethod, $topicName)
$className = $matches[1];
$methodName = $matches[2];
$this->xmlValidator->validateServiceMethod($serviceMethod, $topicName, $className, $methodName);
- return [$className, $methodName];
+ return ['typeName' => $className, 'methodName' => $methodName];
}
}
diff --git a/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Validator.php b/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Validator.php
index c3a61bd3f8bc7..086b70c7e5e48 100644
--- a/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Validator.php
+++ b/lib/internal/Magento/Framework/Communication/Config/Reader/XmlReader/Validator.php
@@ -98,14 +98,6 @@ public function validateResponseRequest(
)
);
}
- if ($responseSchema && !$handlers) {
- throw new \LogicException(
- sprintf(
- '"handler" element must be declared for topic "%s", because it has "response" declared',
- $topicName
- )
- );
- }
if (($requestResponseSchema || $responseSchema) && (count($handlers) >= 2)) {
throw new \LogicException(
sprintf(
diff --git a/lib/internal/Magento/Framework/Communication/Config/ReflectionGenerator.php b/lib/internal/Magento/Framework/Communication/Config/ReflectionGenerator.php
new file mode 100644
index 0000000000000..51d99d6a72b69
--- /dev/null
+++ b/lib/internal/Magento/Framework/Communication/Config/ReflectionGenerator.php
@@ -0,0 +1,82 @@
+methodsMap = $methodsMap;
+ }
+
+ /**
+ * Extract service method metadata.
+ *
+ * @param string $className
+ * @param string $methodName
+ * @return array
+ */
+ public function extractMethodMetadata($className, $methodName)
+ {
+ $result = [
+ Config::SCHEMA_METHOD_PARAMS => [],
+ Config::SCHEMA_METHOD_RETURN_TYPE => $this->methodsMap->getMethodReturnType($className, $methodName),
+ Config::SCHEMA_METHOD_HANDLER => [Config::HANDLER_TYPE => $className, Config::HANDLER_METHOD => $methodName]
+ ];
+ $paramsMeta = $this->methodsMap->getMethodParams($className, $methodName);
+ foreach ($paramsMeta as $paramPosition => $paramMeta) {
+ $result[Config::SCHEMA_METHOD_PARAMS][] = [
+ Config::SCHEMA_METHOD_PARAM_NAME => $paramMeta[MethodsMap::METHOD_META_NAME],
+ Config::SCHEMA_METHOD_PARAM_POSITION => $paramPosition,
+ Config::SCHEMA_METHOD_PARAM_IS_REQUIRED => !$paramMeta[MethodsMap::METHOD_META_HAS_DEFAULT_VALUE],
+ Config::SCHEMA_METHOD_PARAM_TYPE => $paramMeta[MethodsMap::METHOD_META_TYPE],
+ ];
+ }
+ return $result;
+ }
+
+ /**
+ * Generate config data based on service method signature.
+ *
+ * @param string $topicName
+ * @param string $serviceType
+ * @param string $serviceMethod
+ * @param array|null $handlers
+ * @return array
+ */
+ public function generateTopicConfigForServiceMethod($topicName, $serviceType, $serviceMethod, $handlers = [])
+ {
+ $methodMetadata = $this->extractMethodMetadata($serviceType, $serviceMethod);
+ $returnType = $methodMetadata[Config::SCHEMA_METHOD_RETURN_TYPE];
+ $returnType = ($returnType != 'void' && $returnType != 'null') ? $returnType : null;
+ return [
+ Config::TOPIC_NAME => $topicName,
+ Config::TOPIC_IS_SYNCHRONOUS => $returnType ? true : false,
+ Config::TOPIC_REQUEST => $methodMetadata[Config::SCHEMA_METHOD_PARAMS],
+ Config::TOPIC_REQUEST_TYPE => Config::TOPIC_REQUEST_TYPE_METHOD,
+ Config::TOPIC_RESPONSE => $returnType,
+ Config::TOPIC_HANDLERS => $handlers
+ ?: [self::DEFAULT_HANDLER => $methodMetadata[Config::SCHEMA_METHOD_HANDLER]]
+ ];
+ }
+}
diff --git a/lib/internal/Magento/Framework/Data/Form/FormKey.php b/lib/internal/Magento/Framework/Data/Form/FormKey.php
index 6a5485d7bb4f2..55d841ff35194 100644
--- a/lib/internal/Magento/Framework/Data/Form/FormKey.php
+++ b/lib/internal/Magento/Framework/Data/Form/FormKey.php
@@ -22,16 +22,24 @@ class FormKey
*/
protected $session;
+ /**
+ * @var \Magento\Framework\Escaper
+ */
+ protected $escaper;
+
/**
* @param \Magento\Framework\Math\Random $mathRandom
* @param \Magento\Framework\Session\SessionManagerInterface $session
+ * @param \Magento\Framework\Escaper $escaper
*/
public function __construct(
\Magento\Framework\Math\Random $mathRandom,
- \Magento\Framework\Session\SessionManagerInterface $session
+ \Magento\Framework\Session\SessionManagerInterface $session,
+ \Magento\Framework\Escaper $escaper
) {
$this->mathRandom = $mathRandom;
$this->session = $session;
+ $this->escaper = $escaper;
}
/**
@@ -44,7 +52,7 @@ public function getFormKey()
if (!$this->isPresent()) {
$this->set($this->mathRandom->getRandomString(16));
}
- return $this->session->getData(self::FORM_KEY);
+ return $this->escaper->escapeHtmlAttr($this->session->getData(self::FORM_KEY));
}
/**
diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Form/FormKeyTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Form/FormKeyTest.php
index 5adb36c4ccef7..de92b3b911c69 100644
--- a/lib/internal/Magento/Framework/Data/Test/Unit/Form/FormKeyTest.php
+++ b/lib/internal/Magento/Framework/Data/Test/Unit/Form/FormKeyTest.php
@@ -22,6 +22,11 @@ class FormKeyTest extends \PHPUnit_Framework_TestCase
*/
protected $sessionMock;
+ /**
+ * @var \Zend\Escaper\Escaper|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $escaperMock;
+
/**
* @var FormKey
*/
@@ -32,9 +37,12 @@ protected function setUp()
$this->mathRandomMock = $this->getMock('Magento\Framework\Math\Random', [], [], '', false);
$methods = ['setData', 'getData'];
$this->sessionMock = $this->getMock('Magento\Framework\Session\SessionManager', $methods, [], '', false);
+ $this->escaperMock = $this->getMock('Magento\Framework\Escaper', [], [], '', false);
+ $this->escaperMock->expects($this->any())->method('escapeHtmlAttr')->willReturnArgument(0);
$this->formKey = new FormKey(
$this->mathRandomMock,
- $this->sessionMock
+ $this->sessionMock,
+ $this->escaperMock
);
}
diff --git a/lib/internal/Magento/Framework/Escaper.php b/lib/internal/Magento/Framework/Escaper.php
index f28374eb0ac61..c6792dc93fa89 100644
--- a/lib/internal/Magento/Framework/Escaper.php
+++ b/lib/internal/Magento/Framework/Escaper.php
@@ -8,7 +8,7 @@
/**
* Magento escape methods
*/
-class Escaper
+class Escaper extends \Zend\Escaper\Escaper
{
/**
* Escape html entities
diff --git a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php
index 72d30d3373709..9de7bfe1ba66f 100644
--- a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php
+++ b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php
@@ -44,7 +44,11 @@ class MaliciousCode implements \Zend_Filter_Interface
*/
public function filter($value)
{
- return preg_replace($this->_expressions, '', $value);
+ $replaced = 0;
+ do {
+ $value = preg_replace($this->_expressions, '', $value, -1, $replaced);
+ } while ($replaced !== 0);
+ return $value;
}
/**
diff --git a/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php b/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php
index dfe0a755397cc..5c6e4be9d8364 100644
--- a/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php
+++ b/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php
@@ -101,6 +101,10 @@ public function filterDataProvider()
'Base64' => [
'',
'',
+ ],
+ 'Nested malicious tags' => [
+ 'pt>alert(1);pt>',
+ 'alert(1);',
]
];
}
diff --git a/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php b/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php
index 6c2f8db4da1e0..37a1896f565c2 100644
--- a/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php
+++ b/lib/internal/Magento/Framework/ObjectManager/DefinitionFactory.php
@@ -177,22 +177,7 @@ public function getCodeGenerator()
$this->_filesystemDriver,
$this->_generationDir
);
- $this->codeGenerator = new \Magento\Framework\Code\Generator(
- $generatorIo,
- [
- Generator\Factory::ENTITY_TYPE => '\Magento\Framework\ObjectManager\Code\Generator\Factory',
- Generator\Proxy::ENTITY_TYPE => '\Magento\Framework\ObjectManager\Code\Generator\Proxy',
- Generator\Repository::ENTITY_TYPE => '\Magento\Framework\ObjectManager\Code\Generator\Repository',
- Generator\Persistor::ENTITY_TYPE => '\Magento\Framework\ObjectManager\Code\Generator\Persistor',
- InterceptionGenerator\Interceptor::ENTITY_TYPE => '\Magento\Framework\Interception\Code\Generator\Interceptor',
- MapperGenerator::ENTITY_TYPE => '\Magento\Framework\Api\Code\Generator\Mapper',
- SearchResults::ENTITY_TYPE => '\Magento\Framework\Api\Code\Generator\SearchResults',
- ConverterGenerator::ENTITY_TYPE => '\Magento\Framework\ObjectManager\Code\Generator\Converter',
- ProfilerGenerator\Logger::ENTITY_TYPE => '\Magento\Framework\ObjectManager\Profiler\Code\Generator\Logger',
- ExtensionAttributesGenerator::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator',
- ExtensionAttributesInterfaceGenerator::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator'
- ]
- );
+ $this->codeGenerator = new \Magento\Framework\Code\Generator($generatorIo);
}
return $this->codeGenerator;
}
diff --git a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php
index 24e3a990a9677..a8ce1d6a565d7 100644
--- a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php
+++ b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php
@@ -678,11 +678,16 @@ protected function classHasMethod(ClassReflection $class, $methodName)
* @param string $serviceName API service name
* @param string $methodName
* @return $this
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function processInterfaceCallInfo($interface, $serviceName, $methodName)
{
foreach ($interface as $direction => $interfaceData) {
$direction = ($direction == 'in') ? 'requiredInput' : 'returned';
+ if ($direction == 'returned' && !isset($interfaceData['parameters'])) {
+ /** No return value means that service method is asynchronous */
+ return $this;
+ }
foreach ($interfaceData['parameters'] as $parameterData) {
if (!$this->isTypeSimple($parameterData['type']) && !$this->isTypeAny($parameterData['type'])) {
$operation = $this->getOperationName($serviceName, $methodName);
diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
index b9dbc3aebbda2..711daf317ced7 100644
--- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
@@ -94,7 +94,7 @@ protected function configure()
{
$this->setName(self::NAME)
->setDescription(
- 'Generates DI configuration and all non-existing interceptors and factories'
+ 'Generates DI configuration and all missing classes that can be auto-generated'
);
parent::configure();
}
diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
index fc5eb973944b5..789166966a4f2 100644
--- a/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
@@ -30,6 +30,7 @@
use Magento\Setup\Module\Di\Definition\Serializer\Igbinary;
use Magento\Setup\Module\Di\Definition\Serializer\Standard;
use \Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Code\Generator as CodeGenerator;
/**
* Command to generate all non-existing proxies and factories, and pre-compile class definitions,
@@ -87,7 +88,7 @@ class DiCompileMultiTenantCommand extends AbstractSetupCommand
/**
*
- * @var \Magento\Framework\Code\Generator
+ * @var CodeGenerator
*/
private $generator;
@@ -274,26 +275,13 @@ public function generateCode($generationDir, $fileExcludePatterns, $input)
$interceptorScanner = new Scanner\XmlInterceptorScanner();
$this->entities['interceptors'] = $interceptorScanner->collectEntities($this->files['di']);
// 1.2 Generation of Factory and Additional Classes
- $generatorIo = new \Magento\Framework\Code\Generator\Io(
- new \Magento\Framework\Filesystem\Driver\File(),
- $generationDir
+ $generatorIo = $this->objectManager->create(
+ 'Magento\Framework\Code\Generator\Io',
+ ['generationDirectory' => $generationDir]
);
- $this->generator = new \Magento\Framework\Code\Generator(
- $generatorIo,
- [
- Interceptor::ENTITY_TYPE => 'Magento\Framework\Interception\Code\Generator\Interceptor',
- Proxy::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Proxy',
- Factory::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Factory',
- Mapper::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\Mapper',
- Persistor::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Persistor',
- Repository::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Repository',
- Converter::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Converter',
- SearchResults::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\SearchResults',
- ExtensionAttributesInterfaceGenerator::ENTITY_TYPE =>
- 'Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator',
- ExtensionAttributesGenerator::ENTITY_TYPE =>
- 'Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator'
- ]
+ $this->generator = $this->objectManager->create(
+ 'Magento\Framework\Code\Generator',
+ ['ioObject' => $generatorIo]
);
/** Initialize object manager for code generation based on configs */
$this->generator->setObjectManager($this->objectManager);
@@ -302,13 +290,13 @@ public function generateCode($generationDir, $fileExcludePatterns, $input)
foreach ($repositories as $entityName) {
switch ($this->generator->generateClass($entityName)) {
- case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
+ case CodeGenerator::GENERATION_SUCCESS:
$this->log->add(Log::GENERATION_SUCCESS, $entityName);
break;
- case \Magento\Framework\Code\Generator::GENERATION_ERROR:
+ case CodeGenerator::GENERATION_ERROR:
$this->log->add(Log::GENERATION_ERROR, $entityName);
break;
- case \Magento\Framework\Code\Generator::GENERATION_SKIP:
+ case CodeGenerator::GENERATION_SKIP:
default:
//no log
break;
@@ -318,13 +306,13 @@ public function generateCode($generationDir, $fileExcludePatterns, $input)
sort($this->entities[$type]);
foreach ($this->entities[$type] as $entityName) {
switch ($this->generator->generateClass($entityName)) {
- case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
+ case CodeGenerator::GENERATION_SUCCESS:
$this->log->add(Log::GENERATION_SUCCESS, $entityName);
break;
- case \Magento\Framework\Code\Generator::GENERATION_ERROR:
+ case CodeGenerator::GENERATION_ERROR:
$this->log->add(Log::GENERATION_ERROR, $entityName);
break;
- case \Magento\Framework\Code\Generator::GENERATION_SKIP:
+ case CodeGenerator::GENERATION_SKIP:
default:
//no log
break;
@@ -388,13 +376,13 @@ private function compileCode($generationDir, $fileExcludePatterns, $input)
foreach (['interceptors', 'di'] as $type) {
foreach ($this->entities[$type] as $entityName) {
switch ($this->generator->generateClass($entityName)) {
- case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
+ case CodeGenerator::GENERATION_SUCCESS:
$this->log->add(Log::GENERATION_SUCCESS, $entityName);
break;
- case \Magento\Framework\Code\Generator::GENERATION_ERROR:
+ case CodeGenerator::GENERATION_ERROR:
$this->log->add(Log::GENERATION_ERROR, $entityName);
break;
- case \Magento\Framework\Code\Generator::GENERATION_SKIP:
+ case CodeGenerator::GENERATION_SKIP:
default:
//no log
break;