diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000000..17aa66c919eb5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,33 @@
+---
+name: Bug report
+about: Technical issue with the Magento 2 core components
+
+---
+
+
+
+### Preconditions
+
+1.
+2.
+
+### Steps to reproduce
+
+1.
+2.
+
+### Expected result
+
+1. [Screenshots, logs or description]
+2.
+
+### Actual result
+
+1. [Screenshots, logs or description]
+2.
diff --git a/.github/ISSUE_TEMPLATE/developer-experience-issue.md b/.github/ISSUE_TEMPLATE/developer-experience-issue.md
new file mode 100644
index 0000000000000..a66b0c62ef8e2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/developer-experience-issue.md
@@ -0,0 +1,18 @@
+---
+name: Developer experience issue
+about: Issues related to customization, extensibility, modularity
+
+---
+
+
+
+### Summary
+
+
+### Examples
+
+
+### Proposed solution
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000000..de85da43b70fa
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,21 @@
+---
+name: Feature request
+about: Please consider reporting directly to https://github.com/magento/community-features
+
+---
+
+
+
+### Description
+
+
+### Expected behavior
+
+
+### Benefits
+
+
+### Additional information
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 078b93bd7199c..cc722b6d61b33 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+2.3.0
+=============
+To get detailed information about changes in Magento 2.3.0, see the [Release Notes](https://devdocs.magento.com/guides/v2.3/release-notes/bk-release-notes.html)
+
2.1.0
=============
To get detailed information about changes in Magento 2.1.0, please visit [Magento Community Edition (CE) Release Notes](http://devdocs.magento.com/guides/v2.1/release-notes/ReleaseNotes2.1.0CE.html "Magento Community Edition (CE) Release Notes")
diff --git a/README.md b/README.md
index 6b2ac458eb403..50a20b55d4eb2 100644
--- a/README.md
+++ b/README.md
@@ -41,20 +41,8 @@ Magento is thankful for any contribution that can improve our code base, documen
Labels applied by the Magento team
-
-| Label | Description |
-| ------------- |-------------|
-| ![DOC](http://devdocs.magento.com/common/images/github_DOC.png) | Affects Documentation domain. |
-| ![PROD](http://devdocs.magento.com/common/images/github_PROD.png) | Affects the Product team (mostly feature requests or business logic change). |
-| ![TECH](http://devdocs.magento.com/common/images/github_TECH.png) | Affects Architect Group (mostly to make decisions around technology changes). |
-| ![accept](http://devdocs.magento.com/common/images/github_accept.png) | The pull request has been accepted and will be merged into mainline code. |
-| ![reject](http://devdocs.magento.com/common/images/github_reject.png) | The pull request has been rejected and will not be merged into mainline code. Possible reasons can include but are not limited to: issue has already been fixed in another code contribution, or there is an issue with the code contribution. |
-| ![bug report](http://devdocs.magento.com/common/images/github_bug.png) | The Magento Team has confirmed that this issue contains the minimum required information to reproduce. |
-| ![acknowledged](http://devdocs.magento.com/common/images/gitHub_acknowledged.png) | The Magento Team has validated the issue and an internal ticket has been created. |
-| ![in progress](http://devdocs.magento.com/common/images/github_inProgress.png) | The internal ticket is currently in progress, fix is scheduled to be delivered. |
-| ![needs update](http://devdocs.magento.com/common/images/github_needsUpdate.png) | The Magento Team needs additional information from the reporter to properly prioritize and process the issue or pull request. |
-
-To learn more about issue gate labels click [here](https://github.com/magento/magento2/wiki/Magento-Issue-Gates)
+We apply labels to public Pull Requests and Issues to help other participants retrieve additional information about current progress, component assignments, Magento release lines, and much more.
+Please review the Code Contributions guide for detailed information on labels used in Magento 2 repositories.
Reporting security issues
diff --git a/app/bootstrap.php b/app/bootstrap.php
index ba62b296bd49c..8e901cac9bfb8 100644
--- a/app/bootstrap.php
+++ b/app/bootstrap.php
@@ -31,8 +31,6 @@
// Sets default autoload mappings, may be overridden in Bootstrap::create
\Magento\Framework\App\Bootstrap::populateAutoloader(BP, []);
-require_once BP . '/app/functions.php';
-
/* Custom umask value may be provided in optional mage_umask file in root */
$umaskFile = BP . '/magento_umask';
$mask = file_exists($umaskFile) ? octdec(file_get_contents($umaskFile)) : 002;
@@ -54,8 +52,16 @@
&& isset($_SERVER['HTTP_ACCEPT'])
&& strpos($_SERVER['HTTP_ACCEPT'], 'text/html') !== false
) {
- \Magento\Framework\Profiler::applyConfig(
- (isset($_SERVER['MAGE_PROFILER']) && strlen($_SERVER['MAGE_PROFILER'])) ? $_SERVER['MAGE_PROFILER'] : trim(file_get_contents(BP . '/var/profiler.flag')),
+ $profilerConfig = isset($_SERVER['MAGE_PROFILER']) && strlen($_SERVER['MAGE_PROFILER'])
+ ? $_SERVER['MAGE_PROFILER']
+ : trim(file_get_contents(BP . '/var/profiler.flag'));
+
+ if ($profilerConfig) {
+ $profilerConfig = json_decode($profilerConfig, true) ?: $profilerConfig;
+ }
+
+ Magento\Framework\Profiler::applyConfig(
+ $profilerConfig,
BP,
!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
);
diff --git a/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/Index.php b/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/Index.php
index 125dba405b108..22eb3b30722f4 100644
--- a/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/Index.php
+++ b/app/code/Magento/AdminNotification/Controller/Adminhtml/Notification/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\AdminNotification\Controller\Adminhtml\Notification;
-class Index extends \Magento\AdminNotification\Controller\Adminhtml\Notification
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\AdminNotification\Controller\Adminhtml\Notification implements HttpGetActionInterface
{
/**
* @return void
diff --git a/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php b/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php
index 3275de2a82fb7..24ef712c0f61f 100644
--- a/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php
+++ b/app/code/Magento/AdminNotification/Observer/PredispatchAdminActionControllerObserver.php
@@ -37,7 +37,7 @@ public function __construct(
}
/**
- * Predispath admin action controller
+ * Predispatch admin action controller
*
* @param \Magento\Framework\Event\Observer $observer
* @return void
diff --git a/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml b/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml
index fbed5c0960b73..04d700b9f90ce 100644
--- a/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml
+++ b/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml
@@ -7,6 +7,6 @@
-->
-
+
diff --git a/app/code/Magento/AdminNotification/etc/db_schema_whitelist.json b/app/code/Magento/AdminNotification/etc/db_schema_whitelist.json
index df5e14e066636..b068ffffe9219 100644
--- a/app/code/Magento/AdminNotification/etc/db_schema_whitelist.json
+++ b/app/code/Magento/AdminNotification/etc/db_schema_whitelist.json
@@ -1,32 +1,32 @@
{
- "adminnotification_inbox": {
- "column": {
- "notification_id": true,
- "severity": true,
- "date_added": true,
- "title": true,
- "description": true,
- "url": true,
- "is_read": true,
- "is_remove": true
+ "adminnotification_inbox": {
+ "column": {
+ "notification_id": true,
+ "severity": true,
+ "date_added": true,
+ "title": true,
+ "description": true,
+ "url": true,
+ "is_read": true,
+ "is_remove": true
+ },
+ "index": {
+ "ADMINNOTIFICATION_INBOX_SEVERITY": true,
+ "ADMINNOTIFICATION_INBOX_IS_READ": true,
+ "ADMINNOTIFICATION_INBOX_IS_REMOVE": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
},
- "index": {
- "ADMINNOTIFICATION_INBOX_SEVERITY": true,
- "ADMINNOTIFICATION_INBOX_IS_READ": true,
- "ADMINNOTIFICATION_INBOX_IS_REMOVE": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "admin_system_messages": {
- "column": {
- "identity": true,
- "severity": true,
- "created_at": true
- },
- "constraint": {
- "PRIMARY": true
+ "admin_system_messages": {
+ "column": {
+ "identity": true,
+ "severity": true,
+ "created_at": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
}
- }
}
\ No newline at end of file
diff --git a/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php b/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php
index 02413a1899cd7..d78266ab75311 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php
@@ -5,12 +5,14 @@
*/
namespace Magento\AdvancedPricingImportExport\Controller\Adminhtml\Export;
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\ImportExport\Controller\Adminhtml\Export as ExportController;
use Magento\Framework\Controller\ResultFactory;
use Magento\AdvancedPricingImportExport\Model\Export\AdvancedPricing as ExportAdvancedPricing;
use Magento\Catalog\Model\Product as CatalogProduct;
-class GetFilter extends ExportController
+class GetFilter extends ExportController implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* Get grid-filter of entity attributes action.
@@ -37,10 +39,10 @@ public function execute()
);
return $resultLayout;
} catch (\Exception $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
}
} else {
- $this->messageManager->addError(__('Please correct the data sent.'));
+ $this->messageManager->addErrorMessage(__('Please correct the data sent.'));
}
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
diff --git a/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php b/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php
index c2379e9dff062..b20872da2f8e7 100644
--- a/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php
+++ b/app/code/Magento/AdvancedSearch/Model/ResourceModel/Index.php
@@ -6,18 +6,23 @@
namespace Magento\AdvancedSearch\Model\ResourceModel;
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
+use Magento\Framework\Search\Request\IndexScopeResolverInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\Model\ResourceModel\Db\Context;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Catalog\Api\Data\CategoryInterface;
use Magento\Framework\App\ObjectManager;
-use Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver as TableResolver;
use Magento\Framework\Search\Request\Dimension;
use Magento\Catalog\Model\Indexer\Category\Product\AbstractAction;
+use Magento\Framework\Search\Request\IndexScopeResolverInterface as TableResolver;
+use Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
/**
* @api
* @since 100.1.0
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Index extends AbstractDb
{
@@ -38,25 +43,39 @@ class Index extends AbstractDb
*/
private $tableResolver;
+ /**
+ * @var DimensionCollectionFactory|null
+ */
+ private $dimensionCollectionFactory;
+
+ /**
+ * @var int|null
+ */
+ private $websiteId;
+
/**
* Index constructor.
* @param Context $context
* @param StoreManagerInterface $storeManager
* @param MetadataPool $metadataPool
- * @param null $connectionName
+ * @param string|null $connectionName
* @param TableResolver|null $tableResolver
+ * @param DimensionCollectionFactory|null $dimensionCollectionFactory
*/
public function __construct(
Context $context,
StoreManagerInterface $storeManager,
MetadataPool $metadataPool,
$connectionName = null,
- TableResolver $tableResolver = null
+ TableResolver $tableResolver = null,
+ DimensionCollectionFactory $dimensionCollectionFactory = null
) {
parent::__construct($context, $connectionName);
$this->storeManager = $storeManager;
$this->metadataPool = $metadataPool;
- $this->tableResolver = $tableResolver ?: ObjectManager::getInstance()->get(TableResolver::class);
+ $this->tableResolver = $tableResolver ?: ObjectManager::getInstance()->get(IndexScopeResolverInterface::class);
+ $this->dimensionCollectionFactory = $dimensionCollectionFactory
+ ?: ObjectManager::getInstance()->get(DimensionCollectionFactory::class);
}
/**
@@ -78,18 +97,27 @@ protected function _construct()
protected function _getCatalogProductPriceData($productIds = null)
{
$connection = $this->getConnection();
-
- $select = $connection->select()->from(
- $this->getTable('catalog_product_index_price'),
- ['entity_id', 'customer_group_id', 'website_id', 'min_price']
- );
-
- if ($productIds) {
- $select->where('entity_id IN (?)', $productIds);
+ $catalogProductIndexPriceSelect = [];
+
+ foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
+ if (!isset($dimensions[WebsiteDimensionProvider::DIMENSION_NAME]) ||
+ $this->websiteId === null ||
+ $dimensions[WebsiteDimensionProvider::DIMENSION_NAME]->getValue() === $this->websiteId) {
+ $select = $connection->select()->from(
+ $this->tableResolver->resolve('catalog_product_index_price', $dimensions),
+ ['entity_id', 'customer_group_id', 'website_id', 'min_price']
+ );
+ if ($productIds) {
+ $select->where('entity_id IN (?)', $productIds);
+ }
+ $catalogProductIndexPriceSelect[] = $select;
+ }
}
+ $catalogProductIndexPriceUnionSelect = $connection->select()->union($catalogProductIndexPriceSelect);
+
$result = [];
- foreach ($connection->fetchAll($select) as $row) {
+ foreach ($connection->fetchAll($catalogProductIndexPriceUnionSelect) as $row) {
$result[$row['website_id']][$row['entity_id']][$row['customer_group_id']] = round($row['min_price'], 2);
}
@@ -106,9 +134,12 @@ protected function _getCatalogProductPriceData($productIds = null)
*/
public function getPriceIndexData($productIds, $storeId)
{
+ $websiteId = $this->storeManager->getStore($storeId)->getWebsiteId();
+
+ $this->websiteId = $websiteId;
$priceProductsIndexData = $this->_getCatalogProductPriceData($productIds);
+ $this->websiteId = null;
- $websiteId = $this->storeManager->getStore($storeId)->getWebsiteId();
if (!isset($priceProductsIndexData[$websiteId])) {
return [];
}
diff --git a/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php b/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php
index 185e932406e5b..1f37e40842f54 100644
--- a/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php
+++ b/app/code/Magento/AdvancedSearch/Test/Unit/Model/ResourceModel/IndexTest.php
@@ -15,6 +15,9 @@
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Select;
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
class IndexTest extends \PHPUnit\Framework\TestCase
{
/**
@@ -59,10 +62,24 @@ protected function setUp()
$this->resourceConnectionMock->expects($this->any())->method('getConnection')->willReturn($this->adapterMock);
$this->metadataPoolMock = $this->createMock(MetadataPool::class);
+ $indexScopeResolverMock = $this->createMock(
+ \Magento\Framework\Indexer\ScopeResolver\IndexScopeResolver::class
+ );
+ $traversableMock = $this->createMock(\Traversable::class);
+ $dimensionsMock = $this->createMock(\Magento\Framework\Indexer\MultiDimensionProvider::class);
+ $dimensionsMock->method('getIterator')->willReturn($traversableMock);
+ $dimensionFactoryMock = $this->createMock(
+ \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class
+ );
+ $dimensionFactoryMock->method('create')->willReturn($dimensionsMock);
+
$this->model = new Index(
$this->resourceContextMock,
$this->storeManagerMock,
- $this->metadataPoolMock
+ $this->metadataPoolMock,
+ 'connectionName',
+ $indexScopeResolverMock,
+ $dimensionFactoryMock
);
}
@@ -71,11 +88,13 @@ public function testGetPriceIndexDataUsesFrontendPriceIndexerTable()
$storeId = 1;
$storeMock = $this->createMock(StoreInterface::class);
$storeMock->expects($this->any())->method('getId')->willReturn($storeId);
+ $storeMock->method('getWebsiteId')->willReturn(1);
$this->storeManagerMock->expects($this->once())->method('getStore')->with($storeId)->willReturn($storeMock);
$selectMock = $this->createMock(Select::class);
$selectMock->expects($this->any())->method('from')->willReturnSelf();
$selectMock->expects($this->any())->method('where')->willReturnSelf();
+ $selectMock->expects($this->any())->method('union')->willReturnSelf();
$this->adapterMock->expects($this->once())->method('select')->willReturn($selectMock);
$this->adapterMock->expects($this->once())->method('fetchAll')->with($selectMock)->willReturn([]);
diff --git a/app/code/Magento/AdvancedSearch/etc/db_schema_whitelist.json b/app/code/Magento/AdvancedSearch/etc/db_schema_whitelist.json
index eaf7f3d616736..8addf187744fd 100644
--- a/app/code/Magento/AdvancedSearch/etc/db_schema_whitelist.json
+++ b/app/code/Magento/AdvancedSearch/etc/db_schema_whitelist.json
@@ -1,14 +1,14 @@
{
- "catalogsearch_recommendations": {
- "column": {
- "id": true,
- "query_id": true,
- "relation_id": true
- },
- "constraint": {
- "PRIMARY": true,
- "CATALOGSEARCH_RECOMMENDATIONS_QUERY_ID_SEARCH_QUERY_QUERY_ID": true,
- "CATALOGSEARCH_RECOMMENDATIONS_RELATION_ID_SEARCH_QUERY_QUERY_ID": true
+ "catalogsearch_recommendations": {
+ "column": {
+ "id": true,
+ "query_id": true,
+ "relation_id": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "CATALOGSEARCH_RECOMMENDATIONS_QUERY_ID_SEARCH_QUERY_QUERY_ID": true,
+ "CATALOGSEARCH_RECOMMENDATIONS_RELATION_ID_SEARCH_QUERY_QUERY_ID": true
+ }
}
- }
}
\ No newline at end of file
diff --git a/app/code/Magento/AdvancedSearch/etc/di.xml b/app/code/Magento/AdvancedSearch/etc/di.xml
index 9ec75f56bbf7b..21e19fd58825b 100644
--- a/app/code/Magento/AdvancedSearch/etc/di.xml
+++ b/app/code/Magento/AdvancedSearch/etc/di.xml
@@ -19,6 +19,12 @@
Did you mean
+
+
+ Magento\CatalogSearch\Model\ResourceModel\EngineInterface::CONFIG_ENGINE_PATH
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+
+
@@ -26,5 +32,12 @@
+
+
+
+ Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver
+
+
+
diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php
index ff9126a83d59f..87666cb880e54 100644
--- a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php
+++ b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Analytics\Controller\Adminhtml\BIEssentials;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Config\ScopeConfigInterface;
@@ -12,7 +13,7 @@
/**
* Provides link to BI Essentials signup
*/
-class SignUp extends Action
+class SignUp extends Action implements HttpGetActionInterface
{
/**
* Path to config value with URL to BI Essentials sign-up page.
diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php
index cec09377770b0..9068654fa944f 100644
--- a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php
+++ b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Analytics\Controller\Adminhtml\Reports;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Analytics\Model\Exception\State\SubscriptionUpdateException;
use Magento\Analytics\Model\ReportUrlProvider;
use Magento\Backend\App\Action;
@@ -16,7 +17,7 @@
/**
* Provide redirect to resource with reports.
*/
-class Show extends Action
+class Show extends Action implements HttpGetActionInterface
{
/**
* @var ReportUrlProvider
diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php
index 474398fd34e26..ddd9fcba21109 100644
--- a/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php
+++ b/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php
@@ -30,4 +30,9 @@ public function toBody(array $data);
* @return string
*/
public function getContentTypeHeader();
+
+ /**
+ * @return string
+ */
+ public function getContentMediaType(): string;
}
diff --git a/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php b/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php
index 44c54f67da759..059dab554bd92 100644
--- a/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php
+++ b/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Analytics\Model\Connector\Http;
use Magento\Framework\Serialize\Serializer\Json;
@@ -14,9 +16,16 @@ class JsonConverter implements ConverterInterface
{
/**
* Content-Type HTTP header for json.
+ * @deprecated
+ * @see CONTENT_MEDIA_TYPE
*/
const CONTENT_TYPE_HEADER = 'Content-Type: application/json';
+ /**
+ * Media-Type corresponding to this converter.
+ */
+ const CONTENT_MEDIA_TYPE = 'application/json';
+
/**
* @var Json
*/
@@ -56,6 +65,14 @@ public function toBody(array $data)
*/
public function getContentTypeHeader()
{
- return self::CONTENT_TYPE_HEADER;
+ return sprintf('Content-Type: %s', self::CONTENT_MEDIA_TYPE);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getContentMediaType(): string
+ {
+ return self::CONTENT_MEDIA_TYPE;
}
}
diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php b/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php
index ec198e4a3c40b..57b61c1b5562a 100644
--- a/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php
+++ b/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php
@@ -38,7 +38,15 @@ public function __construct(ConverterInterface $converter, array $responseHandle
public function getResult(\Zend_Http_Response $response)
{
$result = false;
- $responseBody = $this->converter->fromBody($response->getBody());
+ $converterMediaType = $this->converter->getContentMediaType();
+
+ /** Content-Type header may not only contain media-type declaration */
+ if ($response->getBody() && is_int(strripos($response->getHeader('Content-Type'), $converterMediaType))) {
+ $responseBody = $this->converter->fromBody($response->getBody());
+ } else {
+ $responseBody = [];
+ }
+
if (array_key_exists($response->getStatus(), $this->responseHandlers)) {
$result = $this->responseHandlers[$response->getStatus()]->handleResponse($responseBody);
}
diff --git a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php
index dfa283e10d070..c05357400d075 100644
--- a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php
+++ b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php
@@ -103,8 +103,9 @@ public function call()
if (!$result) {
$this->logger->warning(
sprintf(
- 'Obtaining of an OTP from the MBI service has been failed: %s',
- !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.'
+ 'Obtaining of an OTP from the MBI service has been failed: %s. Content-Type: %s',
+ !empty($response->getBody()) ? $response->getBody() : 'Response body is empty',
+ $response->getHeader('Content-Type')
)
);
}
diff --git a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php
index c1f8152f3134e..e35c9bb42bc43 100644
--- a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php
+++ b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php
@@ -110,8 +110,10 @@ public function execute()
if (!$result) {
$this->logger->warning(
sprintf(
- 'Subscription for MBI service has been failed. An error occurred during token exchange: %s',
- !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.'
+ 'Subscription for MBI service has been failed. An error occurred during token exchange: %s.'
+ . ' Content-Type: %s',
+ !empty($response->getBody()) ? $response->getBody() : 'Response body is empty',
+ $response->getHeader('Content-Type')
)
);
}
diff --git a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php
index 7b4e452a7b451..59878ff9c0814 100644
--- a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php
+++ b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php
@@ -101,8 +101,9 @@ public function execute()
if (!$result) {
$this->logger->warning(
sprintf(
- 'Update of the subscription for MBI service has been failed: %s',
- !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.'
+ 'Update of the subscription for MBI service has been failed: %s. Content-Type: %s',
+ !empty($response->getBody()) ? $response->getBody() : 'Response body is empty',
+ $response->getHeader('Content-Type')
)
);
}
diff --git a/app/code/Magento/Analytics/ReportXml/ReportProvider.php b/app/code/Magento/Analytics/ReportXml/ReportProvider.php
index 60e722930c244..8966d018dc6b9 100644
--- a/app/code/Magento/Analytics/ReportXml/ReportProvider.php
+++ b/app/code/Magento/Analytics/ReportXml/ReportProvider.php
@@ -55,7 +55,7 @@ public function __construct(
private function getIteratorName(Query $query)
{
$config = $query->getConfig();
- return isset($config['iterator']) ? $config['iterator'] : null;
+ return $config['iterator'] ?? null;
}
/**
diff --git a/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml b/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml
index 8324ad5ba995a..f6e5b955816e2 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Data/UserData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
noreport
No
diff --git a/app/code/Magento/Analytics/Test/Mftf/Data/UserRoleData.xml b/app/code/Magento/Analytics/Test/Mftf/Data/UserRoleData.xml
index 71d8bdcd5994b..099cc71321b84 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Data/UserRoleData.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Data/UserRoleData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
noreport
123123q
diff --git a/app/code/Magento/Analytics/Test/Mftf/Metadata/user-meta.xml b/app/code/Magento/Analytics/Test/Mftf/Metadata/user-meta.xml
index 06186d2d10402..2e1e5f6f5a97d 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Metadata/user-meta.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Metadata/user-meta.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
application/x-www-form-urlencoded
diff --git a/app/code/Magento/Analytics/Test/Mftf/Metadata/user_role-meta.xml b/app/code/Magento/Analytics/Test/Mftf/Metadata/user_role-meta.xml
index f52468807928e..9d0132453c798 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Metadata/user_role-meta.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Metadata/user_role-meta.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
application/x-www-form-urlencoded
diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml
index fefb7874ef736..ff89ca9b663ee 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationBlankIndustryTest.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml
index 15c9727cc8c79..d9617209dcdff 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationEnableDisableAnalyticsTest.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml
index d4f30737bae3e..2d5594a43b1a7 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationIndustryTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml
index b3ccd3afd1bf7..d8aed1250d82a 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationPermissionTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml
index fc1ff7d18b51e..3f17df108b50b 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminConfigurationTimeToSendDataTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php
index 5ee59a7913a61..92f79c2bf6dee 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php
@@ -12,6 +12,7 @@
/**
* A unit test for testing of the CURL HTTP client.
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class CurlTest extends \PHPUnit\Framework\TestCase
{
@@ -97,7 +98,6 @@ public function getTestData()
'version' => '1.1',
'body'=> ['name' => 'value'],
'url' => 'http://www.mystore.com',
- 'headers' => [JsonConverter::CONTENT_TYPE_HEADER],
'method' => \Magento\Framework\HTTP\ZendClient::POST,
]
]
@@ -105,7 +105,9 @@ public function getTestData()
}
/**
+ * @param array $data
* @return void
+ * @throws \Zend_Http_Exception
* @dataProvider getTestData
*/
public function testRequestSuccess(array $data)
@@ -118,7 +120,7 @@ public function testRequestSuccess(array $data)
$data['method'],
$data['url'],
$data['version'],
- $data['headers'],
+ [$this->converterMock->getContentTypeHeader()],
json_encode($data['body'])
);
$this->curlAdapterMock->expects($this->once())
@@ -139,14 +141,16 @@ public function testRequestSuccess(array $data)
$data['method'],
$data['url'],
$data['body'],
- $data['headers'],
+ [$this->converterMock->getContentTypeHeader()],
$data['version']
)
);
}
/**
+ * @param array $data
* @return void
+ * @throws \Zend_Http_Exception
* @dataProvider getTestData
*/
public function testRequestError(array $data)
@@ -158,7 +162,7 @@ public function testRequestError(array $data)
$data['method'],
$data['url'],
$data['version'],
- $data['headers'],
+ [$this->converterMock->getContentTypeHeader()],
json_encode($data['body'])
);
$this->curlAdapterMock->expects($this->once())
@@ -184,7 +188,7 @@ public function testRequestError(array $data)
$data['method'],
$data['url'],
$data['body'],
- $data['headers'],
+ [$this->converterMock->getContentTypeHeader()],
$data['version']
)
);
@@ -195,14 +199,13 @@ public function testRequestError(array $data)
*/
private function createJsonConverter()
{
- $converterMock = $this->getMockBuilder(ConverterInterface::class)
- ->getMockForAbstractClass();
+ $converterMock = $this->getMockBuilder(JsonConverter::class)
+ ->setMethodsExcept(['getContentTypeHeader'])
+ ->disableOriginalConstructor()
+ ->getMock();
$converterMock->expects($this->any())->method('toBody')->willReturnCallback(function ($value) {
return json_encode($value);
});
- $converterMock->expects($this->any())
- ->method('getContentTypeHeader')
- ->willReturn(JsonConverter::CONTENT_TYPE_HEADER);
return $converterMock;
}
}
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php
index 251f0d1474083..d3258c8ae9caa 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php
@@ -25,6 +25,9 @@ class JsonConverterTest extends \PHPUnit\Framework\TestCase
*/
private $converter;
+ /**
+ * @return void
+ */
protected function setUp()
{
$this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -37,9 +40,15 @@ protected function setUp()
);
}
+ /**
+ * @return void
+ */
public function testConverterContainsHeader()
{
- $this->assertEquals(JsonConverter::CONTENT_TYPE_HEADER, $this->converter->getContentTypeHeader());
+ $this->assertEquals(
+ 'Content-Type: ' . JsonConverter::CONTENT_MEDIA_TYPE,
+ $this->converter->getContentTypeHeader()
+ );
}
/**
@@ -66,6 +75,9 @@ public function convertBodyDataProvider()
];
}
+ /**
+ * return void
+ */
public function testConvertData()
{
$this->serializerMock->expects($this->once())
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php
index 3d4c90bcd07f7..2564240c4fa11 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php
@@ -3,49 +3,115 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Analytics\Test\Unit\Model\Connector\Http;
-use Magento\Analytics\Model\Connector\Http\JsonConverter;
+use Magento\Analytics\Model\Connector\Http\ConverterInterface;
use Magento\Analytics\Model\Connector\Http\ResponseHandlerInterface;
use Magento\Analytics\Model\Connector\Http\ResponseResolver;
-use Magento\Framework\Serialize\Serializer\Json;
-use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
class ResponseResolverTest extends \PHPUnit\Framework\TestCase
{
- public function testGetResultHandleResponseSuccess()
+ /**
+ * @var ObjectManagerHelper
+ */
+ private $objectManagerHelper;
+
+ /**
+ * @var ConverterInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $converterMock;
+
+ /**
+ * @var ResponseHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $successResponseHandlerMock;
+
+ /**
+ * @var ResponseHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $notFoundResponseHandlerMock;
+
+ /**
+ * @var ResponseResolver
+ */
+ private $responseResolver;
+
+ /**
+ * @return void
+ */
+ protected function setUp()
{
- $expectedBody = ['test' => 'testValue'];
- $response = new \Zend_Http_Response(201, [], json_encode($expectedBody));
- $responseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class)
- ->getMockForAbstractClass();
- $responseHandlerMock->expects($this->once())
- ->method('handleResponse')
- ->with($expectedBody)
- ->willReturn(true);
- $notFoundResponseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class)
- ->getMockForAbstractClass();
- $notFoundResponseHandlerMock->expects($this->never())->method('handleResponse');
- $serializerMock = $this->getMockBuilder(Json::class)
+ $this->objectManagerHelper = new ObjectManagerHelper($this);
+ $this->converterMock = $this->getMockBuilder(ConverterInterface::class)
->disableOriginalConstructor()
->getMock();
- $serializerMock->expects($this->once())
- ->method('unserialize')
- ->willReturn($expectedBody);
- $objectManager = new ObjectManager($this);
- $responseResolver = $objectManager->getObject(
+ $this->successResponseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class)
+ ->getMockForAbstractClass();
+ $this->notFoundResponseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class)
+ ->getMockForAbstractClass();
+ $this->responseResolver = $this->objectManagerHelper->getObject(
ResponseResolver::class,
[
- 'converter' => $objectManager->getObject(
- JsonConverter::class,
- ['serializer' => $serializerMock]
- ),
+ 'converter' => $this->converterMock,
'responseHandlers' => [
- 201 => $responseHandlerMock,
- 404 => $notFoundResponseHandlerMock,
+ 201 => $this->successResponseHandlerMock,
+ 404 => $this->notFoundResponseHandlerMock,
]
]
);
- $this->assertTrue($responseResolver->getResult($response));
+ }
+
+ /**
+ * @return void
+ * @throws \Zend_Http_Exception
+ */
+ public function testGetResultHandleResponseSuccess()
+ {
+ $expectedBody = ['test' => 'testValue'];
+ $response = new \Zend_Http_Response(201, ['Content-Type' => 'application/json'], json_encode($expectedBody));
+ $this->converterMock
+ ->method('getContentMediaType')
+ ->willReturn('application/json');
+
+ $this->successResponseHandlerMock
+ ->expects($this->once())
+ ->method('handleResponse')
+ ->with($expectedBody)
+ ->willReturn(true);
+ $this->notFoundResponseHandlerMock
+ ->expects($this->never())
+ ->method('handleResponse');
+ $this->converterMock
+ ->method('fromBody')
+ ->willReturn($expectedBody);
+ $this->assertTrue($this->responseResolver->getResult($response));
+ }
+
+ /**
+ * @return void
+ * @throws \Zend_Http_Exception
+ */
+ public function testGetResultHandleResponseUnexpectedContentType()
+ {
+ $expectedBody = 'testString';
+ $response = new \Zend_Http_Response(201, ['Content-Type' => 'plain/text'], $expectedBody);
+ $this->converterMock
+ ->method('getContentMediaType')
+ ->willReturn('application/json');
+ $this->converterMock
+ ->expects($this->never())
+ ->method('fromBody');
+ $this->successResponseHandlerMock
+ ->expects($this->once())
+ ->method('handleResponse')
+ ->with([])
+ ->willReturn(false);
+ $this->notFoundResponseHandlerMock
+ ->expects($this->never())
+ ->method('handleResponse');
+ $this->assertFalse($this->responseResolver->getResult($response));
}
}
diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php
index db6cda7153c1a..c113b2dc275dd 100644
--- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php
+++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php
@@ -57,6 +57,9 @@ class SignUpCommandTest extends \PHPUnit\Framework\TestCase
*/
private $responseResolverMock;
+ /**
+ * @return void
+ */
protected function setUp()
{
$this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class)
@@ -91,6 +94,10 @@ protected function setUp()
);
}
+ /**
+ * @throws \Zend_Http_Exception
+ * @return void
+ */
public function testExecuteSuccess()
{
$this->integrationManagerMock->expects($this->once())
@@ -124,6 +131,9 @@ public function testExecuteSuccess()
$this->assertTrue($this->signUpCommand->execute());
}
+ /**
+ * @return void
+ */
public function testExecuteFailureCannotGenerateToken()
{
$this->integrationManagerMock->expects($this->once())
@@ -134,6 +144,10 @@ public function testExecuteFailureCannotGenerateToken()
$this->assertFalse($this->signUpCommand->execute());
}
+ /**
+ * @throws \Zend_Http_Exception
+ * @return void
+ */
public function testExecuteFailureResponseIsEmpty()
{
$this->integrationManagerMock->expects($this->once())
@@ -163,7 +177,6 @@ private function getTestData()
'url' => 'http://www.mystore.com',
'access-token' => 'thisisaccesstoken',
'integration-token' => 'thisisintegrationtoken',
- 'headers' => [JsonConverter::CONTENT_TYPE_HEADER],
'method' => \Magento\Framework\HTTP\ZendClient::POST,
'body'=> ['token' => 'thisisintegrationtoken','url' => 'http://www.mystore.com'],
];
diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json
index 396e443355d8f..d62f16ffca8cd 100644
--- a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json
+++ b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json
@@ -1,47 +1,47 @@
{
- "magento_bulk": {
- "column": {
- "id": true,
- "uuid": true,
- "user_id": true,
- "description": true,
- "operation_count": true,
- "start_time": true
+ "magento_bulk": {
+ "column": {
+ "id": true,
+ "uuid": true,
+ "user_id": true,
+ "description": true,
+ "operation_count": true,
+ "start_time": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "MAGENTO_BULK_USER_ID_ADMIN_USER_USER_ID": true,
+ "MAGENTO_BULK_UUID": true
+ }
},
- "constraint": {
- "PRIMARY": true,
- "MAGENTO_BULK_USER_ID_ADMIN_USER_USER_ID": true,
- "MAGENTO_BULK_UUID": true
- }
- },
- "magento_operation": {
- "column": {
- "id": true,
- "bulk_uuid": true,
- "topic_name": true,
- "serialized_data": true,
- "result_serialized_data": true,
- "status": true,
- "error_code": true,
- "result_message": true
- },
- "index": {
- "MAGENTO_OPERATION_BULK_UUID_ERROR_CODE": true
- },
- "constraint": {
- "PRIMARY": true,
- "MAGENTO_OPERATION_BULK_UUID_MAGENTO_BULK_UUID": true
- }
- },
- "magento_acknowledged_bulk": {
- "column": {
- "id": true,
- "bulk_uuid": true
+ "magento_operation": {
+ "column": {
+ "id": true,
+ "bulk_uuid": true,
+ "topic_name": true,
+ "serialized_data": true,
+ "result_serialized_data": true,
+ "status": true,
+ "error_code": true,
+ "result_message": true
+ },
+ "index": {
+ "MAGENTO_OPERATION_BULK_UUID_ERROR_CODE": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "MAGENTO_OPERATION_BULK_UUID_MAGENTO_BULK_UUID": true
+ }
},
- "constraint": {
- "PRIMARY": true,
- "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID_MAGENTO_BULK_UUID": true,
- "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID": true
+ "magento_acknowledged_bulk": {
+ "column": {
+ "id": true,
+ "bulk_uuid": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID_MAGENTO_BULK_UUID": true,
+ "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID": true
+ }
}
- }
}
\ No newline at end of file
diff --git a/app/code/Magento/Authorization/etc/db_schema_whitelist.json b/app/code/Magento/Authorization/etc/db_schema_whitelist.json
index eb9256e415593..8c416d2a8b42c 100644
--- a/app/code/Magento/Authorization/etc/db_schema_whitelist.json
+++ b/app/code/Magento/Authorization/etc/db_schema_whitelist.json
@@ -1,38 +1,38 @@
{
- "authorization_role": {
- "column": {
- "role_id": true,
- "parent_id": true,
- "tree_level": true,
- "sort_order": true,
- "role_type": true,
- "user_id": true,
- "user_type": true,
- "role_name": true
+ "authorization_role": {
+ "column": {
+ "role_id": true,
+ "parent_id": true,
+ "tree_level": true,
+ "sort_order": true,
+ "role_type": true,
+ "user_id": true,
+ "user_type": true,
+ "role_name": true
+ },
+ "index": {
+ "AUTHORIZATION_ROLE_PARENT_ID_SORT_ORDER": true,
+ "AUTHORIZATION_ROLE_TREE_LEVEL": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
},
- "index": {
- "AUTHORIZATION_ROLE_PARENT_ID_SORT_ORDER": true,
- "AUTHORIZATION_ROLE_TREE_LEVEL": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "authorization_rule": {
- "column": {
- "rule_id": true,
- "role_id": true,
- "resource_id": true,
- "privileges": true,
- "permission": true
- },
- "index": {
- "AUTHORIZATION_RULE_RESOURCE_ID_ROLE_ID": true,
- "AUTHORIZATION_RULE_ROLE_ID_RESOURCE_ID": true
- },
- "constraint": {
- "PRIMARY": true,
- "AUTHORIZATION_RULE_ROLE_ID_AUTHORIZATION_ROLE_ROLE_ID": true
+ "authorization_rule": {
+ "column": {
+ "rule_id": true,
+ "role_id": true,
+ "resource_id": true,
+ "privileges": true,
+ "permission": true
+ },
+ "index": {
+ "AUTHORIZATION_RULE_RESOURCE_ID_ROLE_ID": true,
+ "AUTHORIZATION_RULE_ROLE_ID_RESOURCE_ID": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "AUTHORIZATION_RULE_ROLE_ID_AUTHORIZATION_ROLE_ROLE_ID": true
+ }
}
- }
}
\ No newline at end of file
diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php
index 3ad9f470909bf..70565ea8ac65f 100644
--- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php
+++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php
@@ -10,12 +10,15 @@
use Magento\Authorizenet\Model\Directpost;
use Magento\Authorizenet\Model\DirectpostFactory;
use Magento\Framework\App\Action\Context;
+use Magento\Framework\App\CsrfAwareActionInterface;
+use Magento\Framework\App\Request\InvalidRequestException;
+use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Registry;
use Psr\Log\LoggerInterface;
-class BackendResponse extends \Magento\Authorizenet\Controller\Directpost\Payment
+class BackendResponse extends \Magento\Authorizenet\Controller\Directpost\Payment implements CsrfAwareActionInterface
{
/**
* @var LoggerInterface
@@ -48,6 +51,23 @@ public function __construct(
$this->logger = $logger ?: $this->_objectManager->get(LoggerInterface::class);
}
+ /**
+ * @inheritDoc
+ */
+ public function createCsrfValidationException(
+ RequestInterface $request
+ ): ?InvalidRequestException {
+ return null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function validateForCsrf(RequestInterface $request): ?bool
+ {
+ return true;
+ }
+
/**
* Response action.
* Action for Authorize.net SIM Relay Request.
diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php
index 92957481b9290..3c1cb90e0c0a5 100644
--- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php
+++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php
@@ -6,6 +6,7 @@
namespace Magento\Authorizenet\Controller\Directpost\Payment;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Authorizenet\Controller\Directpost\Payment;
use Magento\Authorizenet\Helper\DataFactory;
use Magento\Checkout\Model\Type\Onepage;
@@ -25,7 +26,7 @@
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Place extends Payment
+class Place extends Payment implements HttpPostActionInterface
{
/**
* @var \Magento\Quote\Api\CartManagementInterface
diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php
index d88e77d6c4e28..d562df9fb24a9 100644
--- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php
+++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Response.php
@@ -6,8 +6,29 @@
*/
namespace Magento\Authorizenet\Controller\Directpost\Payment;
-class Response extends \Magento\Authorizenet\Controller\Directpost\Payment
+use Magento\Framework\App\CsrfAwareActionInterface;
+use Magento\Framework\App\Request\InvalidRequestException;
+use Magento\Framework\App\RequestInterface;
+
+class Response extends \Magento\Authorizenet\Controller\Directpost\Payment implements CsrfAwareActionInterface
{
+ /**
+ * @inheritDoc
+ */
+ public function createCsrfValidationException(
+ RequestInterface $request
+ ): ?InvalidRequestException {
+ return null;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function validateForCsrf(RequestInterface $request): ?bool
+ {
+ return true;
+ }
+
/**
* Response action.
* Action for Authorize.net SIM Relay Request.
diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Request.php b/app/code/Magento/Authorizenet/Model/Directpost/Request.php
index d9a403e5c991e..fc78d836b6080 100644
--- a/app/code/Magento/Authorizenet/Model/Directpost/Request.php
+++ b/app/code/Magento/Authorizenet/Model/Directpost/Request.php
@@ -112,50 +112,50 @@ public function setDataFromOrder(
sprintf('%.2F', $order->getBaseShippingAmount())
);
- //need to use strval() because NULL values IE6-8 decodes as "null" in JSON in JavaScript,
+ //need to use (string) because NULL values IE6-8 decodes as "null" in JSON in JavaScript,
//but we need "" for null values.
$billing = $order->getBillingAddress();
if (!empty($billing)) {
- $this->setXFirstName(strval($billing->getFirstname()))
- ->setXLastName(strval($billing->getLastname()))
- ->setXCompany(strval($billing->getCompany()))
- ->setXAddress(strval($billing->getStreetLine(1)))
- ->setXCity(strval($billing->getCity()))
- ->setXState(strval($billing->getRegion()))
- ->setXZip(strval($billing->getPostcode()))
- ->setXCountry(strval($billing->getCountryId()))
- ->setXPhone(strval($billing->getTelephone()))
- ->setXFax(strval($billing->getFax()))
- ->setXCustId(strval($billing->getCustomerId()))
- ->setXCustomerIp(strval($order->getRemoteIp()))
- ->setXCustomerTaxId(strval($billing->getTaxId()))
- ->setXEmail(strval($order->getCustomerEmail()))
- ->setXEmailCustomer(strval($paymentMethod->getConfigData('email_customer')))
- ->setXMerchantEmail(strval($paymentMethod->getConfigData('merchant_email')));
+ $this->setXFirstName((string)$billing->getFirstname())
+ ->setXLastName((string)$billing->getLastname())
+ ->setXCompany((string)$billing->getCompany())
+ ->setXAddress((string)$billing->getStreetLine(1))
+ ->setXCity((string)$billing->getCity())
+ ->setXState((string)$billing->getRegion())
+ ->setXZip((string)$billing->getPostcode())
+ ->setXCountry((string)$billing->getCountryId())
+ ->setXPhone((string)$billing->getTelephone())
+ ->setXFax((string)$billing->getFax())
+ ->setXCustId((string)$billing->getCustomerId())
+ ->setXCustomerIp((string)$order->getRemoteIp())
+ ->setXCustomerTaxId((string)$billing->getTaxId())
+ ->setXEmail((string)$order->getCustomerEmail())
+ ->setXEmailCustomer((string)$paymentMethod->getConfigData('email_customer'))
+ ->setXMerchantEmail((string)$paymentMethod->getConfigData('merchant_email'));
}
$shipping = $order->getShippingAddress();
if (!empty($shipping)) {
$this->setXShipToFirstName(
- strval($shipping->getFirstname())
+ (string)$shipping->getFirstname()
)->setXShipToLastName(
- strval($shipping->getLastname())
+ (string)$shipping->getLastname()
)->setXShipToCompany(
- strval($shipping->getCompany())
+ (string)$shipping->getCompany()
)->setXShipToAddress(
- strval($shipping->getStreetLine(1))
+ (string)$shipping->getStreetLine(1)
)->setXShipToCity(
- strval($shipping->getCity())
+ (string)$shipping->getCity()
)->setXShipToState(
- strval($shipping->getRegion())
+ (string)$shipping->getRegion()
)->setXShipToZip(
- strval($shipping->getPostcode())
+ (string)$shipping->getPostcode()
)->setXShipToCountry(
- strval($shipping->getCountryId())
+ (string)$shipping->getCountryId()
);
}
- $this->setXPoNum(strval($payment->getPoNumber()));
+ $this->setXPoNum((string)$payment->getPoNumber());
return $this;
}
diff --git a/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js b/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js
index 8edc38dce6f60..2b57e5cc2fb0d 100644
--- a/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js
+++ b/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js
@@ -6,7 +6,7 @@
var config = {
map: {
'*': {
- transparent: 'Magento_Payment/transparent'
+ transparent: 'Magento_Payment/js/transparent'
}
}
};
diff --git a/app/code/Magento/Backend/App/Action/Plugin/Authentication.php b/app/code/Magento/Backend/App/Action/Plugin/Authentication.php
index 68506a521c1cf..4b25e9921e404 100644
--- a/app/code/Magento/Backend/App/Action/Plugin/Authentication.php
+++ b/app/code/Magento/Backend/App/Action/Plugin/Authentication.php
@@ -160,7 +160,7 @@ protected function _processNotLoggedInUser(\Magento\Framework\App\RequestInterfa
} else {
$this->_actionFlag->set('', \Magento\Framework\App\ActionInterface::FLAG_NO_DISPATCH, true);
$this->_response->setRedirect($this->_url->getCurrentUrl());
- $this->messageManager->addError(__('Invalid Form Key. Please refresh the page.'));
+ $this->messageManager->addErrorMessage(__('Invalid Form Key. Please refresh the page.'));
$isRedirectNeeded = true;
}
}
@@ -205,7 +205,7 @@ protected function _performLogin(\Magento\Framework\App\RequestInterface $reques
$this->_auth->login($username, $password);
} catch (AuthenticationException $e) {
if (!$request->getParam('messageSent')) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
$request->setParam('messageSent', true);
$outputValue = false;
}
diff --git a/app/code/Magento/Backend/App/DefaultPath.php b/app/code/Magento/Backend/App/DefaultPath.php
index df8b718389741..b790a2edc3fab 100644
--- a/app/code/Magento/Backend/App/DefaultPath.php
+++ b/app/code/Magento/Backend/App/DefaultPath.php
@@ -42,6 +42,6 @@ public function __construct(\Magento\Backend\App\ConfigInterface $config)
*/
public function getPart($code)
{
- return isset($this->_parts[$code]) ? $this->_parts[$code] : null;
+ return $this->_parts[$code] ?? null;
}
}
diff --git a/app/code/Magento/Backend/Block/Media/Uploader.php b/app/code/Magento/Backend/Block/Media/Uploader.php
index 5bad74d8a8be5..eb98808dd644b 100644
--- a/app/code/Magento/Backend/Block/Media/Uploader.php
+++ b/app/code/Magento/Backend/Block/Media/Uploader.php
@@ -3,10 +3,13 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Backend\Block\Media;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Framework\Image\Adapter\UploadConfigInterface;
/**
* Adminhtml media library uploader
@@ -35,24 +38,35 @@ class Uploader extends \Magento\Backend\Block\Widget
*/
private $jsonEncoder;
+ /**
+ * @var UploadConfigInterface
+ */
+ private $imageConfig;
+
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\File\Size $fileSize
* @param array $data
* @param Json $jsonEncoder
+ * @param UploadConfigInterface $imageConfig
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\File\Size $fileSize,
array $data = [],
- Json $jsonEncoder = null
+ Json $jsonEncoder = null,
+ UploadConfigInterface $imageConfig = null
) {
$this->_fileSizeService = $fileSize;
$this->jsonEncoder = $jsonEncoder ?: ObjectManager::getInstance()->get(Json::class);
+ $this->imageConfig = $imageConfig ?: ObjectManager::getInstance()->get(UploadConfigInterface::class);
+
parent::__construct($context, $data);
}
/**
+ * Initialize block.
+ *
* @return void
*/
protected function _construct()
@@ -90,6 +104,26 @@ public function getFileSizeService()
return $this->_fileSizeService;
}
+ /**
+ * Get Image Upload Maximum Width Config.
+ *
+ * @return int
+ */
+ public function getImageUploadMaxWidth()
+ {
+ return $this->imageConfig->getMaxWidth();
+ }
+
+ /**
+ * Get Image Upload Maximum Height Config.
+ *
+ * @return int
+ */
+ public function getImageUploadMaxHeight()
+ {
+ return $this->imageConfig->getMaxHeight();
+ }
+
/**
* Prepares layout and set element renderer
*
diff --git a/app/code/Magento/Backend/Block/Menu.php b/app/code/Magento/Backend/Block/Menu.php
index 7d86497288a69..744c4d06a0d17 100644
--- a/app/code/Magento/Backend/Block/Menu.php
+++ b/app/code/Magento/Backend/Block/Menu.php
@@ -74,6 +74,11 @@ class Menu extends \Magento\Backend\Block\Template
*/
private $anchorRenderer;
+ /**
+ * @var ConfigInterface
+ */
+ private $routeConfig;
+
/**
* @param Template\Context $context
* @param \Magento\Backend\Model\UrlInterface $url
@@ -81,9 +86,11 @@ class Menu extends \Magento\Backend\Block\Template
* @param \Magento\Backend\Model\Auth\Session $authSession
* @param \Magento\Backend\Model\Menu\Config $menuConfig
* @param \Magento\Framework\Locale\ResolverInterface $localeResolver
+ * @param \Magento\Framework\App\Route\ConfigInterface $routeConfig
* @param array $data
* @param MenuItemChecker|null $menuItemChecker
* @param AnchorRenderer|null $anchorRenderer
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
@@ -94,7 +101,8 @@ public function __construct(
\Magento\Framework\Locale\ResolverInterface $localeResolver,
array $data = [],
MenuItemChecker $menuItemChecker = null,
- AnchorRenderer $anchorRenderer = null
+ AnchorRenderer $anchorRenderer = null,
+ \Magento\Framework\App\Route\ConfigInterface $routeConfig = null
) {
$this->_url = $url;
$this->_iteratorFactory = $iteratorFactory;
@@ -103,6 +111,9 @@ public function __construct(
$this->_localeResolver = $localeResolver;
$this->menuItemChecker = $menuItemChecker;
$this->anchorRenderer = $anchorRenderer;
+ $this->routeConfig = $routeConfig ?:
+ \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(\Magento\Framework\App\Route\ConfigInterface::class);
parent::__construct($context, $data);
}
@@ -203,8 +214,9 @@ protected function _afterToHtml($html)
*/
protected function _callbackSecretKey($match)
{
+ $routeId = $this->routeConfig->getRouteByFrontName($match[1]);
return \Magento\Backend\Model\UrlInterface::SECRET_KEY_PARAM_NAME . '/' . $this->_url->getSecretKey(
- $match[1],
+ $routeId,
$match[2],
$match[3]
);
diff --git a/app/code/Magento/Backend/Block/System/Store/Delete/Group.php b/app/code/Magento/Backend/Block/System/Store/Delete/Group.php
index ae80b56066a6d..e95f3bbf9f8c1 100644
--- a/app/code/Magento/Backend/Block/System/Store/Delete/Group.php
+++ b/app/code/Magento/Backend/Block/System/Store/Delete/Group.php
@@ -19,7 +19,7 @@ protected function _prepareLayout()
{
$itemId = $this->getRequest()->getParam('group_id');
- $this->setTemplate('system/store/delete_group.phtml');
+ $this->setTemplate('Magento_Backend::system/store/delete_group.phtml');
$this->setAction($this->getUrl('adminhtml/*/deleteGroupPost', ['group_id' => $itemId]));
$this->addChild(
'confirm_deletion_button',
diff --git a/app/code/Magento/Backend/Block/System/Store/Delete/Website.php b/app/code/Magento/Backend/Block/System/Store/Delete/Website.php
index da28a471130cc..82cbb780137b8 100644
--- a/app/code/Magento/Backend/Block/System/Store/Delete/Website.php
+++ b/app/code/Magento/Backend/Block/System/Store/Delete/Website.php
@@ -19,7 +19,7 @@ protected function _prepareLayout()
{
$itemId = $this->getRequest()->getParam('website_id');
- $this->setTemplate('system/store/delete_website.phtml');
+ $this->setTemplate('Magento_Backend::system/store/delete_website.phtml');
$this->setAction($this->getUrl('adminhtml/*/deleteWebsitePost', ['website_id' => $itemId]));
$this->addChild(
'confirm_deletion_button',
diff --git a/app/code/Magento/Backend/Block/Widget/Button/ButtonList.php b/app/code/Magento/Backend/Block/Widget/Button/ButtonList.php
index 94af9a1d7578f..5a792ddb39132 100644
--- a/app/code/Magento/Backend/Block/Widget/Button/ButtonList.php
+++ b/app/code/Magento/Backend/Block/Widget/Button/ButtonList.php
@@ -7,6 +7,8 @@
namespace Magento\Backend\Block\Widget\Button;
/**
+ * Button list widget
+ *
* @api
* @since 100.0.2
*/
@@ -127,12 +129,6 @@ public function getItems()
*/
public function sortButtons(Item $itemA, Item $itemB)
{
- $sortOrderA = intval($itemA->getSortOrder());
- $sortOrderB = intval($itemB->getSortOrder());
-
- if ($sortOrderA == $sortOrderB) {
- return 0;
- }
- return ($sortOrderA < $sortOrderB) ? -1 : 1;
+ return (int)$itemA->getSortOrder() <=> (int)$itemB->getSortOrder();
}
}
diff --git a/app/code/Magento/Backend/Block/Widget/Form/Container.php b/app/code/Magento/Backend/Block/Widget/Form/Container.php
index 8b7babc1bb9b6..97116de6db79b 100644
--- a/app/code/Magento/Backend/Block/Widget/Form/Container.php
+++ b/app/code/Magento/Backend/Block/Widget/Form/Container.php
@@ -93,7 +93,7 @@ protected function _construct()
'class' => 'delete',
'onclick' => 'deleteConfirm(\'' . __(
'Are you sure you want to do this?'
- ) . '\', \'' . $this->getDeleteUrl() . '\')'
+ ) . '\', \'' . $this->getDeleteUrl() . '\', {data: {}})'
]
);
}
diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Currency.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Currency.php
index b3f467ce37c88..03566bce3fc34 100644
--- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Currency.php
+++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Currency.php
@@ -82,7 +82,7 @@ public function render(\Magento\Framework\DataObject $row)
{
if ($data = (string)$this->_getValue($row)) {
$currency_code = $this->_getCurrencyCode($row);
- $data = floatval($data) * $this->_getRate($row);
+ $data = (float)$data * $this->_getRate($row);
$sign = (bool)(int)$this->getColumn()->getShowNumberSign() && $data > 0 ? '+' : '';
$data = sprintf("%f", $data);
$data = $this->_localeCurrency->getCurrency($currency_code)->toCurrency($data);
@@ -118,10 +118,10 @@ protected function _getCurrencyCode($row)
protected function _getRate($row)
{
if ($rate = $this->getColumn()->getRate()) {
- return floatval($rate);
+ return (float)$rate;
}
if ($rate = $row->getData($this->getColumn()->getRateField())) {
- return floatval($rate);
+ return (float)$rate;
}
return $this->_defaultBaseCurrency->getRate($this->_getCurrencyCode($row));
}
diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Price.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Price.php
index e4300c63485f5..9da23af83f036 100644
--- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Price.php
+++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Price.php
@@ -60,7 +60,7 @@ public function render(\Magento\Framework\DataObject $row)
return $data;
}
- $data = floatval($data) * $this->_getRate($row);
+ $data = (float)$data * $this->_getRate($row);
$data = sprintf("%f", $data);
$data = $this->_localeCurrency->getCurrency($currencyCode)->toCurrency($data);
return $data;
@@ -94,10 +94,10 @@ protected function _getCurrencyCode($row)
protected function _getRate($row)
{
if ($rate = $this->getColumn()->getRate()) {
- return floatval($rate);
+ return (float)$rate;
}
if ($rate = $row->getData($this->getColumn()->getRateField())) {
- return floatval($rate);
+ return (float)$rate;
}
return 1;
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Auth/DeniedJson.php b/app/code/Magento/Backend/Controller/Adminhtml/Auth/DeniedJson.php
index ad4546097768a..23731e29f0df4 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Auth/DeniedJson.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Auth/DeniedJson.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Auth;
-class DeniedJson extends \Magento\Backend\Controller\Adminhtml\Auth
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class DeniedJson extends \Magento\Backend\Controller\Adminhtml\Auth implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php b/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php
index e1ea57f63035e..1de77c810f316 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Auth/Login.php
@@ -6,11 +6,14 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Auth;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGet;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPost;
+
/**
* @api
* @since 100.0.2
*/
-class Login extends \Magento\Backend\Controller\Adminhtml\Auth
+class Login extends \Magento\Backend\Controller\Adminhtml\Auth implements HttpGet, HttpPost
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Auth/Logout.php b/app/code/Magento/Backend/Controller/Adminhtml/Auth/Logout.php
index 41e32c929287a..d7ad080395e29 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Auth/Logout.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Auth/Logout.php
@@ -6,7 +6,10 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Auth;
-class Logout extends \Magento\Backend\Controller\Adminhtml\Auth
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGet;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPost;
+
+class Logout extends \Magento\Backend\Controller\Adminhtml\Auth implements HttpGet, HttpPost
{
/**
* Administrator logout action
@@ -16,7 +19,7 @@ class Logout extends \Magento\Backend\Controller\Adminhtml\Auth
public function execute()
{
$this->_auth->logout();
- $this->messageManager->addSuccess(__('You have logged out.'));
+ $this->messageManager->addSuccessMessage(__('You have logged out.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanImages.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanImages.php
index 7a926b1c09c3e..79bc19256d270 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanImages.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanImages.php
@@ -6,10 +6,11 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Cache;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Controller\ResultFactory;
-class CleanImages extends \Magento\Backend\Controller\Adminhtml\Cache
+class CleanImages extends \Magento\Backend\Controller\Adminhtml\Cache implements HttpGetActionInterface
{
/**
* Authorization level of a basic admin session
@@ -28,11 +29,11 @@ public function execute()
try {
$this->_objectManager->create(\Magento\Catalog\Model\Product\Image::class)->clearCache();
$this->_eventManager->dispatch('clean_catalog_images_cache_after');
- $this->messageManager->addSuccess(__('The image cache was cleaned.'));
+ $this->messageManager->addSuccessMessage(__('The image cache was cleaned.'));
} catch (LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('An error occurred while clearing the image cache.'));
+ $this->messageManager->addExceptionMessage($e, __('An error occurred while clearing the image cache.'));
}
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanMedia.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanMedia.php
index 72f23ab65cf8a..36aca1afcc480 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanMedia.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanMedia.php
@@ -6,10 +6,11 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Cache;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Controller\ResultFactory;
-class CleanMedia extends \Magento\Backend\Controller\Adminhtml\Cache
+class CleanMedia extends \Magento\Backend\Controller\Adminhtml\Cache implements HttpGetActionInterface
{
/**
* Authorization level of a basic admin session
@@ -28,11 +29,12 @@ public function execute()
try {
$this->_objectManager->get(\Magento\Framework\View\Asset\MergeService::class)->cleanMergedJsCss();
$this->_eventManager->dispatch('clean_media_cache_after');
- $this->messageManager->addSuccess(__('The JavaScript/CSS cache has been cleaned.'));
+ $this->messageManager->addSuccessMessage(__('The JavaScript/CSS cache has been cleaned.'));
} catch (LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('An error occurred while clearing the JavaScript/CSS cache.'));
+ $this->messageManager
+ ->addExceptionMessage($e, __('An error occurred while clearing the JavaScript/CSS cache.'));
}
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFiles.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFiles.php
index 27ae2fc31e150..a3a26c5cf6242 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFiles.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/CleanStaticFiles.php
@@ -6,9 +6,10 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Cache;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Framework\Controller\ResultFactory;
-class CleanStaticFiles extends \Magento\Backend\Controller\Adminhtml\Cache
+class CleanStaticFiles extends \Magento\Backend\Controller\Adminhtml\Cache implements HttpGetActionInterface
{
/**
* Authorization level of a basic admin session
@@ -26,7 +27,7 @@ public function execute()
{
$this->_objectManager->get(\Magento\Framework\App\State\CleanupFiles::class)->clearMaterializedViewFiles();
$this->_eventManager->dispatch('clean_static_files_cache_after');
- $this->messageManager->addSuccess(__('The static files cache has been cleaned.'));
+ $this->messageManager->addSuccessMessage(__('The static files cache has been cleaned.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushAll.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushAll.php
index ca89ea58fa6f3..daf424d14c55b 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushAll.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushAll.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Cache;
-class FlushAll extends \Magento\Backend\Controller\Adminhtml\Cache
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class FlushAll extends \Magento\Backend\Controller\Adminhtml\Cache implements HttpGetActionInterface
{
/**
* Authorization level of a basic admin session
@@ -27,7 +29,7 @@ public function execute()
foreach ($this->_cacheFrontendPool as $cacheFrontend) {
$cacheFrontend->getBackend()->clean();
}
- $this->messageManager->addSuccess(__("You flushed the cache storage."));
+ $this->messageManager->addSuccessMessage(__("You flushed the cache storage."));
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('adminhtml/*');
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushSystem.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushSystem.php
index f0fed159e0f22..f3474bf43872b 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushSystem.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/FlushSystem.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Cache;
-class FlushSystem extends \Magento\Backend\Controller\Adminhtml\Cache
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class FlushSystem extends \Magento\Backend\Controller\Adminhtml\Cache implements HttpGetActionInterface
{
/**
* Authorization level of a basic admin session
@@ -27,7 +29,7 @@ public function execute()
$cacheFrontend->clean();
}
$this->_eventManager->dispatch('adminhtml_cache_flush_system');
- $this->messageManager->addSuccess(__("The Magento cache storage has been flushed."));
+ $this->messageManager->addSuccessMessage(__("The Magento cache storage has been flushed."));
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('adminhtml/*');
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/Index.php
index 05bd309ca620e..f1e908bb842ee 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Cache;
-class Index extends \Magento\Backend\Controller\Adminhtml\Cache
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Backend\Controller\Adminhtml\Cache implements HttpGetActionInterface
{
/**
* Display cache management grid
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php
index 2bfa937b06b77..03b88ca1d3f47 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassDisable.php
@@ -67,12 +67,12 @@ private function disableCache()
}
if ($updatedTypes > 0) {
$this->_cacheState->persist();
- $this->messageManager->addSuccess(__("%1 cache type(s) disabled.", $updatedTypes));
+ $this->messageManager->addSuccessMessage(__("%1 cache type(s) disabled.", $updatedTypes));
}
} catch (LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('An error occurred while disabling cache.'));
+ $this->messageManager->addExceptionMessage($e, __('An error occurred while disabling cache.'));
}
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php
index 113e0f2d8961b..1b98a00d4bf35 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php
@@ -66,12 +66,12 @@ private function enableCache()
}
if ($updatedTypes > 0) {
$this->_cacheState->persist();
- $this->messageManager->addSuccess(__("%1 cache type(s) enabled.", $updatedTypes));
+ $this->messageManager->addSuccessMessage(__("%1 cache type(s) enabled.", $updatedTypes));
}
} catch (LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('An error occurred while enabling cache.'));
+ $this->messageManager->addExceptionMessage($e, __('An error occurred while enabling cache.'));
}
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php
index 3843b030afb3d..bde211debcf72 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php
@@ -37,12 +37,12 @@ public function execute()
$updatedTypes++;
}
if ($updatedTypes > 0) {
- $this->messageManager->addSuccess(__("%1 cache type(s) refreshed.", $updatedTypes));
+ $this->messageManager->addSuccessMessage(__("%1 cache type(s) refreshed.", $updatedTypes));
}
} catch (LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('An error occurred while refreshing cache.'));
+ $this->messageManager->addExceptionMessage($e, __('An error occurred while refreshing cache.'));
}
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/Index.php
index d8c52f6c50bba..decca6837fa00 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/Index.php
@@ -6,7 +6,11 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Dashboard;
-class Index extends \Magento\Backend\Controller\Adminhtml\Dashboard
+use Magento\Backend\Controller\Adminhtml\Dashboard as DashboardAction;
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface;
+
+class Index extends DashboardAction implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/RefreshStatistics.php b/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/RefreshStatistics.php
index f831fa67f4bb0..c10d1a77997b7 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/RefreshStatistics.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/RefreshStatistics.php
@@ -34,9 +34,9 @@ public function execute()
foreach ($collectionsNames as $collectionName) {
$this->_objectManager->create($collectionName)->aggregate();
}
- $this->messageManager->addSuccess(__('We updated lifetime statistic.'));
+ $this->messageManager->addSuccessMessage(__('We updated lifetime statistic.'));
} catch (\Exception $e) {
- $this->messageManager->addError(__('We can\'t refresh lifetime statistics.'));
+ $this->messageManager->addErrorMessage(__('We can\'t refresh lifetime statistics.'));
$this->logger->critical($e);
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Index/GlobalSearch.php b/app/code/Magento/Backend/Controller/Adminhtml/Index/GlobalSearch.php
index 9ca4021d08356..37f3064aeaa38 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Index/GlobalSearch.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Index/GlobalSearch.php
@@ -6,11 +6,15 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Index;
+use Magento\Backend\Controller\Adminhtml\Index as IndexAction;
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
+
/**
* @api
* @since 100.0.2
*/
-class GlobalSearch extends \Magento\Backend\Controller\Adminhtml\Index
+class GlobalSearch extends IndexAction implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Index/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/Index/Index.php
index a5c71fb2dbc5c..afb1b4573271d 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Index/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Index/Index.php
@@ -6,7 +6,10 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Index;
-class Index extends \Magento\Backend\Controller\Adminhtml\Index
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGet;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPost;
+
+class Index extends \Magento\Backend\Controller\Adminhtml\Index implements HttpGet, HttpPost
{
/**
* Admin area entry point
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php
index ce59d2fd48e5a..e84987d8e1d70 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Noroute/Index.php
@@ -6,6 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Noroute;
+/**
+ * @SuppressWarnings(PHPMD.AllPurposeAction)
+ */
class Index extends \Magento\Backend\App\Action
{
/**
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Index.php
index 54771bfdc1a7d..648f1be86f56c 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Account;
-class Index extends \Magento\Backend\Controller\Adminhtml\System\Account
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Backend\Controller\Adminhtml\System\Account implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php
index 1b10c151a9d21..d95b0541c2c76 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Account/Save.php
@@ -76,12 +76,12 @@ public function execute()
$errors = $user->validate();
if ($errors !== true && !empty($errors)) {
foreach ($errors as $error) {
- $this->messageManager->addError($error);
+ $this->messageManager->addErrorMessage($error);
}
} else {
$user->save();
$user->sendNotificationEmailsIfRequired();
- $this->messageManager->addSuccess(__('You saved the account.'));
+ $this->messageManager->addSuccessMessage(__('You saved the account.'));
}
} catch (UserLockedException $e) {
$this->_auth->logout();
@@ -91,12 +91,12 @@ public function execute()
} catch (ValidatorException $e) {
$this->messageManager->addMessages($e->getMessages());
if ($e->getMessage()) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
}
} catch (LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addError(__('An error occurred while saving account.'));
+ $this->messageManager->addErrorMessage(__('An error occurred while saving account.'));
}
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Delete.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Delete.php
index 76402169f269e..21f28188cf874 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Delete.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Delete.php
@@ -19,11 +19,11 @@ public function execute()
try {
$design->delete();
- $this->messageManager->addSuccess(__('You deleted the design change.'));
+ $this->messageManager->addSuccessMessage(__('You deleted the design change.'));
} catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __("You can't delete the design change."));
+ $this->messageManager->addExceptionMessage($e, __("You can't delete the design change."));
}
}
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Index.php
index 30b26f2294193..c6a05b5a71d0c 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Design;
-class Index extends \Magento\Backend\Controller\Adminhtml\System\Design
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Backend\Controller\Adminhtml\System\Design implements HttpGetActionInterface
{
/**
* @return \Magento\Backend\Model\View\Result\Page
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Save.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Save.php
index 1f478604ced7d..0228b48f7f11e 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Save.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Design/Save.php
@@ -50,9 +50,9 @@ public function execute()
try {
$design->save();
$this->_eventManager->dispatch('theme_save_after');
- $this->messageManager->addSuccess(__('You saved the design change.'));
+ $this->messageManager->addSuccessMessage(__('You saved the design change.'));
} catch (\Exception $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
$this->_objectManager->get(\Magento\Backend\Model\Session::class)->setDesignData($data);
return $resultRedirect->setPath('adminhtml/*/', ['id' => $design->getId()]);
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php
index 4fbae6abb423a..0beeb5168b6d1 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store.php
@@ -103,12 +103,12 @@ protected function _backupDatabase()
->setType('db')
->setPath($filesystem->getDirectoryRead(DirectoryList::VAR_DIR)->getAbsolutePath('backups'));
$backupDb->createBackup($backup);
- $this->messageManager->addSuccess(__('The database was backed up.'));
+ $this->messageManager->addSuccessMessage(__('The database was backed up.'));
} catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
return false;
} catch (\Exception $e) {
- $this->messageManager->addException(
+ $this->messageManager->addExceptionMessage(
$e,
__('We can\'t create a backup right now. Please try again later.')
);
@@ -125,7 +125,7 @@ protected function _backupDatabase()
*/
protected function _addDeletionNotice($typeTitle)
{
- $this->messageManager->addNotice(
+ $this->messageManager->addNoticeMessage(
__(
'Deleting a %1 will not delete the information associated with the %1 (e.g. categories, products, etc.)'
. ', but the %1 will not be able to be restored. It is suggested that you create a database backup '
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroup.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroup.php
index 925ae4c69ee8e..4e323be709ae1 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroup.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroup.php
@@ -15,13 +15,13 @@ public function execute()
{
$itemId = $this->getRequest()->getParam('item_id', null);
if (!($model = $this->_objectManager->create(\Magento\Store\Model\Group::class)->load($itemId))) {
- $this->messageManager->addError(__('Something went wrong. Please try again.'));
+ $this->messageManager->addErrorMessage(__('Something went wrong. Please try again.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */
$redirectResult = $this->resultRedirectFactory->create();
return $redirectResult->setPath('adminhtml/*/');
}
if (!$model->isCanDelete()) {
- $this->messageManager->addError(__('This store cannot be deleted.'));
+ $this->messageManager->addErrorMessage(__('This store cannot be deleted.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */
$redirectResult = $this->resultRedirectFactory->create();
return $redirectResult->setPath('adminhtml/*/editGroup', ['group_id' => $itemId]);
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php
index b6fbd88c7669c..49c327060dae5 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php
@@ -1,16 +1,20 @@
resultFactory->create(ResultFactory::TYPE_REDIRECT);
if (!($model = $this->_objectManager->create(\Magento\Store\Model\Group::class)->load($itemId))) {
- $this->messageManager->addError(__('Something went wrong. Please try again.'));
+ $this->messageManager->addErrorMessage(__('Something went wrong. Please try again.'));
return $redirectResult->setPath('adminhtml/*/');
}
if (!$model->isCanDelete()) {
- $this->messageManager->addError(__('This store cannot be deleted.'));
+ $this->messageManager->addErrorMessage(__('This store cannot be deleted.'));
return $redirectResult->setPath('adminhtml/*/editGroup', ['group_id' => $model->getId()]);
}
@@ -35,12 +39,12 @@ public function execute()
try {
$model->delete();
- $this->messageManager->addSuccess(__('You deleted the store.'));
+ $this->messageManager->addSuccessMessage(__('You deleted the store.'));
return $redirectResult->setPath('adminhtml/*/');
} catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('Unable to delete the store. Please try again later.'));
+ $this->messageManager->addExceptionMessage($e, __('Unable to delete the store. Please try again later.'));
}
return $redirectResult->setPath('adminhtml/*/editGroup', ['group_id' => $itemId]);
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStore.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStore.php
index b31de6cacc5ff..c340b1ec53aa5 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStore.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStore.php
@@ -15,13 +15,13 @@ public function execute()
{
$itemId = $this->getRequest()->getParam('item_id', null);
if (!($model = $this->_objectManager->create(\Magento\Store\Model\Store::class)->load($itemId))) {
- $this->messageManager->addError(__('Something went wrong. Please try again.'));
+ $this->messageManager->addErrorMessage(__('Something went wrong. Please try again.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */
$redirectResult = $this->resultRedirectFactory->create();
return $redirectResult->setPath('adminhtml/*/');
}
if (!$model->isCanDelete()) {
- $this->messageManager->addError(__('This store view cannot be deleted.'));
+ $this->messageManager->addErrorMessage(__('This store view cannot be deleted.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */
$redirectResult = $this->resultRedirectFactory->create();
return $redirectResult->setPath('adminhtml/*/editStore', ['store_id' => $itemId]);
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php
index 13b104c5ec4c0..7999012b43594 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php
@@ -1,14 +1,17 @@
resultFactory->create(ResultFactory::TYPE_REDIRECT);
if (!($model = $this->_objectManager->create(\Magento\Store\Model\Store::class)->load($itemId))) {
- $this->messageManager->addError(__('Something went wrong. Please try again.'));
+ $this->messageManager->addErrorMessage(__('Something went wrong. Please try again.'));
return $redirectResult->setPath('adminhtml/*/');
}
if (!$model->isCanDelete()) {
- $this->messageManager->addError(__('This store view cannot be deleted.'));
+ $this->messageManager->addErrorMessage(__('This store view cannot be deleted.'));
return $redirectResult->setPath('adminhtml/*/editStore', ['store_id' => $model->getId()]);
}
@@ -37,12 +40,13 @@ public function execute()
try {
$model->delete();
- $this->messageManager->addSuccess(__('You deleted the store view.'));
+ $this->messageManager->addSuccessMessage(__('You deleted the store view.'));
return $redirectResult->setPath('adminhtml/*/');
} catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('Unable to delete the store view. Please try again later.'));
+ $this->messageManager
+ ->addExceptionMessage($e, __('Unable to delete the store view. Please try again later.'));
}
return $redirectResult->setPath('adminhtml/*/editStore', ['store_id' => $itemId]);
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsite.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsite.php
index 1f2ec4b2ba4b1..9e8664b8ecd11 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsite.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsite.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Store;
-class DeleteWebsite extends \Magento\Backend\Controller\Adminhtml\System\Store
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class DeleteWebsite extends \Magento\Backend\Controller\Adminhtml\System\Store implements HttpGetActionInterface
{
/**
* @return \Magento\Framework\Controller\ResultInterface
@@ -15,13 +17,13 @@ public function execute()
{
$itemId = $this->getRequest()->getParam('item_id', null);
if (!($model = $this->_objectManager->create(\Magento\Store\Model\Website::class)->load($itemId))) {
- $this->messageManager->addError(__('Something went wrong. Please try again.'));
+ $this->messageManager->addErrorMessage(__('Something went wrong. Please try again.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */
$redirectResult = $this->resultRedirectFactory->create();
return $redirectResult->setPath('adminhtml/*/');
}
if (!$model->isCanDelete()) {
- $this->messageManager->addError(__('This website cannot be deleted.'));
+ $this->messageManager->addErrorMessage(__('This website cannot be deleted.'));
/** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */
$redirectResult = $this->resultRedirectFactory->create();
return $redirectResult->setPath('adminhtml/*/editWebsite', ['website_id' => $itemId]);
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php
index c2d24b8c41a8c..3fee1a25c9fe4 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php
@@ -6,11 +6,16 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Store;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;
-class DeleteWebsitePost extends \Magento\Backend\Controller\Adminhtml\System\Store
+/**
+ * Delete website.
+ */
+class DeleteWebsitePost extends \Magento\Backend\Controller\Adminhtml\System\Store implements HttpPostActionInterface
{
/**
+ * @inheritDoc
* @return \Magento\Backend\Model\View\Result\Redirect
*/
public function execute()
@@ -23,11 +28,11 @@ public function execute()
$redirectResult = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
if (!$model) {
- $this->messageManager->addError(__('Something went wrong. Please try again.'));
+ $this->messageManager->addErrorMessage(__('Something went wrong. Please try again.'));
return $redirectResult->setPath('adminhtml/*/');
}
if (!$model->isCanDelete()) {
- $this->messageManager->addError(__('This website cannot be deleted.'));
+ $this->messageManager->addErrorMessage(__('This website cannot be deleted.'));
return $redirectResult->setPath('adminhtml/*/editWebsite', ['website_id' => $model->getId()]);
}
@@ -37,12 +42,12 @@ public function execute()
try {
$model->delete();
- $this->messageManager->addSuccess(__('You deleted the website.'));
+ $this->messageManager->addSuccessMessage(__('You deleted the website.'));
return $redirectResult->setPath('adminhtml/*/');
} catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
} catch (\Exception $e) {
- $this->messageManager->addException($e, __('Unable to delete the website. Please try again later.'));
+ $this->messageManager->addExceptionMessage($e, __('Unable to delete the website. Please try again later.'));
}
return $redirectResult->setPath('*/*/editWebsite', ['website_id' => $itemId]);
}
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditStore.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditStore.php
index cbc068a480865..e5cd43b521fd1 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditStore.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditStore.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Store;
-class EditStore extends \Magento\Backend\Controller\Adminhtml\System\Store
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class EditStore extends \Magento\Backend\Controller\Adminhtml\System\Store implements HttpGetActionInterface
{
/**
* @return \Magento\Framework\Controller\ResultInterface
@@ -57,7 +59,7 @@ public function execute()
if ($model->getId() || $this->_coreRegistry->registry('store_action') == 'add') {
$this->_coreRegistry->register('store_data', $model);
if ($this->_coreRegistry->registry('store_action') == 'edit' && $codeBase && !$model->isReadOnly()) {
- $this->messageManager->addNotice($codeBase);
+ $this->messageManager->addNoticeMessage($codeBase);
}
$resultPage = $this->createPage();
if ($this->_coreRegistry->registry('store_action') == 'add') {
@@ -71,7 +73,7 @@ public function execute()
));
return $resultPage;
} else {
- $this->messageManager->addError($notExists);
+ $this->messageManager->addErrorMessage($notExists);
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('adminhtml/*/');
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditWebsite.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditWebsite.php
index bfdf7cdbeb8fb..74ed7951e6214 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditWebsite.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/EditWebsite.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Store;
-class EditWebsite extends \Magento\Backend\Controller\Adminhtml\System\Store
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class EditWebsite extends \Magento\Backend\Controller\Adminhtml\System\Store implements HttpGetActionInterface
{
/**
* @return \Magento\Backend\Model\View\Result\Forward
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Index.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Index.php
index b104704f41bdb..54da065c4af91 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Index.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Index.php
@@ -6,12 +6,13 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Store;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Framework\Controller\ResultFactory;
/**
* Class Index returns Stores page
*/
-class Index extends \Magento\Backend\Controller\Adminhtml\System\Store
+class Index extends \Magento\Backend\Controller\Adminhtml\System\Store implements HttpGetActionInterface
{
/**
* Returns Stores page
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Save.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Save.php
index 8ca783f887ec4..b67f1f23f16ba 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Save.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/Save.php
@@ -6,12 +6,14 @@
*/
namespace Magento\Backend\Controller\Adminhtml\System\Store;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
+
/**
* Class Save
*
* Save controller for system entities such as: Store, StoreGroup, Website
*/
-class Save extends \Magento\Backend\Controller\Adminhtml\System\Store
+class Save extends \Magento\Backend\Controller\Adminhtml\System\Store implements HttpPostActionInterface
{
/**
* Process Website model save
@@ -32,7 +34,7 @@ private function processWebsiteSave($postData)
}
$websiteModel->save();
- $this->messageManager->addSuccess(__('You saved the website.'));
+ $this->messageManager->addSuccessMessage(__('You saved the website.'));
return $postData;
}
@@ -68,7 +70,7 @@ private function processStoreSave($postData)
);
}
$storeModel->save();
- $this->messageManager->addSuccess(__('You saved the store view.'));
+ $this->messageManager->addSuccessMessage(__('You saved the store view.'));
return $postData;
}
@@ -98,7 +100,7 @@ private function processGroupSave($postData)
);
}
$groupModel->save();
- $this->messageManager->addSuccess(__('You saved the store.'));
+ $this->messageManager->addSuccessMessage(__('You saved the store.'));
return $postData;
}
@@ -134,10 +136,10 @@ public function execute()
$redirectResult->setPath('adminhtml/*/');
return $redirectResult;
} catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->messageManager->addError($e->getMessage());
+ $this->messageManager->addErrorMessage($e->getMessage());
$this->_getSession()->setPostData($postData);
} catch (\Exception $e) {
- $this->messageManager->addException(
+ $this->messageManager->addExceptionMessage(
$e,
__('Something went wrong while saving. Please review the error log.')
);
diff --git a/app/code/Magento/Backend/Helper/Dashboard/Order.php b/app/code/Magento/Backend/Helper/Dashboard/Order.php
index 9fc2c2cdb4e6f..c19c28b6e33eb 100644
--- a/app/code/Magento/Backend/Helper/Dashboard/Order.php
+++ b/app/code/Magento/Backend/Helper/Dashboard/Order.php
@@ -13,7 +13,7 @@
* @api
* @since 100.0.2
*/
-class Order extends \Magento\Backend\Helper\Dashboard\AbstractDashboard
+class Order extends AbstractDashboard
{
/**
* @var \Magento\Reports\Model\ResourceModel\Order\Collection
@@ -29,32 +29,25 @@ class Order extends \Magento\Backend\Helper\Dashboard\AbstractDashboard
/**
* @param \Magento\Framework\App\Helper\Context $context
* @param \Magento\Reports\Model\ResourceModel\Order\Collection $orderCollection
+ * @param \Magento\Store\Model\StoreManagerInterface $storeManager
*/
public function __construct(
\Magento\Framework\App\Helper\Context $context,
- \Magento\Reports\Model\ResourceModel\Order\Collection $orderCollection
+ \Magento\Reports\Model\ResourceModel\Order\Collection $orderCollection,
+ \Magento\Store\Model\StoreManagerInterface $storeManager = null
) {
$this->_orderCollection = $orderCollection;
- parent::__construct($context);
- }
+ $this->_storeManager = $storeManager ?: ObjectManager::getInstance()
+ ->get(\Magento\Store\Model\StoreManagerInterface::class);
- /**
- * The getter function to get the new StoreManager dependency
- *
- * @return \Magento\Store\Model\StoreManagerInterface
- *
- * @deprecated 100.1.0
- */
- private function getStoreManager()
- {
- if ($this->_storeManager === null) {
- $this->_storeManager = ObjectManager::getInstance()->get(\Magento\Store\Model\StoreManagerInterface::class);
- }
- return $this->_storeManager;
+ parent::__construct($context);
}
/**
* @return void
+ *
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
*/
protected function _initCollection()
{
@@ -65,15 +58,15 @@ protected function _initCollection()
if ($this->getParam('store')) {
$this->_collection->addFieldToFilter('store_id', $this->getParam('store'));
} elseif ($this->getParam('website')) {
- $storeIds = $this->getStoreManager()->getWebsite($this->getParam('website'))->getStoreIds();
+ $storeIds = $this->_storeManager->getWebsite($this->getParam('website'))->getStoreIds();
$this->_collection->addFieldToFilter('store_id', ['in' => implode(',', $storeIds)]);
} elseif ($this->getParam('group')) {
- $storeIds = $this->getStoreManager()->getGroup($this->getParam('group'))->getStoreIds();
+ $storeIds = $this->_storeManager->getGroup($this->getParam('group'))->getStoreIds();
$this->_collection->addFieldToFilter('store_id', ['in' => implode(',', $storeIds)]);
} elseif (!$this->_collection->isLive()) {
$this->_collection->addFieldToFilter(
'store_id',
- ['eq' => $this->getStoreManager()->getStore(\Magento\Store\Model\Store::ADMIN_CODE)->getId()]
+ ['eq' => $this->_storeManager->getStore(\Magento\Store\Model\Store::ADMIN_CODE)->getId()]
);
}
$this->_collection->load();
diff --git a/app/code/Magento/Backend/Model/Menu.php b/app/code/Magento/Backend/Model/Menu.php
index 22110cf52de2b..0246346ec4d97 100644
--- a/app/code/Magento/Backend/Model/Menu.php
+++ b/app/code/Magento/Backend/Model/Menu.php
@@ -83,7 +83,7 @@ public function add(Item $item, $parentId = null, $index = null)
}
$parentItem->getChildren()->add($item, null, $index);
} else {
- $index = intval($index);
+ $index = (int) $index;
if (!isset($this[$index])) {
$this->offsetSet($index, $item);
$this->_logger->info(
diff --git a/app/code/Magento/Backend/Model/Menu/Builder.php b/app/code/Magento/Backend/Model/Menu/Builder.php
index ae572deab53d9..1c6e900bc5cfc 100644
--- a/app/code/Magento/Backend/Model/Menu/Builder.php
+++ b/app/code/Magento/Backend/Model/Menu/Builder.php
@@ -102,6 +102,6 @@ public function getResult(\Magento\Backend\Model\Menu $menu)
*/
protected function _getParam($params, $paramName, $defaultValue = null)
{
- return isset($params[$paramName]) ? $params[$paramName] : $defaultValue;
+ return $params[$paramName] ?? $defaultValue;
}
}
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginActionGroup.xml
index bcff329d79dad..9ba4430bafe35 100644
--- a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginActionGroup.xml
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml
index 8a24ab2a2f185..a7ef237a232b8 100644
--- a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LogoutActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LogoutActionGroup.xml
index cdaf231e9dda0..a4d922086df34 100644
--- a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LogoutActionGroup.xml
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LogoutActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/SecondaryGridActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/SecondaryGridActionGroup.xml
index 9fe5f54f1db3c..6f27b03e4df30 100644
--- a/app/code/Magento/Backend/Test/Mftf/ActionGroup/SecondaryGridActionGroup.xml
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/SecondaryGridActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/SortByIdDescendingActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/SortByIdDescendingActionGroup.xml
index b7b63c5d9a62e..fd353964bae9a 100644
--- a/app/code/Magento/Backend/Test/Mftf/ActionGroup/SortByIdDescendingActionGroup.xml
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/SortByIdDescendingActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Data/BackenedData.xml b/app/code/Magento/Backend/Test/Mftf/Data/BackenedData.xml
index 286685315a7bc..016e936977cd0 100644
--- a/app/code/Magento/Backend/Test/Mftf/Data/BackenedData.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Data/BackenedData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
data
diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml
index a53938d534644..d1bf3c2cb2ed6 100644
--- a/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminConfigurationStoresPage.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminDashboardPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminDashboardPage.xml
new file mode 100644
index 0000000000000..8c258accdf06c
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminDashboardPage.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml
index ca0797f7ded26..b68b9914186f6 100644
--- a/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminLogoutPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminLogoutPage.xml
index 75ef114ec64b6..713199771e824 100644
--- a/app/code/Magento/Backend/Test/Mftf/Page/AdminLogoutPage.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminLogoutPage.xml
@@ -7,6 +7,6 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminConfirmationModalSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminConfirmationModalSection.xml
index dc512e66528ac..2ec25da461908 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminConfirmationModalSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminConfirmationModalSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminGridTableSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminGridTableSection.xml
index 3e8f8a8f2e412..cc92e530cf3d4 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminGridTableSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminGridTableSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml
index 92b06878ab87f..441ce886f117b 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml
index b65a969e334c4..3b10fac7bb9dc 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml
index f8d259cc8e490..cb164d43a49ff 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminMainActionsSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml
new file mode 100644
index 0000000000000..9d3182b6236a4
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminMessagesSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminMessagesSection.xml
index ff5e02397cbff..b1350d5dcc1d7 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminMessagesSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminMessagesSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminSecondaryGridSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminSecondaryGridSection.xml
index ea84ce7ea0c4f..9051eb747a7a6 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminSecondaryGridSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminSecondaryGridSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginTest.xml
index 99d0f6654738a..7f0194b7dc347 100644
--- a/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginTest.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanMediaTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanMediaTest.php
index b1911da024227..ac0f4a2f467c8 100644
--- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanMediaTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanMediaTest.php
@@ -38,7 +38,7 @@ public function testExecute()
$messageManagerParams = $helper->getConstructArguments(\Magento\Framework\Message\Manager::class);
$messageManagerParams['exceptionMessageFactory'] = $exceptionMessageFactory;
$messageManager = $this->getMockBuilder(\Magento\Framework\Message\Manager::class)
- ->setMethods(['addSuccess'])
+ ->setMethods(['addSuccessMessage'])
->setConstructorArgs($messageManagerParams)
->getMock();
@@ -86,7 +86,7 @@ public function testExecute()
$mergeService->expects($this->once())->method('cleanMergedJsCss');
$messageManager->expects($this->once())
- ->method('addSuccess')
+ ->method('addSuccessMessage')
->with('The JavaScript/CSS cache has been cleaned.');
$valueMap = [
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanStaticFilesTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanStaticFilesTest.php
index 40d9ca1aa8996..fc457cd9681e6 100644
--- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanStaticFilesTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/CleanStaticFilesTest.php
@@ -76,7 +76,7 @@ public function testExecute()
->with('clean_static_files_cache_after');
$this->messageManagerMock->expects($this->once())
- ->method('addSuccess')
+ ->method('addSuccessMessage')
->with('The static files cache has been cleaned.');
$resultRedirect = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class)
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php
index 197b46acc61bc..a8b248c611e07 100644
--- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassDisableTest.php
@@ -156,7 +156,7 @@ public function testExecuteInvalidTypeCache()
->willReturn(['someCache']);
$this->messageManagerMock->expects($this->once())
- ->method('addError')
+ ->method('addErrorMessage')
->with('These cache type(s) don\'t exist: someCache')
->willReturnSelf();
@@ -176,7 +176,7 @@ public function testExecuteWithException()
->willThrowException($exception);
$this->messageManagerMock->expects($this->once())
- ->method('addException')
+ ->method('addExceptionMessage')
->with($exception, 'An error occurred while disabling cache.')
->willReturnSelf();
@@ -216,7 +216,7 @@ public function testExecuteSuccess()
->method('persist');
$this->messageManagerMock->expects($this->once())
- ->method('addSuccess')
+ ->method('addSuccessMessage')
->with('1 cache type(s) disabled.')
->willReturnSelf();
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php
index 9b3640193154a..6eac44a564f6d 100644
--- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php
@@ -156,7 +156,7 @@ public function testExecuteInvalidTypeCache()
->willReturn(['someCache']);
$this->messageManagerMock->expects($this->once())
- ->method('addError')
+ ->method('addErrorMessage')
->with('These cache type(s) don\'t exist: someCache')
->willReturnSelf();
@@ -176,7 +176,7 @@ public function testExecuteWithException()
->willThrowException($exception);
$this->messageManagerMock->expects($this->once())
- ->method('addException')
+ ->method('addExceptionMessage')
->with($exception, 'An error occurred while enabling cache.')
->willReturnSelf();
@@ -216,7 +216,7 @@ public function testExecuteSuccess()
->method('persist');
$this->messageManagerMock->expects($this->once())
- ->method('addSuccess')
+ ->method('addSuccessMessage')
->with('1 cache type(s) enabled.')
->willReturnSelf();
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/RefreshStatisticsTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/RefreshStatisticsTest.php
index e8dcc00345fc6..a985681919f0b 100644
--- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/RefreshStatisticsTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/RefreshStatisticsTest.php
@@ -107,7 +107,7 @@ public function testExecute()
$this->resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirect);
$this->messageManager->expects($this->once())
- ->method('addSuccess')
+ ->method('addSuccessMessage')
->with(__('We updated lifetime statistic.'));
$this->objectManager->expects($this->any())
diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php
index 844a821df1c20..a8490d6ba2e58 100644
--- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/System/Account/SaveTest.php
@@ -71,7 +71,7 @@ protected function setUp()
->getMock();
$this->_messagesMock = $this->getMockBuilder(\Magento\Framework\Message\Manager::class)
->disableOriginalConstructor()
- ->setMethods(['addSuccess'])
+ ->setMethods(['addSuccessMessage'])
->getMockForAbstractClass();
$this->_authSessionMock = $this->getMockBuilder(\Magento\Backend\Model\Auth\Session::class)
@@ -221,7 +221,7 @@ public function testSaveAction()
$this->_requestMock->setParams($requestParams);
- $this->_messagesMock->expects($this->once())->method('addSuccess')->with($this->equalTo($testedMessage));
+ $this->_messagesMock->expects($this->once())->method('addSuccessMessage')->with($this->equalTo($testedMessage));
$this->_controller->execute();
}
diff --git a/app/code/Magento/Backend/etc/adminhtml/di.xml b/app/code/Magento/Backend/etc/adminhtml/di.xml
index d8e9674d2b4cb..3384384343fe9 100644
--- a/app/code/Magento/Backend/etc/adminhtml/di.xml
+++ b/app/code/Magento/Backend/etc/adminhtml/di.xml
@@ -14,8 +14,6 @@
-
Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT
@@ -169,4 +167,5 @@
Magento\Backend\Block\Template
+
diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml
index be1b836d64802..e061455acbe6b 100644
--- a/app/code/Magento/Backend/etc/adminhtml/system.xml
+++ b/app/code/Magento/Backend/etc/adminhtml/system.xml
@@ -197,7 +197,7 @@
Image Processing Settings
-
+
Image Adapter
Magento\Config\Model\Config\Source\Image\Adapter
Magento\Config\Model\Config\Backend\Image\Adapter
@@ -234,6 +234,7 @@
Top destinations
Magento\Directory\Model\Config\Source\Country
+ 1
@@ -314,11 +315,11 @@
Disable Email Communications
Magento\Config\Model\Config\Source\Yesno
-
+
Host
For Windows server only.
-
+
Port (25)
For Windows server only.
@@ -335,6 +336,19 @@
+
+ Images Upload Configuration
+
+ Maximum Width
+ validate-greater-than-zero validate-number required-entry
+ Maximum allowed width for uploaded image.
+
+
+ Maximum Height
+ validate-greater-than-zero validate-number required-entry
+ Maximum allowed height for uploaded image.
+
+
Admin
@@ -435,7 +449,7 @@
Warning! When using Store Code in URLs, in some cases system may not work properly if URLs without Store Codes are specified in the third-party services (e.g. PayPal etc.).]]>
-
+
Auto-redirect to Base URL
Magento\Config\Model\Config\Source\Web\Redirect
I.e. redirect from http://example.com/store/ to http://www.example.com/store/
@@ -448,7 +462,7 @@
Magento\Config\Model\Config\Source\Yesno
-
+
Base URLs
Any of the fields allow fully qualified URLs that end with '/' (slash) e.g. http://example.com/magento/
@@ -456,7 +470,7 @@
Magento\Config\Model\Config\Backend\Baseurl
Specify URL or {{base_url}} placeholder.
-
+
Base Link URL
Magento\Config\Model\Config\Backend\Baseurl
May start with {{unsecure_base_url}} placeholder.
@@ -466,13 +480,13 @@
Magento\Config\Model\Config\Backend\Baseurl
May be empty or start with {{unsecure_base_url}} placeholder.
-
+
Base URL for User Media Files
Magento\Config\Model\Config\Backend\Baseurl
May be empty or start with {{unsecure_base_url}} placeholder.
-
+
Base URLs (Secure)
Any of the fields allow fully qualified URLs that end with '/' (slash) e.g. https://example.com/magento/
@@ -480,7 +494,7 @@
Magento\Config\Model\Config\Backend\Baseurl
Specify URL or {{base_url}}, or {{unsecure_base_url}} placeholder.
-
+
Secure Base Link URL
Magento\Config\Model\Config\Backend\Baseurl
May start with {{secure_base_url}} or {{unsecure_base_url}} placeholder.
@@ -490,24 +504,24 @@
Magento\Config\Model\Config\Backend\Baseurl
May be empty or start with {{secure_base_url}}, or {{unsecure_base_url}} placeholder.
-
+
Secure Base URL for User Media Files
Magento\Config\Model\Config\Backend\Baseurl
May be empty or start with {{secure_base_url}}, or {{unsecure_base_url}} placeholder.
-
+
Use Secure URLs on Storefront
Magento\Config\Model\Config\Source\Yesno
Magento\Config\Model\Config\Backend\Secure
Enter https protocol to use Secure URLs on Storefront.
-
+
Use Secure URLs in Admin
Magento\Config\Model\Config\Source\Yesno
Magento\Config\Model\Config\Backend\Secure
Enter https protocol to use Secure URLs in Admin.
-
+
Enable HTTP Strict Transport Security (HSTS)
Magento\Config\Model\Config\Source\Yesno
Magento\Config\Model\Config\Backend\Secure
@@ -517,7 +531,7 @@
1
-
+
Upgrade Insecure Requests
Magento\Config\Model\Config\Source\Yesno
Magento\Config\Model\Config\Backend\Secure
diff --git a/app/code/Magento/Backend/etc/config.xml b/app/code/Magento/Backend/etc/config.xml
index b7aaf8bf20dba..45d283ad3ff22 100644
--- a/app/code/Magento/Backend/etc/config.xml
+++ b/app/code/Magento/Backend/etc/config.xml
@@ -28,6 +28,10 @@
1
+
+ 1920
+ 1200
+
diff --git a/app/code/Magento/Backend/etc/module.xml b/app/code/Magento/Backend/etc/module.xml
index 6d1691a0e5603..3a5cd8226753d 100644
--- a/app/code/Magento/Backend/etc/module.xml
+++ b/app/code/Magento/Backend/etc/module.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml
index 1e14dd837634a..966372773f295 100644
--- a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml
+++ b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml
@@ -13,8 +13,8 @@
data-mage-init='{
"Magento_Backend/js/media-uploader" : {
"maxFileSize": = /* @escapeNotVerified */ $block->getFileSizeService()->getMaxFileSize() ?>,
- "maxWidth":= /* @escapeNotVerified */ \Magento\Framework\File\Uploader::MAX_IMAGE_WIDTH ?> ,
- "maxHeight": = /* @escapeNotVerified */ \Magento\Framework\File\Uploader::MAX_IMAGE_HEIGHT ?>
+ "maxWidth":= /* @escapeNotVerified */ $block->getImageUploadMaxWidth() ?> ,
+ "maxHeight": = /* @escapeNotVerified */ $block->getImageUploadMaxHeight() ?>
}
}'
>
diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml
index c665c1095a549..fad8f5968009f 100644
--- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml
+++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml
@@ -107,7 +107,7 @@ $numColumns = !is_null($block->getColumns()) ? sizeof($block->getColumns()) : 0;
= /* @escapeNotVerified */ __('of %1', '' . $block->getCollection()->getLastPageNumber() . ' ') ?>
-
= /* @escapeNotVerified */ __('Next page') ?>
diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js
index f9f43cebc592b..7e0b6bdfb46dd 100644
--- a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js
+++ b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js
@@ -123,11 +123,10 @@ define([
this.element.find('input[type=file]').fileupload('option', {
process: [{
action: 'load',
- fileTypes: /^image\/(gif|jpeg|png)$/
+ fileTypes: /^image\/(gif|jpeg|png)$/,
+ maxFileSize: this.options.maxFileSize
}, {
- action: 'resize',
- maxWidth: this.options.maxWidth,
- maxHeight: this.options.maxHeight
+ action: 'resize'
}, {
action: 'save'
}]
diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php
index 27770182a6db6..53f45aff50cbc 100644
--- a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php
+++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php
@@ -82,7 +82,7 @@ public function execute()
$backupManager->create();
- $this->messageManager->addSuccess($successMessage);
+ $this->messageManager->addSuccessMessage($successMessage);
$response->setRedirectUrl($this->getUrl('*/*/index'));
} catch (\Magento\Framework\Backup\Exception\NotEnoughFreeSpace $e) {
diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php
index 3bbda65cb4cf6..271e3713034d0 100644
--- a/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php
+++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Backup\Controller\Adminhtml\Index;
-class Index extends \Magento\Backup\Controller\Adminhtml\Index
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Backup\Controller\Adminhtml\Index implements HttpGetActionInterface
{
/**
* Backup list action
diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/MassDelete.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/MassDelete.php
index 04292d2759093..90657fc2490ba 100644
--- a/app/code/Magento/Backup/Controller/Adminhtml/Index/MassDelete.php
+++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/MassDelete.php
@@ -49,13 +49,13 @@ public function execute()
$resultData->setIsSuccess(true);
if ($allBackupsDeleted) {
- $this->messageManager->addSuccess(__('You deleted the selected backup(s).'));
+ $this->messageManager->addSuccessMessage(__('You deleted the selected backup(s).'));
} else {
throw new \Exception($deleteFailMessage);
}
} catch (\Exception $e) {
$resultData->setIsSuccess(false);
- $this->messageManager->addError($deleteFailMessage);
+ $this->messageManager->addErrorMessage($deleteFailMessage);
}
return $this->_redirect('backup/*/index');
diff --git a/app/code/Magento/Backup/Helper/Data.php b/app/code/Magento/Backup/Helper/Data.php
index 3d60bf9d9c9cf..b0bc292ffe926 100644
--- a/app/code/Magento/Backup/Helper/Data.php
+++ b/app/code/Magento/Backup/Helper/Data.php
@@ -110,7 +110,7 @@ public function getBackupsDir()
public function getExtensionByType($type)
{
$extensions = $this->getExtensions();
- return isset($extensions[$type]) ? $extensions[$type] : '';
+ return $extensions[$type] ?? '';
}
/**
diff --git a/app/code/Magento/Backup/Model/BackupFactory.php b/app/code/Magento/Backup/Model/BackupFactory.php
index 28b0a7baf43cb..f88b410a2371b 100644
--- a/app/code/Magento/Backup/Model/BackupFactory.php
+++ b/app/code/Magento/Backup/Model/BackupFactory.php
@@ -39,8 +39,8 @@ public function __construct(\Magento\Framework\ObjectManagerInterface $objectMan
*/
public function create($timestamp, $type)
{
- $fsCollection = $this->_objectManager->get(\Magento\Backup\Model\Fs\Collection::class);
- $backupInstance = $this->_objectManager->get(\Magento\Backup\Model\Backup::class);
+ $fsCollection = $this->_objectManager->create(\Magento\Backup\Model\Fs\Collection::class);
+ $backupInstance = $this->_objectManager->create(\Magento\Backup\Model\Backup::class);
foreach ($fsCollection as $backup) {
if ($backup->getTime() === (int) $timestamp && $backup->getType() === $type) {
diff --git a/app/code/Magento/Backup/Model/Config/Backend/Cron.php b/app/code/Magento/Backup/Model/Config/Backend/Cron.php
index 4855ef1129502..2f0e4069f0499 100644
--- a/app/code/Magento/Backup/Model/Config/Backend/Cron.php
+++ b/app/code/Magento/Backup/Model/Config/Backend/Cron.php
@@ -76,8 +76,8 @@ public function afterSave()
if ($enabled) {
$cronExprArray = [
- intval($time[1]), # Minute
- intval($time[0]), # Hour
+ (int) $time[1], # Minute
+ (int) $time[0], # Hour
$frequency == $frequencyMonthly ? '1' : '*', # Day of the Month
'*', # Month of the Year
$frequency == $frequencyWeekly ? '1' : '*', # Day of the Week
diff --git a/app/code/Magento/Backup/Model/Fs/Collection.php b/app/code/Magento/Backup/Model/Fs/Collection.php
index 2d08ac04528ac..b17c17f7074fb 100644
--- a/app/code/Magento/Backup/Model/Fs/Collection.php
+++ b/app/code/Magento/Backup/Model/Fs/Collection.php
@@ -115,7 +115,8 @@ protected function _generateRow($filename)
if (isset($row['display_name']) && $row['display_name'] == '') {
$row['display_name'] = 'WebSetupWizard';
}
- $row['id'] = $row['time'] . '_' . $row['type'] . (isset($row['display_name']) ? $row['display_name'] : '');
+ $row['id'] = $row['time'] . '_' . $row['type']
+ . (isset($row['display_name']) ? '_' . $row['display_name'] : '');
return $row;
}
}
diff --git a/app/code/Magento/Backup/Test/Mftf/ActionGroup/CreateBackupActionGroup.xml b/app/code/Magento/Backup/Test/Mftf/ActionGroup/CreateBackupActionGroup.xml
new file mode 100644
index 0000000000000..89381112e6c66
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/ActionGroup/CreateBackupActionGroup.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/ActionGroup/DeleteBackupActionGroup.xml b/app/code/Magento/Backup/Test/Mftf/ActionGroup/DeleteBackupActionGroup.xml
new file mode 100644
index 0000000000000..4f34f24c3a806
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/ActionGroup/DeleteBackupActionGroup.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/Data/BackupData.xml b/app/code/Magento/Backup/Test/Mftf/Data/BackupData.xml
new file mode 100644
index 0000000000000..ae97351cafcaf
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/Data/BackupData.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+ systemBackup
+ System
+
+
+ mediaBackup
+ Database and Media
+
+
+ databaseBackup
+ Database
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/Page/BackupIndexPage.xml b/app/code/Magento/Backup/Test/Mftf/Page/BackupIndexPage.xml
new file mode 100644
index 0000000000000..aad29e6e6d566
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/Page/BackupIndexPage.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/Section/AdminCreateBackupFormSection.xml b/app/code/Magento/Backup/Test/Mftf/Section/AdminCreateBackupFormSection.xml
new file mode 100644
index 0000000000000..af88146bcfb4b
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/Section/AdminCreateBackupFormSection.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/Section/AdminGridActionSection.xml b/app/code/Magento/Backup/Test/Mftf/Section/AdminGridActionSection.xml
new file mode 100644
index 0000000000000..cca6b428a2820
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/Section/AdminGridActionSection.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/Section/AdminGridTableSection.xml b/app/code/Magento/Backup/Test/Mftf/Section/AdminGridTableSection.xml
new file mode 100644
index 0000000000000..72fb51684931f
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/Section/AdminGridTableSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/Section/AdminMainActionsSection.xml b/app/code/Magento/Backup/Test/Mftf/Section/AdminMainActionsSection.xml
new file mode 100644
index 0000000000000..11ba79f32b5db
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/Section/AdminMainActionsSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Mftf/Test/AdminCreateAndDeleteBackupsTest.xml b/app/code/Magento/Backup/Test/Mftf/Test/AdminCreateAndDeleteBackupsTest.xml
new file mode 100644
index 0000000000000..496bb79343092
--- /dev/null
+++ b/app/code/Magento/Backup/Test/Mftf/Test/AdminCreateAndDeleteBackupsTest.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php b/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php
index 629028bfd6f15..abf5e63276afa 100644
--- a/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php
+++ b/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php
@@ -56,7 +56,7 @@ protected function setUp()
$this->_objectManager->expects(
$this->at(0)
)->method(
- 'get'
+ 'create'
)->with(
\Magento\Backup\Model\Fs\Collection::class
)->will(
@@ -65,7 +65,7 @@ protected function setUp()
$this->_objectManager->expects(
$this->at(1)
)->method(
- 'get'
+ 'create'
)->with(
\Magento\Backup\Model\Backup::class
)->will(
diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php
index 4c3f1e179d378..6d43929db7675 100644
--- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php
+++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php
@@ -17,8 +17,6 @@ class TransactionRefund extends AbstractTransaction
protected function process(array $data)
{
$storeId = $data['store_id'] ?? null;
- // sending store id and other additional keys are restricted by Braintree API
- unset($data['store_id']);
return $this->adapterFactory->create($storeId)
->refund($data['transaction_id'], $data[PaymentDataBuilder::AMOUNT]);
diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php
index 16ebd7a7a00c5..6760e724fd3a6 100644
--- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php
+++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php
@@ -19,8 +19,6 @@ class TransactionSubmitForSettlement extends AbstractTransaction
protected function process(array $data)
{
$storeId = $data['store_id'] ?? null;
- // sending store id and other additional keys are restricted by Braintree API
- unset($data['store_id']);
return $this->adapterFactory->create($storeId)
->submitForSettlement($data[CaptureDataBuilder::TRANSACTION_ID], $data[PaymentDataBuilder::AMOUNT]);
diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php
index e9a478a8bac23..0a940839fc154 100644
--- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php
+++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php
@@ -15,8 +15,6 @@ class TransactionVoid extends AbstractTransaction
protected function process(array $data)
{
$storeId = $data['store_id'] ?? null;
- // sending store id and other additional keys are restricted by Braintree API
- unset($data['store_id']);
return $this->adapterFactory->create($storeId)->void($data['transaction_id']);
}
diff --git a/app/code/Magento/Braintree/Gateway/Request/MerchantAccountDataBuilder.php b/app/code/Magento/Braintree/Gateway/Request/MerchantAccountDataBuilder.php
new file mode 100644
index 0000000000000..6dc40e76322df
--- /dev/null
+++ b/app/code/Magento/Braintree/Gateway/Request/MerchantAccountDataBuilder.php
@@ -0,0 +1,64 @@
+config = $config;
+ $this->subjectReader = $subjectReader;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function build(array $buildSubject): array
+ {
+ $paymentDO = $this->subjectReader->readPayment($buildSubject);
+ $order = $paymentDO->getOrder();
+
+ $result = [];
+ $merchantAccountId = $this->config->getMerchantAccountId($order->getStoreId());
+ if (!empty($merchantAccountId)) {
+ $result[self::$merchantAccountId] = $merchantAccountId;
+ }
+
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php b/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php
index 85a0c64451398..fe75ce86cca2f 100644
--- a/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php
+++ b/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php
@@ -6,8 +6,8 @@
namespace Magento\Braintree\Gateway\Request;
use Magento\Braintree\Gateway\Config\Config;
-use Magento\Braintree\Observer\DataAssignObserver;
use Magento\Braintree\Gateway\SubjectReader;
+use Magento\Braintree\Observer\DataAssignObserver;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Magento\Payment\Helper\Formatter;
@@ -36,9 +36,8 @@ class PaymentDataBuilder implements BuilderInterface
const PAYMENT_METHOD_NONCE = 'paymentMethodNonce';
/**
- * The merchant account ID used to create a transaction.
- * Currency is also determined by merchant account ID.
- * If no merchant account ID is specified, Braintree will use your default merchant account.
+ * @deprecated
+ * @see \Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
*/
const MERCHANT_ACCOUNT_ID = 'merchantAccountId';
@@ -47,25 +46,18 @@ class PaymentDataBuilder implements BuilderInterface
*/
const ORDER_ID = 'orderId';
- /**
- * @var Config
- */
- private $config;
-
/**
* @var SubjectReader
*/
private $subjectReader;
/**
- * Constructor
- *
* @param Config $config
* @param SubjectReader $subjectReader
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function __construct(Config $config, SubjectReader $subjectReader)
{
- $this->config = $config;
$this->subjectReader = $subjectReader;
}
@@ -87,11 +79,6 @@ public function build(array $buildSubject)
self::ORDER_ID => $order->getOrderIncrementId()
];
- $merchantAccountId = $this->config->getMerchantAccountId($order->getStoreId());
- if (!empty($merchantAccountId)) {
- $result[self::MERCHANT_ACCOUNT_ID] = $merchantAccountId;
- }
-
return $result;
}
}
diff --git a/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php b/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php
index e06b913db8ef4..e6c5ee22c62b4 100644
--- a/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php
+++ b/app/code/Magento/Braintree/Model/Ui/PayPal/ConfigProvider.php
@@ -47,6 +47,8 @@ public function __construct(Config $config, ResolverInterface $resolver)
*/
public function getConfig()
{
+ $requireBillingAddressAll = \Magento\Paypal\Model\Config::REQUIRE_BILLING_ADDRESS_ALL;
+
return [
'payment' => [
self::PAYPAL_CODE => [
@@ -60,6 +62,8 @@ public function getConfig()
'vaultCode' => self::PAYPAL_VAULT_CODE,
'skipOrderReview' => $this->config->isSkipOrderReview(),
'paymentIcon' => $this->config->getPayPalIcon(),
+ 'isRequiredBillingAddress' =>
+ (int)$this->config->isRequiredBillingAddress() === $requireBillingAddressAll
]
]
];
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml
new file mode 100644
index 0000000000000..e86d5403e11eb
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminRoleActionGroup.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml
new file mode 100644
index 0000000000000..23c322083773c
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/AdminUserActionGroup.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/ConfigureBraintreeActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/ConfigureBraintreeActionGroup.xml
new file mode 100644
index 0000000000000..27e2039fe526e
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/ConfigureBraintreeActionGroup.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateCustomerActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateCustomerActionGroup.xml
new file mode 100644
index 0000000000000..a68042127ec48
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateCustomerActionGroup.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml
new file mode 100644
index 0000000000000..ee7158c2b63f7
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewOrderActionGroup.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewProductActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewProductActionGroup.xml
new file mode 100644
index 0000000000000..19de3e859ae9a
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/CreateNewProductActionGroup.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteCustomerActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteCustomerActionGroup.xml
new file mode 100644
index 0000000000000..65eddc0d9e51a
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteCustomerActionGroup.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteProductActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteProductActionGroup.xml
new file mode 100644
index 0000000000000..724c6d92846c4
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/DeleteProductActionGroup.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/StorefrontFillCartDataActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/StorefrontFillCartDataActionGroup.xml
new file mode 100644
index 0000000000000..bc6d6c2b46dc9
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/StorefrontFillCartDataActionGroup.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/ActionGroup/SwitchAccountActionGroup.xml b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/SwitchAccountActionGroup.xml
new file mode 100644
index 0000000000000..7c774a634b369
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/ActionGroup/SwitchAccountActionGroup.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml
index 6e669a1b8bf4b..8f2588a6effa5 100644
--- a/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml
+++ b/app/code/Magento/Braintree/Test/Mftf/Data/BraintreeData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
SampleTitle
SamplePaymentAction
@@ -35,6 +35,33 @@
somePrivateKey
+
+ BraintreeTitle
+ PaymentAction
+ Environment
+ MerchantId
+ PublicKey
+ PrivateKey
+
+
+ Credit Card (Braintree)
+
+
+ authorize
+
+
+ sandbox
+
+
+ d4pdjhxgjfrsmzbf
+
+
+ m7q4wmh43xrgyrst
+
+
+ 67de364080b1b4e2492d7a3de413a572
+
+
DefaultTitle
@@ -62,4 +89,62 @@
+
+
+ BraintreeValuteActive
+ EnableSolution
+
+
+ 1
+
+
+ 1
+
+
+
+ DefaultBraintreeValuteActive
+ DefaultEnableSolution
+
+
+ 0
+
+
+ 0
+
+
+
+ Website
+ new_website
+ Store
+ new_store
+ Block
+
+
+
+ Role
+
+
+ admin
+ John
+ Smith
+ admin123
+ mail@mail.com
+
+
+
+ 5105105105105100
+ 12
+ 20
+ 113
+
+
+
+ Credit Card (Braintree)
+ d4pdjhxgjfrsmzbf
+ m7q4wmh43xrgyrst
+ 67de364080b1b4e2492d7a3de413a572
+ Magneto
+ PayPal (Braintree)
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/NewCustomerData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/NewCustomerData.xml
new file mode 100644
index 0000000000000..772c1c39a04ca
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Data/NewCustomerData.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+ Abgar
+ Abgaryan
+ m@m.com
+ Abgar
+ Abgaryan
+ Street
+ Yerevan
+ 9999
+ 9999
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Data/NewProductData.xml b/app/code/Magento/Braintree/Test/Mftf/Data/NewProductData.xml
new file mode 100644
index 0000000000000..72661ae94076f
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Data/NewProductData.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ ProductTest
+ 100
+ 100
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Metadata/braintree_config-meta.xml b/app/code/Magento/Braintree/Test/Mftf/Metadata/braintree_config-meta.xml
index e4d02a58b5bf4..5e3b870d65c67 100644
--- a/app/code/Magento/Braintree/Test/Mftf/Metadata/braintree_config-meta.xml
+++ b/app/code/Magento/Braintree/Test/Mftf/Metadata/braintree_config-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
@@ -42,4 +42,22 @@
+
+
+
+
+
+
+
+ integer
+
+
+ string
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateRoleSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateRoleSection.xml
new file mode 100644
index 0000000000000..1158f471d51f0
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateRoleSection.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateUserSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateUserSection.xml
new file mode 100644
index 0000000000000..98d748b5a30ea
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminCreateUserSection.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteRoleSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteRoleSection.xml
new file mode 100644
index 0000000000000..220c9a444b02f
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteRoleSection.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteUserSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteUserSection.xml
new file mode 100644
index 0000000000000..bf2e2b44eb602
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminDeleteUserSection.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditRoleInfoSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditRoleInfoSection.xml
new file mode 100644
index 0000000000000..e37ce8f4738b3
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditRoleInfoSection.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserRoleSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserRoleSection.xml
new file mode 100644
index 0000000000000..e999413c96d74
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserRoleSection.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserSection.xml
new file mode 100644
index 0000000000000..2e5fcfb7b5c8d
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminEditUserSection.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml
new file mode 100644
index 0000000000000..660c7393b4061
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminMenuSection.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminRoleGridSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminRoleGridSection.xml
new file mode 100644
index 0000000000000..63cbadc71d3d3
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminRoleGridSection.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/AdminUserGridSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/AdminUserGridSection.xml
new file mode 100644
index 0000000000000..9564bc61f799c
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/AdminUserGridSection.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfiguraionSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfiguraionSection.xml
new file mode 100644
index 0000000000000..016af2e102744
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfiguraionSection.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfigurationPaymentSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfigurationPaymentSection.xml
new file mode 100644
index 0000000000000..d8e1b837a1d1b
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/BraintreeConfigurationPaymentSection.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/CatalogSubmenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/CatalogSubmenuSection.xml
new file mode 100644
index 0000000000000..32f02a69f817e
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/CatalogSubmenuSection.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationListSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationListSection.xml
new file mode 100644
index 0000000000000..100407438eaae
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationListSection.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationPaymentSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationPaymentSection.xml
new file mode 100644
index 0000000000000..885a45be721f1
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/ConfigurationPaymentSection.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/CustomersPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersPageSection.xml
new file mode 100644
index 0000000000000..e4a75b1b6a842
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersPageSection.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/CustomersSubmenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersSubmenuSection.xml
new file mode 100644
index 0000000000000..937afb83da96f
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/CustomersSubmenuSection.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/NewCustomerPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/NewCustomerPageSection.xml
new file mode 100644
index 0000000000000..d302f9c7d0cba
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/NewCustomerPageSection.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/NewOrderSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/NewOrderSection.xml
new file mode 100644
index 0000000000000..13f59ad2cf18e
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/NewOrderSection.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/NewProductPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/NewProductPageSection.xml
new file mode 100644
index 0000000000000..42e451940c91b
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/NewProductPageSection.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/ProductsPageSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/ProductsPageSection.xml
new file mode 100644
index 0000000000000..267efdf3d0e5e
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/ProductsPageSection.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/StoresSubmenuSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/StoresSubmenuSection.xml
new file mode 100644
index 0000000000000..f094baa9f3446
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/StoresSubmenuSection.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Section/SwitchAccountSection.xml b/app/code/Magento/Braintree/Test/Mftf/Section/SwitchAccountSection.xml
new file mode 100644
index 0000000000000..3a07cbc6dd145
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Section/SwitchAccountSection.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml
new file mode 100644
index 0000000000000..7f6d862ada085
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml b/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml
new file mode 100644
index 0000000000000..df2e98816f0d3
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Mftf/Test/CreateAnAdminOrderUsingBraintreePaymentTest1.xml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php
index 76ab8b8b53b3f..5620e8ffa92b8 100644
--- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php
@@ -5,14 +5,14 @@
*/
namespace Magento\Braintree\Test\Unit\Gateway\Request;
-use Magento\Braintree\Gateway\Config\Config;
-use Magento\Braintree\Gateway\SubjectReader;
use Magento\Braintree\Gateway\Request\PaymentDataBuilder;
+use Magento\Braintree\Gateway\SubjectReader;
use Magento\Braintree\Observer\DataAssignObserver;
use Magento\Payment\Gateway\Data\OrderAdapterInterface;
use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;
use Magento\Sales\Model\Order\Payment;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Magento\Braintree\Gateway\Config\Config;
/**
* Tests \Magento\Braintree\Gateway\Request\PaymentDataBuilder.
@@ -20,18 +20,12 @@
class PaymentDataBuilderTest extends \PHPUnit\Framework\TestCase
{
const PAYMENT_METHOD_NONCE = 'nonce';
- const MERCHANT_ACCOUNT_ID = '245345';
/**
* @var PaymentDataBuilder
*/
private $builder;
- /**
- * @var Config|MockObject
- */
- private $configMock;
-
/**
* @var Payment|MockObject
*/
@@ -52,12 +46,12 @@ class PaymentDataBuilderTest extends \PHPUnit\Framework\TestCase
*/
private $orderMock;
+ /**
+ * @inheritdoc
+ */
protected function setUp()
{
$this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class);
- $this->configMock = $this->getMockBuilder(Config::class)
- ->disableOriginalConstructor()
- ->getMock();
$this->paymentMock = $this->getMockBuilder(Payment::class)
->disableOriginalConstructor()
->getMock();
@@ -66,13 +60,19 @@ protected function setUp()
->getMock();
$this->orderMock = $this->createMock(OrderAdapterInterface::class);
- $this->builder = new PaymentDataBuilder($this->configMock, $this->subjectReaderMock);
+ /** @var Config $config */
+ $config = $this->getMockBuilder(Config::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->builder = new PaymentDataBuilder($config, $this->subjectReaderMock);
}
/**
+ * @return void
* @expectedException \InvalidArgumentException
*/
- public function testBuildReadPaymentException()
+ public function testBuildReadPaymentException(): void
{
$buildSubject = [];
@@ -85,9 +85,10 @@ public function testBuildReadPaymentException()
}
/**
+ * @return void
* @expectedException \InvalidArgumentException
*/
- public function testBuildReadAmountException()
+ public function testBuildReadAmountException(): void
{
$buildSubject = [
'payment' => $this->paymentDOMock,
@@ -106,7 +107,10 @@ public function testBuildReadAmountException()
$this->builder->build($buildSubject);
}
- public function testBuild()
+ /**
+ * @return void
+ */
+ public function testBuild(): void
{
$additionalData = [
[
@@ -118,8 +122,7 @@ public function testBuild()
$expectedResult = [
PaymentDataBuilder::AMOUNT => 10.00,
PaymentDataBuilder::PAYMENT_METHOD_NONCE => self::PAYMENT_METHOD_NONCE,
- PaymentDataBuilder::ORDER_ID => '000000101',
- PaymentDataBuilder::MERCHANT_ACCOUNT_ID => self::MERCHANT_ACCOUNT_ID,
+ PaymentDataBuilder::ORDER_ID => '000000101'
];
$buildSubject = [
@@ -131,10 +134,6 @@ public function testBuild()
->method('getAdditionalInformation')
->willReturnMap($additionalData);
- $this->configMock->expects(self::once())
- ->method('getMerchantAccountId')
- ->willReturn(self::MERCHANT_ACCOUNT_ID);
-
$this->paymentDOMock->expects(self::once())
->method('getPayment')
->willReturn($this->paymentMock);
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/AvailabilityCheckerTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/AvailabilityCheckerTest.php
new file mode 100644
index 0000000000000..2248aab1aad2e
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/AvailabilityCheckerTest.php
@@ -0,0 +1,70 @@
+configMock = $this->createMock(Config::class);
+ $this->availabilityChecker = new AvailabilityChecker($this->configMock);
+ }
+
+ /**
+ * Test isAvailable method
+ *
+ * @dataProvider isAvailableDataProvider
+ *
+ * @param bool $isVerify3DSecure
+ * @param bool $expected
+ *
+ * @return void
+ */
+ public function testIsAvailable(bool $isVerify3DSecure, bool $expected)
+ {
+ $this->configMock->expects($this->once())->method('isVerify3DSecure')->willReturn($isVerify3DSecure);
+ $actual = $this->availabilityChecker->isAvailable();
+ self::assertEquals($expected, $actual);
+ }
+
+ /**
+ * Data provider for isAvailable method test
+ *
+ * @return array
+ */
+ public function isAvailableDataProvider()
+ {
+ return [
+ [true, false],
+ [false, true],
+ ];
+ }
+}
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/TokenFormatterTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/TokenFormatterTest.php
new file mode 100644
index 0000000000000..a5c7cd743d85f
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/CreditCard/TokenFormatterTest.php
@@ -0,0 +1,119 @@
+ 'visa',
+ 'maskedCC' => '1111************9999',
+ 'expirationDate' => '01-01-2020'
+ ];
+
+ /**
+ * Set Up
+ *
+ * @return void
+ */
+ protected function setUp()
+ {
+ $this->paymentTokenMock = $this->getMockBuilder(PaymentTokenInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->creditCardTokenFormatter = new CreditCardTokenFormatter();
+ }
+
+ /**
+ * Testing the payment format with a known credit card type
+ *
+ * @return void
+ */
+ public function testFormatPaymentTokenWithKnownCardType()
+ {
+ $this->tokenDetails['type'] = key(CreditCardTokenFormatter::$baseCardTypes);
+ $this->paymentTokenMock->expects($this->once())
+ ->method('getTokenDetails')
+ ->willReturn(json_encode($this->tokenDetails));
+
+ $formattedString = sprintf(
+ '%s: %s, %s: %s (%s: %s)',
+ __('Credit Card'),
+ reset(CreditCardTokenFormatter::$baseCardTypes),
+ __('ending'),
+ $this->tokenDetails['maskedCC'],
+ __('expires'),
+ $this->tokenDetails['expirationDate']
+ );
+
+ self::assertEquals(
+ $formattedString,
+ $this->creditCardTokenFormatter->formatPaymentToken($this->paymentTokenMock)
+ );
+ }
+
+ /**
+ * Testing the payment format with a unknown credit card type
+ *
+ * @return void
+ */
+ public function testFormatPaymentTokenWithUnknownCardType()
+ {
+ $this->paymentTokenMock->expects($this->once())
+ ->method('getTokenDetails')
+ ->willReturn(json_encode($this->tokenDetails));
+
+ $formattedString = sprintf(
+ '%s: %s, %s: %s (%s: %s)',
+ __('Credit Card'),
+ $this->tokenDetails['type'],
+ __('ending'),
+ $this->tokenDetails['maskedCC'],
+ __('expires'),
+ $this->tokenDetails['expirationDate']
+ );
+
+ self::assertEquals(
+ $formattedString,
+ $this->creditCardTokenFormatter->formatPaymentToken($this->paymentTokenMock)
+ );
+ }
+
+ /**
+ * Testing the payment format with wrong card data
+ *
+ * @return void
+ */
+ public function testFormatPaymentTokenWithWrongData()
+ {
+ unset($this->tokenDetails['type']);
+ $this->paymentTokenMock->expects($this->once())
+ ->method('getTokenDetails')
+ ->willReturn(json_encode($this->tokenDetails));
+ self::expectException('\InvalidArgumentException');
+
+ $this->creditCardTokenFormatter->formatPaymentToken($this->paymentTokenMock);
+ }
+}
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PayPal/TokenFormatterTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PayPal/TokenFormatterTest.php
new file mode 100644
index 0000000000000..e4cd8fd58043b
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PayPal/TokenFormatterTest.php
@@ -0,0 +1,104 @@
+ 'visa',
+ 'maskedCC' => '4444************9999',
+ 'expirationDate' => '07-07-2025'
+ ];
+
+ /**
+ * Test setup
+ */
+ protected function setUp()
+ {
+ $this->paymentTokenMock = $this->getMockBuilder(PaymentTokenInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->paypalTokenFormatter = new PaypalTokenFormatter();
+ }
+
+ /**
+ * testFormatPaymentTokenWithKnownCardType
+ */
+ public function testFormatPaymentTokenWithKnownCardType()
+ {
+ $this->tokenDetails['type'] = key(PaypalTokenFormatter::$baseCardTypes);
+ $this->paymentTokenMock->expects($this->once())
+ ->method('getTokenDetails')
+ ->willReturn(json_encode($this->tokenDetails));
+
+ $formattedString = sprintf(
+ '%s: %s, %s: %s (%s: %s)',
+ __('Credit Card'),
+ reset(PaypalTokenFormatter::$baseCardTypes),
+ __('ending'),
+ $this->tokenDetails['maskedCC'],
+ __('expires'),
+ $this->tokenDetails['expirationDate']
+ );
+
+ self::assertEquals($formattedString, $this->paypalTokenFormatter->formatPaymentToken($this->paymentTokenMock));
+ }
+
+ /**
+ * testFormatPaymentTokenWithUnknownCardType
+ */
+ public function testFormatPaymentTokenWithUnknownCardType()
+ {
+ $this->paymentTokenMock->expects($this->once())
+ ->method('getTokenDetails')
+ ->willReturn(json_encode($this->tokenDetails));
+
+ $formattedString = sprintf(
+ '%s: %s, %s: %s (%s: %s)',
+ __('Credit Card'),
+ $this->tokenDetails['type'],
+ __('ending'),
+ $this->tokenDetails['maskedCC'],
+ __('expires'),
+ $this->tokenDetails['expirationDate']
+ );
+
+ self::assertEquals($formattedString, $this->paypalTokenFormatter->formatPaymentToken($this->paymentTokenMock));
+ }
+
+ /**
+ * testFormatPaymentTokenWithWrongData
+ */
+ public function testFormatPaymentTokenWithWrongData()
+ {
+ unset($this->tokenDetails['type']);
+
+ $this->paymentTokenMock->expects($this->once())
+ ->method('getTokenDetails')
+ ->willReturn(json_encode($this->tokenDetails));
+ self::expectException('\InvalidArgumentException');
+
+ $this->paypalTokenFormatter->formatPaymentToken($this->paymentTokenMock);
+ }
+}
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PaymentAdditionalInformationProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PaymentAdditionalInformationProviderTest.php
new file mode 100644
index 0000000000000..2631fcbe5f5b5
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Unit/Model/InstantPurchase/PaymentAdditionalInformationProviderTest.php
@@ -0,0 +1,83 @@
+getPaymentNonceCommandMock = $this->createMock(GetPaymentNonceCommand::class);
+ $this->paymentTokenMock = $this->createMock(PaymentTokenInterface::class);
+ $this->arrayResultMock = $this->createMock(ArrayResult::class);
+ $this->paymentAdditionalInformationProvider = new PaymentAdditionalInformationProvider(
+ $this->getPaymentNonceCommandMock
+ );
+ }
+
+ /**
+ * Test getAdditionalInformation method
+ *
+ * @return void
+ */
+ public function testGetAdditionalInformation()
+ {
+ $customerId = 15;
+ $publicHash = '3n4b7sn48g';
+ $paymentMethodNonce = 'test';
+
+ $this->paymentTokenMock->expects($this->once())->method('getCustomerId')->willReturn($customerId);
+ $this->paymentTokenMock->expects($this->once())->method('getPublicHash')->willReturn($publicHash);
+ $this->getPaymentNonceCommandMock->expects($this->once())->method('execute')->with([
+ PaymentTokenInterface::CUSTOMER_ID => $customerId,
+ PaymentTokenInterface::PUBLIC_HASH => $publicHash,
+ ])->willReturn($this->arrayResultMock);
+ $this->arrayResultMock->expects($this->once())->method('get')
+ ->willReturn(['paymentMethodNonce' => $paymentMethodNonce]);
+
+ $expected = [
+ 'payment_method_nonce' => $paymentMethodNonce,
+ ];
+ $actual = $this->paymentAdditionalInformationProvider->getAdditionalInformation($this->paymentTokenMock);
+ self::assertEquals($expected, $actual);
+ }
+}
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/LocaleResolverTest.php b/app/code/Magento/Braintree/Test/Unit/Model/LocaleResolverTest.php
new file mode 100644
index 0000000000000..b6ef534c55c29
--- /dev/null
+++ b/app/code/Magento/Braintree/Test/Unit/Model/LocaleResolverTest.php
@@ -0,0 +1,138 @@
+configMock = $this->createMock(Config::class);
+ $this->resolverMock = $this->createMock(ResolverInterface::class);
+ $this->localeResolver = new LocaleResolver($this->resolverMock, $this->configMock);
+ }
+
+ /**
+ * Test getDefaultLocalePath method
+ *
+ * @return void
+ */
+ public function testGetDefaultLocalePath()
+ {
+ $expected = 'general/locale/code';
+ $this->resolverMock->expects($this->once())->method('getDefaultLocalePath')->willReturn($expected);
+ $actual = $this->localeResolver->getDefaultLocalePath();
+ self::assertEquals($expected, $actual);
+ }
+
+ /**
+ * Test setDefaultLocale method
+ *
+ * @return void
+ */
+ public function testSetDefaultLocale()
+ {
+ $defaultLocale = 'en_US';
+ $this->resolverMock->expects($this->once())->method('setDefaultLocale')->with($defaultLocale);
+ $this->localeResolver->setDefaultLocale($defaultLocale);
+ }
+
+ /**
+ * Test getDefaultLocale method
+ *
+ * @return void
+ */
+ public function testGetDefaultLocale()
+ {
+ $expected = 'fr_FR';
+ $this->resolverMock->expects($this->once())->method('getDefaultLocale')->willReturn($expected);
+ $actual = $this->localeResolver->getDefaultLocale();
+ self::assertEquals($expected, $actual);
+ }
+
+ /**
+ * Test setLocale method
+ *
+ * @return void
+ */
+ public function testSetLocale()
+ {
+ $locale = 'en_GB';
+ $this->resolverMock->expects($this->once())->method('setLocale')->with($locale);
+ $this->localeResolver->setLocale($locale);
+ }
+
+ /**
+ * Test getLocale method
+ *
+ * @return void
+ */
+ public function testGetLocale()
+ {
+ $locale = 'en_TEST';
+ $allowedLocales = 'en_US,en_GB,en_AU,da_DK,fr_FR,fr_CA,de_DE,zh_HK,it_IT,nl_NL';
+ $this->resolverMock->expects($this->once())->method('getLocale')->willReturn($locale);
+ $this->configMock->expects($this->once())->method('getValue')->with('supported_locales')
+ ->willReturn($allowedLocales);
+
+ $expected = 'en_US';
+ $actual = $this->localeResolver->getLocale();
+ self::assertEquals($expected, $actual);
+ }
+
+ /**
+ * Test emulate method
+ *
+ * @return void
+ */
+ public function testEmulate()
+ {
+ $scopeId = 12;
+ $this->resolverMock->expects($this->once())->method('emulate')->with($scopeId);
+ $this->localeResolver->emulate($scopeId);
+ }
+
+ /**
+ * Test revert method
+ *
+ * @return void
+ */
+ public function testRevert()
+ {
+ $this->resolverMock->expects($this->once())->method('revert');
+ $this->localeResolver->revert();
+ }
+}
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php
index 76bf5b659bda3..62452228b6186 100644
--- a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php
@@ -51,6 +51,9 @@ class QuoteUpdaterTest extends \PHPUnit\Framework\TestCase
*/
private $quoteUpdater;
+ /**
+ * @return void
+ */
protected function setUp()
{
$this->configMock = $this->getMockBuilder(Config::class)
@@ -99,6 +102,10 @@ protected function setUp()
);
}
+ /**
+ * @return void
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
public function testExecute()
{
$details = $this->getDetails();
@@ -121,6 +128,9 @@ public function testExecute()
$this->quoteUpdater->execute(self::TEST_NONCE, $details, $quoteMock);
}
+ /**
+ * @return void
+ */
private function disabledQuoteAddressValidationStep()
{
$this->billingAddressMock->expects(self::once())
@@ -300,7 +310,7 @@ private function getQuoteMock()
$cartExtensionMock = $this->getMockBuilder(CartExtensionInterface::class)
->setMethods(['setShippingAssignments'])
->disableOriginalConstructor()
- ->getMock();
+ ->getMockForAbstractClass();
$quoteMock->expects(self::any())
->method('getExtensionAttributes')
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php
index 22f7f46bd98f1..42469fe0faf45 100644
--- a/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/PayPal/ConfigProviderTest.php
@@ -77,6 +77,9 @@ public function testGetConfig($expected)
'width' => 30, 'height' => 26, 'url' => 'https://icon.test.url'
]);
+ $this->config->method('isRequiredBillingAddress')
+ ->willReturn(1);
+
self::assertEquals($expected, $this->configProvider->getConfig());
}
@@ -101,7 +104,8 @@ public function getConfigDataProvider()
'skipOrderReview' => false,
'paymentIcon' => [
'width' => 30, 'height' => 26, 'url' => 'https://icon.test.url'
- ]
+ ],
+ 'isRequiredBillingAddress' => true
]
]
]
diff --git a/app/code/Magento/Braintree/composer.json b/app/code/Magento/Braintree/composer.json
index ba51a5436fedb..5af56a2afd3fe 100644
--- a/app/code/Magento/Braintree/composer.json
+++ b/app/code/Magento/Braintree/composer.json
@@ -6,7 +6,7 @@
},
"require": {
"php": "~7.1.3||~7.2.0",
- "braintree/braintree_php": "3.34.0",
+ "braintree/braintree_php": "3.35.0",
"magento/framework": "*",
"magento/magento-composer-installer": "*",
"magento/module-catalog": "*",
diff --git a/app/code/Magento/Braintree/etc/acl.xml b/app/code/Magento/Braintree/etc/acl.xml
index a188586cc0a26..066ccc818d4e6 100644
--- a/app/code/Magento/Braintree/etc/acl.xml
+++ b/app/code/Magento/Braintree/etc/acl.xml
@@ -11,7 +11,16 @@
-
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/etc/adminhtml/di.xml b/app/code/Magento/Braintree/etc/adminhtml/di.xml
index 7a803f803ae89..9de1ad48d2261 100644
--- a/app/code/Magento/Braintree/etc/adminhtml/di.xml
+++ b/app/code/Magento/Braintree/etc/adminhtml/di.xml
@@ -29,6 +29,7 @@
- Magento\Braintree\Gateway\Request\VaultDataBuilder
- Magento\Braintree\Gateway\Request\DescriptorDataBuilder
- Magento\Braintree\Gateway\Request\StoreConfigBuilder
+ - Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
@@ -41,6 +42,7 @@
- Magento\Braintree\Gateway\Request\AddressDataBuilder
- Magento\Braintree\Gateway\Request\DescriptorDataBuilder
- Magento\Braintree\Gateway\Request\StoreConfigBuilder
+ - Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
diff --git a/app/code/Magento/Braintree/etc/adminhtml/menu.xml b/app/code/Magento/Braintree/etc/adminhtml/menu.xml
index 590d5b3dce008..ce4dd4844f3bc 100644
--- a/app/code/Magento/Braintree/etc/adminhtml/menu.xml
+++ b/app/code/Magento/Braintree/etc/adminhtml/menu.xml
@@ -10,6 +10,7 @@
Vault Title
payment/braintree_cc_vault/title
-
+
Merchant Account ID
If you don't specify the merchant account to use to process a transaction, Braintree will process it using your default merchant account.
payment/braintree/merchant_account_id
-
+
Advanced Fraud Protection
Magento\Config\Model\Config\Source\Yesno
Be sure to Enable Advanced Fraud Protection in Your Braintree Account in Settings/Processing Section
payment/braintree/fraudprotection
-
+
Kount Merchant ID
accounts@braintreepayments.com to setup your Kount account.]]>
@@ -108,7 +108,7 @@
Magento\Config\Model\Config\Source\Yesno
payment/braintree/debug
-
+
CVV Verification
Magento\Config\Model\Config\Source\Yesno
Be sure to Enable AVS and/or CVV in Your Braintree Account in Settings/Processing Section.
@@ -149,7 +149,7 @@
PayPal through Braintree
Magento\Config\Block\System\Config\Form\Fieldset
-
+
Title
payment/braintree_paypal/title
It is recommended to set this value to "PayPal" per store views.
@@ -187,7 +187,7 @@
1
payment/braintree_paypal/specificcountry
-
+
Require Customer's Billing Address
Magento\Config\Model\Config\Source\Yesno
payment/braintree_paypal/require_billing_address
@@ -203,7 +203,7 @@
Magento\Config\Model\Config\Source\Yesno
payment/braintree_paypal/debug
-
+
Display on Shopping Cart
Magento\Config\Model\Config\Source\Yesno
payment/braintree_paypal/display_on_shopping_cart
@@ -239,14 +239,14 @@
payment/braintree/verify_specific_countries
-
+
Dynamic Descriptors
Braintree Support.]]>
Magento\Config\Block\System\Config\Form\Fieldset
-
+
Name
payment/braintree/descriptor_name
@@ -254,14 +254,14 @@
and the product descriptor can be up to 18, 14, or 9 characters respectively (with an * in between for a total descriptor name of 22 characters).
-
+
Phone
payment/braintree/descriptor_phone
The value in the phone number field of a customer's statement. Phone must be 10-14 characters and can only contain numbers, dashes, parentheses and periods.
-
+
URL
payment/braintree/descriptor_url
diff --git a/app/code/Magento/Braintree/etc/di.xml b/app/code/Magento/Braintree/etc/di.xml
index 290fb5be58f34..67c90e6991e28 100644
--- a/app/code/Magento/Braintree/etc/di.xml
+++ b/app/code/Magento/Braintree/etc/di.xml
@@ -233,6 +233,7 @@
- Magento\Braintree\Gateway\Request\KountPaymentDataBuilder
- Magento\Braintree\Gateway\Request\DescriptorDataBuilder
- Magento\Braintree\Gateway\Request\StoreConfigBuilder
+ - Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
@@ -291,6 +292,7 @@
- Magento\Braintree\Gateway\Request\KountPaymentDataBuilder
- Magento\Braintree\Gateway\Request\DescriptorDataBuilder
- Magento\Braintree\Gateway\Request\StoreConfigBuilder
+ - Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
@@ -325,6 +327,7 @@
- Magento\Braintree\Gateway\Request\VaultCaptureDataBuilder
- Magento\Braintree\Gateway\Request\SettlementDataBuilder
- Magento\Braintree\Gateway\Request\StoreConfigBuilder
+ - Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
@@ -347,6 +350,7 @@
- Magento\Braintree\Gateway\Request\PayPal\DeviceDataBuilder
- Magento\Braintree\Gateway\Request\DescriptorDataBuilder
- Magento\Braintree\Gateway\Request\StoreConfigBuilder
+ - Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
@@ -380,6 +384,7 @@
- Magento\Braintree\Gateway\Request\AddressDataBuilder
- Magento\Braintree\Gateway\Request\DescriptorDataBuilder
- Magento\Braintree\Gateway\Request\StoreConfigBuilder
+ - Magento\Braintree\Gateway\Request\MerchantAccountDataBuilder
diff --git a/app/code/Magento/Braintree/i18n/en_US.csv b/app/code/Magento/Braintree/i18n/en_US.csv
index 194ad14d49751..6bf677151ed0d 100644
--- a/app/code/Magento/Braintree/i18n/en_US.csv
+++ b/app/code/Magento/Braintree/i18n/en_US.csv
@@ -190,4 +190,5 @@ Currency,Currency
"Partial settlements are not supported by this processor.","Partial settlements are not supported by this processor."
"Transaction can not be voided if status of a PayPal partial settlement child transaction is settlement_pending.","Transaction can not be voided if status of a PayPal partial settlement child transaction is settlement_pending."
"Too many concurrent attempts to refund this transaction. Try again later.","Too many concurrent attempts to refund this transaction. Try again later."
-"Too many concurrent attempts to void this transaction. Try again later.","Too many concurrent attempts to void this transaction. Try again later."
\ No newline at end of file
+"Too many concurrent attempts to void this transaction. Try again later.","Too many concurrent attempts to void this transaction. Try again later."
+"Braintree Settlement","Braintree Settlement"
diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js b/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js
index 9c95b79196e9d..ab01565d7f1e5 100644
--- a/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js
+++ b/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js
@@ -24,6 +24,7 @@ define([
scriptLoaded: false,
braintree: null,
selectedCardType: null,
+ checkout: null,
imports: {
onActiveChange: 'active'
}
@@ -147,6 +148,12 @@ define([
this.disableEventListeners();
+ if (self.checkout) {
+ self.checkout.teardown(function () {
+ self.checkout = null;
+ });
+ }
+
self.braintree.setup(self.clientToken, 'custom', {
id: self.selector,
hostedFields: self.getHostedFields(),
@@ -154,7 +161,8 @@ define([
/**
* Triggered when sdk was loaded
*/
- onReady: function () {
+ onReady: function (checkout) {
+ self.checkout = checkout;
$('body').trigger('processStop');
self.enableEventListeners();
},
diff --git a/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml
index ab294f8e797b7..c4152e1c3ebf9 100644
--- a/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml
+++ b/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml
@@ -35,6 +35,9 @@
-
- false
+ -
+
- true
+
diff --git a/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml b/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml
index 1d60d19458a28..c1ef461ecae7c 100644
--- a/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml
+++ b/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml
@@ -29,6 +29,7 @@ $config = [
class="action-braintree-paypal-logo" disabled>
+ alt="= $block->escapeHtml(__('Pay with PayPal')) ?>"
+ title="= $block->escapeHtml(__('Pay with PayPal')) ?>"/>
diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js
index 7c75cc3e594ee..abf434bc6da26 100644
--- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js
+++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/paypal.js
@@ -206,7 +206,9 @@ define([
beforePlaceOrder: function (data) {
this.setPaymentMethodNonce(data.nonce);
- if (quote.billingAddress() === null && typeof data.details.billingAddress !== 'undefined') {
+ if ((this.isRequiredBillingAddress() || quote.billingAddress() === null) &&
+ typeof data.details.billingAddress !== 'undefined'
+ ) {
this.setBillingAddress(data.details, data.details.billingAddress);
}
@@ -264,6 +266,14 @@ define([
return window.checkoutConfig.payment[this.getCode()].isAllowShippingAddressOverride;
},
+ /**
+ * Is billing address required from PayPal side
+ * @returns {Boolean}
+ */
+ isRequiredBillingAddress: function () {
+ return window.checkoutConfig.payment[this.getCode()].isRequiredBillingAddress;
+ },
+
/**
* Get configuration for PayPal
* @returns {Object}
diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
index 542f170da8c3a..41f11b3d529ee 100644
--- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
+++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
@@ -56,6 +56,11 @@ class Bundle extends \Magento\Catalog\Block\Product\View\AbstractView
*/
private $catalogRuleProcessor;
+ /**
+ * @var array
+ */
+ private $optionsPosition = [];
+
/**
* @param \Magento\Catalog\Block\Product\Context $context
* @param \Magento\Framework\Stdlib\ArrayUtils $arrayUtils
@@ -86,6 +91,8 @@ public function __construct(
}
/**
+ * Return catalog rule processor or creates processor if it does not exist
+ *
* @deprecated 100.2.0
* @return \Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor
*/
@@ -101,6 +108,7 @@ private function getCatalogRuleProcessor()
/**
* Returns the bundle product options
+ *
* Will return cached options data if the product options are already initialized
* In a case when $stripSelection parameter is true will reload stored bundle selections collection from DB
*
@@ -135,6 +143,8 @@ public function getOptions($stripSelection = false)
}
/**
+ * Return true if product has options
+ *
* @return bool
*/
public function hasOptions()
@@ -150,7 +160,6 @@ public function hasOptions()
* Returns JSON encoded config to be used in JS scripts
*
* @return string
- *
*/
public function getJsonConfig()
{
@@ -172,6 +181,7 @@ public function getJsonConfig()
}
$optionId = $optionItem->getId();
$options[$optionId] = $this->getOptionItemData($optionItem, $currentProduct, $position);
+ $this->optionsPosition[$position] = $optionId;
// Add attribute default value (if set)
if ($preConfiguredFlag) {
@@ -370,6 +380,7 @@ private function getConfigData(Product $product, array $options)
$config = [
'options' => $options,
'selected' => $this->selectedOptions,
+ 'positions' => $this->optionsPosition,
'bundleId' => $product->getId(),
'priceFormat' => $this->localeFormat->getPriceFormat(),
'prices' => [
diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php
index 17ecba545efad..92bada8094c7e 100644
--- a/app/code/Magento/Bundle/Model/Product/Type.php
+++ b/app/code/Magento/Bundle/Model/Product/Type.php
@@ -6,13 +6,13 @@
namespace Magento\Bundle\Model\Product;
-use Magento\Framework\App\ObjectManager;
+use Magento\Bundle\Model\ResourceModel\Selection\Collection as Selections;
+use Magento\Bundle\Model\ResourceModel\Selection\Collection\FilterApplier as SelectionCollectionFilterApplier;
use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Framework\Serialize\Serializer\Json;
-use Magento\Framework\EntityManager\MetadataPool;
-use Magento\Bundle\Model\ResourceModel\Selection\Collection\FilterApplier as SelectionCollectionFilterApplier;
-use Magento\Bundle\Model\ResourceModel\Selection\Collection as Selections;
/**
* Bundle Type Model
@@ -537,7 +537,7 @@ public function updateQtyOption($options, \Magento\Framework\DataObject $option,
foreach ($options as $quoteItemOption) {
if ($quoteItemOption->getCode() == 'selection_qty_' . $selection->getSelectionId()) {
if ($optionUpdateFlag) {
- $quoteItemOption->setValue(intval($quoteItemOption->getValue()));
+ $quoteItemOption->setValue((int) $quoteItemOption->getValue());
} else {
$quoteItemOption->setValue($value);
}
@@ -559,7 +559,7 @@ public function updateQtyOption($options, \Magento\Framework\DataObject $option,
*/
public function prepareQuoteItemQty($qty, $product)
{
- return intval($qty);
+ return (int) $qty;
}
/**
@@ -625,6 +625,7 @@ public function isSalable($product)
/**
* Prepare product and its configuration to be added to some products list.
+ *
* Perform standard preparation process and then prepare of bundle selections options.
*
* @param \Magento\Framework\DataObject $buyRequest
@@ -790,6 +791,8 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p
}
/**
+ * Cast array values to int
+ *
* @param array $array
* @return int[]|int[][]
*/
@@ -809,6 +812,8 @@ private function recursiveIntval(array $array)
}
/**
+ * Convert multi dimensional array to flat
+ *
* @param array $array
* @return int[]
*/
@@ -920,8 +925,7 @@ public function getOptionsByIds($optionIds, $product)
}
/**
- * Prepare additional options/information for order item which will be
- * created from this product
+ * Prepare additional options/information for order item which will be created from this product
*
* @param \Magento\Catalog\Model\Product $product
* @return array
@@ -987,6 +991,7 @@ public function getOrderOptions($product)
/**
* Sort selections method for usort function
+ *
* Sort selections by option position, selection position and selection id
*
* @param \Magento\Catalog\Model\Product $firstItem
@@ -1009,10 +1014,8 @@ public function shakeSelections($firstItem, $secondItem)
$secondItem->getPosition(),
$secondItem->getSelectionId(),
];
- if ($aPosition == $bPosition) {
- return 0;
- }
- return $aPosition < $bPosition ? -1 : 1;
+
+ return $aPosition <=> $bPosition;
}
/**
@@ -1050,6 +1053,7 @@ public function getForceChildItemQtyChanges($product)
/**
* Retrieve additional searchable data from type instance
+ *
* Using based on product id and store_id data
*
* @param \Magento\Catalog\Model\Product $product
@@ -1118,6 +1122,7 @@ public function checkProductBuyState($product)
/**
* Retrieve products divided into groups required to purchase
+ *
* At least one product in each group has to be purchased
*
* @param \Magento\Catalog\Model\Product $product
@@ -1214,6 +1219,8 @@ public function getIdentities(\Magento\Catalog\Model\Product $product)
}
/**
+ * Returns selection qty
+ *
* @param \Magento\Framework\DataObject $selection
* @param int[] $qtys
* @param int $selectionOptionId
@@ -1232,6 +1239,8 @@ protected function getQty($selection, $qtys, $selectionOptionId)
}
/**
+ * Returns qty
+ *
* @param \Magento\Catalog\Model\Product $product
* @param \Magento\Framework\DataObject $selection
* @return float|int
@@ -1249,6 +1258,8 @@ protected function getBeforeQty($product, $selection)
}
/**
+ * Validate required options
+ *
* @param \Magento\Catalog\Model\Product $product
* @param bool $isStrictProcessMode
* @param \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection
@@ -1270,6 +1281,8 @@ protected function checkIsAllRequiredOptions($product, $isStrictProcessMode, $op
}
/**
+ * Check if selection is salable
+ *
* @param \Magento\Bundle\Model\ResourceModel\Selection\Collection $selections
* @param bool $skipSaleableCheck
* @param \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection
@@ -1300,6 +1313,8 @@ protected function checkSelectionsIsSale($selections, $skipSaleableCheck, $optio
}
/**
+ * Validate result
+ *
* @param array $_result
* @return void
* @throws \Magento\Framework\Exception\LocalizedException
@@ -1318,6 +1333,8 @@ protected function checkIsResult($_result)
}
/**
+ * Merge selections with options
+ *
* @param \Magento\Catalog\Model\Product\Option[] $options
* @param \Magento\Framework\DataObject[] $selections
* @return \Magento\Framework\DataObject[]
diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php
index 0b6e97cfb9299..b5dfd312cd0c4 100644
--- a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php
+++ b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Price.php
@@ -6,20 +6,171 @@
namespace Magento\Bundle\Model\ResourceModel\Indexer;
use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier;
+use Magento\Framework\Indexer\DimensionalIndexerInterface;
+use Magento\Framework\EntityManager\MetadataPool;
+use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructureFactory;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Query\JoinAttributeProcessor;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
+use Magento\Catalog\Model\Product\Attribute\Source\Status;
/**
* Bundle products Price indexer resource model
*
- * @author Magento Core Team
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Price extends \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice
+class Price implements DimensionalIndexerInterface
{
/**
- * @inheritdoc
+ * @var IndexTableStructureFactory
*/
- protected function reindex($entityIds = null)
+ private $indexTableStructureFactory;
+
+ /**
+ * @var TableMaintainer
+ */
+ private $tableMaintainer;
+
+ /**
+ * @var MetadataPool
+ */
+ private $metadataPool;
+
+ /**
+ * @var \Magento\Framework\App\ResourceConnection
+ */
+ private $resource;
+
+ /**
+ * @var bool
+ */
+ private $fullReindexAction;
+
+ /**
+ * @var string
+ */
+ private $connectionName;
+
+ /**
+ * @var \Magento\Framework\DB\Adapter\AdapterInterface
+ */
+ private $connection;
+
+ /**
+ * Mapping between dimensions and field in database
+ *
+ * @var array
+ */
+ private $dimensionToFieldMapper = [
+ WebsiteDimensionProvider::DIMENSION_NAME => 'pw.website_id',
+ CustomerGroupDimensionProvider::DIMENSION_NAME => 'cg.customer_group_id',
+ ];
+
+ /**
+ * @var BasePriceModifier
+ */
+ private $basePriceModifier;
+
+ /**
+ * @var JoinAttributeProcessor
+ */
+ private $joinAttributeProcessor;
+
+ /**
+ * @var \Magento\Framework\Event\ManagerInterface
+ */
+ private $eventManager;
+
+ /**
+ * @var \Magento\Framework\Module\Manager
+ */
+ private $moduleManager;
+
+ /**
+ * @param IndexTableStructureFactory $indexTableStructureFactory
+ * @param TableMaintainer $tableMaintainer
+ * @param MetadataPool $metadataPool
+ * @param \Magento\Framework\App\ResourceConnection $resource
+ * @param BasePriceModifier $basePriceModifier
+ * @param JoinAttributeProcessor $joinAttributeProcessor
+ * @param \Magento\Framework\Event\ManagerInterface $eventManager
+ * @param \Magento\Framework\Module\Manager $moduleManager
+ * @param bool $fullReindexAction
+ * @param string $connectionName
+ *
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+ */
+ public function __construct(
+ IndexTableStructureFactory $indexTableStructureFactory,
+ TableMaintainer $tableMaintainer,
+ MetadataPool $metadataPool,
+ \Magento\Framework\App\ResourceConnection $resource,
+ BasePriceModifier $basePriceModifier,
+ JoinAttributeProcessor $joinAttributeProcessor,
+ \Magento\Framework\Event\ManagerInterface $eventManager,
+ \Magento\Framework\Module\Manager $moduleManager,
+ $fullReindexAction = false,
+ $connectionName = 'indexer'
+ ) {
+ $this->indexTableStructureFactory = $indexTableStructureFactory;
+ $this->tableMaintainer = $tableMaintainer;
+ $this->connectionName = $connectionName;
+ $this->metadataPool = $metadataPool;
+ $this->resource = $resource;
+ $this->fullReindexAction = $fullReindexAction;
+ $this->basePriceModifier = $basePriceModifier;
+ $this->joinAttributeProcessor = $joinAttributeProcessor;
+ $this->eventManager = $eventManager;
+ $this->moduleManager = $moduleManager;
+ }
+
+ /**
+ * {@inheritdoc}
+ * @param array $dimensions
+ * @param \Traversable $entityIds
+ * @throws \Exception
+ */
+ public function executeByDimensions(array $dimensions, \Traversable $entityIds)
{
- $this->_prepareBundlePrice($entityIds);
+ $this->tableMaintainer->createMainTmpTable($dimensions);
+
+ $temporaryPriceTable = $this->indexTableStructureFactory->create([
+ 'tableName' => $this->tableMaintainer->getMainTmpTable($dimensions),
+ 'entityField' => 'entity_id',
+ 'customerGroupField' => 'customer_group_id',
+ 'websiteField' => 'website_id',
+ 'taxClassField' => 'tax_class_id',
+ 'originalPriceField' => 'price',
+ 'finalPriceField' => 'final_price',
+ 'minPriceField' => 'min_price',
+ 'maxPriceField' => 'max_price',
+ 'tierPriceField' => 'tier_price',
+ ]);
+
+ $entityIds = iterator_to_array($entityIds);
+
+ $this->prepareTierPriceIndex($dimensions, $entityIds);
+
+ $this->prepareBundlePriceTable();
+
+ $this->prepareBundlePriceByType(
+ \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED,
+ $dimensions,
+ $entityIds
+ );
+
+ $this->prepareBundlePriceByType(
+ \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC,
+ $dimensions,
+ $entityIds
+ );
+
+ $this->calculateBundleOptionPrice($temporaryPriceTable, $dimensions);
+
+ $this->basePriceModifier->modifyPrice($temporaryPriceTable, $entityIds);
}
/**
@@ -27,9 +178,9 @@ protected function reindex($entityIds = null)
*
* @return string
*/
- protected function _getBundlePriceTable()
+ private function getBundlePriceTable()
{
- return $this->tableStrategy->getTableName('catalog_product_index_price_bundle');
+ return $this->getTable('catalog_product_index_price_bundle_tmp');
}
/**
@@ -37,9 +188,9 @@ protected function _getBundlePriceTable()
*
* @return string
*/
- protected function _getBundleSelectionTable()
+ private function getBundleSelectionTable()
{
- return $this->tableStrategy->getTableName('catalog_product_index_price_bundle_sel');
+ return $this->getTable('catalog_product_index_price_bundle_sel_tmp');
}
/**
@@ -47,9 +198,9 @@ protected function _getBundleSelectionTable()
*
* @return string
*/
- protected function _getBundleOptionTable()
+ private function getBundleOptionTable()
{
- return $this->tableStrategy->getTableName('catalog_product_index_price_bundle_opt');
+ return $this->getTable('catalog_product_index_price_bundle_opt_tmp');
}
/**
@@ -57,9 +208,9 @@ protected function _getBundleOptionTable()
*
* @return $this
*/
- protected function _prepareBundlePriceTable()
+ private function prepareBundlePriceTable()
{
- $this->getConnection()->delete($this->_getBundlePriceTable());
+ $this->getConnection()->delete($this->getBundlePriceTable());
return $this;
}
@@ -68,9 +219,9 @@ protected function _prepareBundlePriceTable()
*
* @return $this
*/
- protected function _prepareBundleSelectionTable()
+ private function prepareBundleSelectionTable()
{
- $this->getConnection()->delete($this->_getBundleSelectionTable());
+ $this->getConnection()->delete($this->getBundleSelectionTable());
return $this;
}
@@ -79,9 +230,9 @@ protected function _prepareBundleSelectionTable()
*
* @return $this
*/
- protected function _prepareBundleOptionTable()
+ private function prepareBundleOptionTable()
{
- $this->getConnection()->delete($this->_getBundleOptionTable());
+ $this->getConnection()->delete($this->getBundleOptionTable());
return $this;
}
@@ -89,51 +240,58 @@ protected function _prepareBundleOptionTable()
* Prepare temporary price index data for bundle products by price type
*
* @param int $priceType
+ * @param array $dimensions
* @param int|array $entityIds the entity ids limitation
- * @return $this
+ * @return void
+ * @throws \Exception
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
- protected function _prepareBundlePriceByType($priceType, $entityIds = null)
+ private function prepareBundlePriceByType($priceType, array $dimensions, $entityIds = null)
{
$connection = $this->getConnection();
- $table = $this->_getBundlePriceTable();
-
$select = $connection->select()->from(
['e' => $this->getTable('catalog_product_entity')],
['entity_id']
- )->join(
+ )->joinInner(
['cg' => $this->getTable('customer_group')],
- '',
+ array_key_exists(CustomerGroupDimensionProvider::DIMENSION_NAME, $dimensions)
+ ? sprintf(
+ '%s = %s',
+ $this->dimensionToFieldMapper[CustomerGroupDimensionProvider::DIMENSION_NAME],
+ $dimensions[CustomerGroupDimensionProvider::DIMENSION_NAME]->getValue()
+ ) : '',
['customer_group_id']
- );
- $this->_addWebsiteJoinToSelect($select, true);
- $this->_addProductWebsiteJoinToSelect($select, 'cw.website_id', "e.entity_id");
- $select->columns(
- 'website_id',
- 'cw'
- )->join(
- ['cwd' => $this->_getWebsiteDateTable()],
- 'cw.website_id = cwd.website_id',
+ )->joinInner(
+ ['pw' => $this->getTable('catalog_product_website')],
+ 'pw.product_id = e.entity_id',
+ ['pw.website_id']
+ )->joinInner(
+ ['cwd' => $this->getTable('catalog_product_index_website')],
+ 'pw.website_id = cwd.website_id',
[]
- )->joinLeft(
- ['tp' => $this->_getTierPriceIndexTable()],
- 'tp.entity_id = e.entity_id AND tp.website_id = cw.website_id' .
+ );
+ $select->joinLeft(
+ ['tp' => $this->getTable('catalog_product_index_tier_price')],
+ 'tp.entity_id = e.entity_id AND tp.website_id = pw.website_id' .
' AND tp.customer_group_id = cg.customer_group_id',
[]
)->where(
'e.type_id=?',
- $this->getTypeId()
+ \Magento\Bundle\Ui\DataProvider\Product\Listing\Collector\BundlePrice::PRODUCT_TYPE
);
- // add enable products limitation
- $statusCond = $connection->quoteInto(
- '=?',
- \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
- );
- $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
- $this->_addAttributeToSelect($select, 'status', "e.$linkField", 'cs.store_id', $statusCond, true);
+ foreach ($dimensions as $dimension) {
+ if (!isset($this->dimensionToFieldMapper[$dimension->getName()])) {
+ throw new \LogicException(
+ 'Provided dimension is not valid for Price indexer: ' . $dimension->getName()
+ );
+ }
+ $select->where($this->dimensionToFieldMapper[$dimension->getName()] . ' = ?', $dimension->getValue());
+ }
+
+ $this->joinAttributeProcessor->process($select, 'status', Status::STATUS_ENABLED);
if ($this->moduleManager->isEnabled('Magento_Tax')) {
- $taxClassId = $this->_addAttributeToSelect($select, 'tax_class_id', "e.$linkField", 'cs.store_id');
+ $taxClassId = $this->joinAttributeProcessor->process($select, 'tax_class_id');
} else {
$taxClassId = new \Zend_Db_Expr('0');
}
@@ -146,13 +304,12 @@ protected function _prepareBundlePriceByType($priceType, $entityIds = null)
);
}
- $priceTypeCond = $connection->quoteInto('=?', $priceType);
- $this->_addAttributeToSelect($select, 'price_type', "e.$linkField", 'cs.store_id', $priceTypeCond);
+ $this->joinAttributeProcessor->process($select, 'price_type', $priceType);
- $price = $this->_addAttributeToSelect($select, 'price', "e.$linkField", 'cs.store_id');
- $specialPrice = $this->_addAttributeToSelect($select, 'special_price', "e.$linkField", 'cs.store_id');
- $specialFrom = $this->_addAttributeToSelect($select, 'special_from_date', "e.$linkField", 'cs.store_id');
- $specialTo = $this->_addAttributeToSelect($select, 'special_to_date', "e.$linkField", 'cs.store_id');
+ $price = $this->joinAttributeProcessor->process($select, 'price');
+ $specialPrice = $this->joinAttributeProcessor->process($select, 'special_price');
+ $specialFrom = $this->joinAttributeProcessor->process($select, 'special_from_date');
+ $specialTo = $this->joinAttributeProcessor->process($select, 'special_to_date');
$currentDate = new \Zend_Db_Expr('cwd.website_date');
$specialFromDate = $connection->getDatePartSql($specialFrom);
@@ -205,39 +362,41 @@ protected function _prepareBundlePriceByType($priceType, $entityIds = null)
/**
* Add additional external limitation
*/
- $this->_eventManager->dispatch(
+ $this->eventManager->dispatch(
'catalog_product_prepare_index_select',
[
'select' => $select,
'entity_field' => new \Zend_Db_Expr('e.entity_id'),
- 'website_field' => new \Zend_Db_Expr('cw.website_id'),
- 'store_field' => new \Zend_Db_Expr('cs.store_id')
+ 'website_field' => new \Zend_Db_Expr('pw.website_id'),
+ 'store_field' => new \Zend_Db_Expr('cwd.default_store_id')
]
);
- $query = $select->insertFromSelect($table);
+ $query = $select->insertFromSelect($this->getBundlePriceTable());
$connection->query($query);
-
- return $this;
}
/**
* Calculate fixed bundle product selections price
*
- * @return $this
+ * @param IndexTableStructure $priceTable
+ * @param array $dimensions
+ *
+ * @return void
+ * @throws \Exception
*/
- protected function _calculateBundleOptionPrice()
+ private function calculateBundleOptionPrice($priceTable, $dimensions)
{
$connection = $this->getConnection();
- $this->_prepareBundleSelectionTable();
- $this->_calculateBundleSelectionPrice(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED);
- $this->_calculateBundleSelectionPrice(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC);
+ $this->prepareBundleSelectionTable();
+ $this->calculateBundleSelectionPrice($dimensions, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED);
+ $this->calculateBundleSelectionPrice($dimensions, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC);
- $this->_prepareBundleOptionTable();
+ $this->prepareBundleOptionTable();
$select = $connection->select()->from(
- $this->_getBundleSelectionTable(),
+ $this->getBundleSelectionTable(),
['entity_id', 'customer_group_id', 'website_id', 'option_id']
)->group(
['entity_id', 'customer_group_id', 'website_id', 'option_id']
@@ -254,24 +413,24 @@ protected function _calculateBundleOptionPrice()
]
);
- $query = $select->insertFromSelect($this->_getBundleOptionTable());
+ $query = $select->insertFromSelect($this->getBundleOptionTable());
$connection->query($query);
- $this->_prepareDefaultFinalPriceTable();
- $this->applyBundlePrice();
- $this->applyBundleOptionPrice();
-
- return $this;
+ $this->getConnection()->delete($priceTable->getTableName());
+ $this->applyBundlePrice($priceTable);
+ $this->applyBundleOptionPrice($priceTable);
}
/**
* Calculate bundle product selections price by product type
*
+ * @param array $dimensions
* @param int $priceType
- * @return $this
+ * @return void
+ * @throws \Exception
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
- protected function _calculateBundleSelectionPrice($priceType)
+ private function calculateBundleSelectionPrice($dimensions, $priceType)
{
$connection = $this->getConnection();
@@ -334,9 +493,10 @@ protected function _calculateBundleSelectionPrice($priceType)
]);
}
- $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
+ $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
+ $linkField = $metadata->getLinkField();
$select = $connection->select()->from(
- ['i' => $this->_getBundlePriceTable()],
+ ['i' => $this->getBundlePriceTable()],
['entity_id', 'customer_group_id', 'website_id']
)->join(
['parent_product' => $this->getTable('catalog_product_entity')],
@@ -355,7 +515,7 @@ protected function _calculateBundleSelectionPrice($priceType)
'bs.selection_id = bsp.selection_id AND bsp.website_id = i.website_id',
['']
)->join(
- ['idx' => $this->getIdxTable()],
+ ['idx' => $this->getMainTable($dimensions)],
'bs.product_id = idx.entity_id AND i.customer_group_id = idx.customer_group_id' .
' AND i.website_id = idx.website_id',
[]
@@ -375,49 +535,26 @@ protected function _calculateBundleSelectionPrice($priceType)
]
);
- $query = $select->insertFromSelect($this->_getBundleSelectionTable());
+ $query = $select->insertFromSelect($this->getBundleSelectionTable());
$connection->query($query);
-
- return $this;
- }
-
- /**
- * Prepare temporary index price for bundle products
- *
- * @param int|array $entityIds the entity ids limitation
- * @return $this
- */
- protected function _prepareBundlePrice($entityIds = null)
- {
- if (!$this->hasEntity() && empty($entityIds)) {
- return $this;
- }
- $this->_prepareTierPriceIndex($entityIds);
- $this->_prepareBundlePriceTable();
- $this->_prepareBundlePriceByType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED, $entityIds);
- $this->_prepareBundlePriceByType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC, $entityIds);
-
- $this->_calculateBundleOptionPrice();
- $this->_applyCustomOption();
-
- $this->_movePriceDataToIndexTable();
-
- return $this;
}
/**
* Prepare percentage tier price for bundle products
*
- * @param int|array $entityIds
- * @return $this
+ * @param array $dimensions
+ * @param array $entityIds
+ * @return void
+ * @throws \Exception
*/
- protected function _prepareTierPriceIndex($entityIds = null)
+ private function prepareTierPriceIndex($dimensions, $entityIds)
{
$connection = $this->getConnection();
- $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
+ $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
+ $linkField = $metadata->getLinkField();
// remove index by bundle products
$select = $connection->select()->from(
- ['i' => $this->_getTierPriceIndexTable()],
+ ['i' => $this->getTable('catalog_product_index_tier_price')],
null
)->join(
['e' => $this->getTable('catalog_product_entity')],
@@ -425,7 +562,7 @@ protected function _prepareTierPriceIndex($entityIds = null)
[]
)->where(
'e.type_id=?',
- $this->getTypeId()
+ \Magento\Bundle\Ui\DataProvider\Product\Listing\Collector\BundlePrice::PRODUCT_TYPE
);
$query = $select->deleteFromSelect('i');
$connection->query($query);
@@ -442,40 +579,47 @@ protected function _prepareTierPriceIndex($entityIds = null)
'tp.all_groups = 1 OR (tp.all_groups = 0 AND tp.customer_group_id = cg.customer_group_id)',
['customer_group_id']
)->join(
- ['cw' => $this->getTable('store_website')],
- 'tp.website_id = 0 OR tp.website_id = cw.website_id',
+ ['pw' => $this->getTable('store_website')],
+ 'tp.website_id = 0 OR tp.website_id = pw.website_id',
['website_id']
)->where(
- 'cw.website_id != 0'
+ 'pw.website_id != 0'
)->where(
'e.type_id=?',
- $this->getTypeId()
+ \Magento\Bundle\Ui\DataProvider\Product\Listing\Collector\BundlePrice::PRODUCT_TYPE
)->columns(
new \Zend_Db_Expr('MIN(tp.value)')
)->group(
- ['e.entity_id', 'cg.customer_group_id', 'cw.website_id']
+ ['e.entity_id', 'cg.customer_group_id', 'pw.website_id']
);
if (!empty($entityIds)) {
$select->where('e.entity_id IN(?)', $entityIds);
}
+ foreach ($dimensions as $dimension) {
+ if (!isset($this->dimensionToFieldMapper[$dimension->getName()])) {
+ throw new \LogicException(
+ 'Provided dimension is not valid for Price indexer: ' . $dimension->getName()
+ );
+ }
+ $select->where($this->dimensionToFieldMapper[$dimension->getName()] . ' = ?', $dimension->getValue());
+ }
- $query = $select->insertFromSelect($this->_getTierPriceIndexTable());
+ $query = $select->insertFromSelect($this->getTable('catalog_product_index_tier_price'));
$connection->query($query);
-
- return $this;
}
/**
* Create bundle price.
*
+ * @param IndexTableStructure $priceTable
* @return void
*/
- private function applyBundlePrice(): void
+ private function applyBundlePrice($priceTable): void
{
$select = $this->getConnection()->select();
$select->from(
- $this->_getBundlePriceTable(),
+ $this->getBundlePriceTable(),
[
'entity_id',
'customer_group_id',
@@ -486,11 +630,10 @@ private function applyBundlePrice(): void
'min_price',
'max_price',
'tier_price',
- 'base_tier',
]
);
- $query = $select->insertFromSelect($this->_getDefaultFinalPriceTable());
+ $query = $select->insertFromSelect($priceTable->getTableName());
$this->getConnection()->query($query);
}
@@ -498,13 +641,14 @@ private function applyBundlePrice(): void
* Make insert/update bundle option price.
*
* @return void
+ * @param IndexTableStructure $priceTable
*/
- private function applyBundleOptionPrice(): void
+ private function applyBundleOptionPrice($priceTable): void
{
$connection = $this->getConnection();
$subSelect = $connection->select()->from(
- $this->_getBundleOptionTable(),
+ $this->getBundleOptionTable(),
[
'entity_id',
'customer_group_id',
@@ -534,7 +678,47 @@ private function applyBundleOptionPrice(): void
]
);
- $query = $select->crossUpdateFromSelect(['i' => $this->_getDefaultFinalPriceTable()]);
+ $query = $select->crossUpdateFromSelect(['i' => $priceTable->getTableName()]);
$connection->query($query);
}
+
+ /**
+ * Get main table
+ *
+ * @param array $dimensions
+ * @return string
+ */
+ private function getMainTable($dimensions)
+ {
+ if ($this->fullReindexAction) {
+ return $this->tableMaintainer->getMainReplicaTable($dimensions);
+ }
+ return $this->tableMaintainer->getMainTable($dimensions);
+ }
+
+ /**
+ * Get connection
+ *
+ * return \Magento\Framework\DB\Adapter\AdapterInterface
+ * @throws \DomainException
+ */
+ private function getConnection(): \Magento\Framework\DB\Adapter\AdapterInterface
+ {
+ if ($this->connection === null) {
+ $this->connection = $this->resource->getConnection($this->connectionName);
+ }
+
+ return $this->connection;
+ }
+
+ /**
+ * Get table
+ *
+ * @param string $tableName
+ * @return string
+ */
+ private function getTable($tableName)
+ {
+ return $this->resource->getTableName($tableName, $this->connectionName);
+ }
}
diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Selection/Collection.php b/app/code/Magento/Bundle/Model/ResourceModel/Selection/Collection.php
index e9295b22674bd..5b88288ff72ca 100644
--- a/app/code/Magento/Bundle/Model/ResourceModel/Selection/Collection.php
+++ b/app/code/Magento/Bundle/Model/ResourceModel/Selection/Collection.php
@@ -5,10 +5,8 @@
*/
namespace Magento\Bundle\Model\ResourceModel\Selection;
-use Magento\Customer\Api\GroupManagementInterface;
use Magento\Framework\DataObject;
use Magento\Framework\DB\Select;
-use Magento\Framework\EntityManager\MetadataPool;
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
use Magento\Framework\App\ObjectManager;
@@ -45,6 +43,95 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
*/
private $websiteScopePriceJoined = false;
+ /**
+ * @var \Magento\CatalogInventory\Model\ResourceModel\Stock\Item
+ */
+ private $stockItem;
+
+ /**
+ * Collection constructor.
+ * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
+ * @param \Psr\Log\LoggerInterface $logger
+ * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
+ * @param \Magento\Framework\Event\ManagerInterface $eventManager
+ * @param \Magento\Eav\Model\Config $eavConfig
+ * @param \Magento\Framework\App\ResourceConnection $resource
+ * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
+ * @param \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper
+ * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
+ * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+ * @param \Magento\Framework\Module\Manager $moduleManager
+ * @param \Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
+ * @param \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory
+ * @param \Magento\Catalog\Model\ResourceModel\Url $catalogUrl
+ * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
+ * @param \Magento\Customer\Model\Session $customerSession
+ * @param \Magento\Framework\Stdlib\DateTime $dateTime
+ * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
+ * @param \Magento\Framework\DB\Adapter\AdapterInterface|null $connection
+ * @param ProductLimitationFactory|null $productLimitationFactory
+ * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool
+ * @param \Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer|null $tableMaintainer
+ * @param \Magento\CatalogInventory\Model\ResourceModel\Stock\Item|null $stockItem
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+ */
+ public function __construct(
+ \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
+ \Psr\Log\LoggerInterface $logger,
+ \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
+ \Magento\Framework\Event\ManagerInterface $eventManager,
+ \Magento\Eav\Model\Config $eavConfig,
+ \Magento\Framework\App\ResourceConnection $resource,
+ \Magento\Eav\Model\EntityFactory $eavEntityFactory,
+ \Magento\Catalog\Model\ResourceModel\Helper $resourceHelper,
+ \Magento\Framework\Validator\UniversalFactory $universalFactory,
+ \Magento\Store\Model\StoreManagerInterface $storeManager,
+ \Magento\Framework\Module\Manager $moduleManager,
+ \Magento\Catalog\Model\Indexer\Product\Flat\State $catalogProductFlatState,
+ \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
+ \Magento\Catalog\Model\Product\OptionFactory $productOptionFactory,
+ \Magento\Catalog\Model\ResourceModel\Url $catalogUrl,
+ \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
+ \Magento\Customer\Model\Session $customerSession,
+ \Magento\Framework\Stdlib\DateTime $dateTime,
+ \Magento\Customer\Api\GroupManagementInterface $groupManagement,
+ \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
+ ProductLimitationFactory $productLimitationFactory = null,
+ \Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
+ \Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer $tableMaintainer = null,
+ \Magento\CatalogInventory\Model\ResourceModel\Stock\Item $stockItem = null
+ ) {
+ parent::__construct(
+ $entityFactory,
+ $logger,
+ $fetchStrategy,
+ $eventManager,
+ $eavConfig,
+ $resource,
+ $eavEntityFactory,
+ $resourceHelper,
+ $universalFactory,
+ $storeManager,
+ $moduleManager,
+ $catalogProductFlatState,
+ $scopeConfig,
+ $productOptionFactory,
+ $catalogUrl,
+ $localeDate,
+ $customerSession,
+ $dateTime,
+ $groupManagement,
+ $connection,
+ $productLimitationFactory,
+ $metadataPool,
+ $tableMaintainer
+ );
+
+ $this->stockItem = $stockItem
+ ?? ObjectManager::getInstance()->get(\Magento\CatalogInventory\Model\ResourceModel\Stock\Item::class);
+ }
+
/**
* Initialize collection
*
@@ -64,13 +151,7 @@ protected function _construct()
*/
public function _afterLoad()
{
- parent::_afterLoad();
- if ($this->getStoreId() && $this->_items) {
- foreach ($this->_items as $item) {
- $item->setStoreId($this->getStoreId());
- }
- }
- return $this;
+ return parent::_afterLoad();
}
/**
@@ -170,28 +251,30 @@ public function setPositionOrder()
*/
public function addQuantityFilter()
{
- $stockItemTable = $this->getTable('cataloginventory_stock_item');
- $stockStatusTable = $this->getTable('cataloginventory_stock_status');
+ $manageStockExpr = $this->stockItem->getManageStockExpr('stock_item');
+ $backordersExpr = $this->stockItem->getBackordersExpr('stock_item');
+ $minQtyExpr = $this->getConnection()->getCheckSql(
+ 'selection.selection_can_change_qty',
+ $this->stockItem->getMinSaleQtyExpr('stock_item'),
+ 'selection.selection_qty'
+ );
+
+ $where = $manageStockExpr . ' = 0';
+ $where .= ' OR ('
+ . 'stock_item.is_in_stock = ' . \Magento\CatalogInventory\Model\Stock::STOCK_IN_STOCK
+ . ' AND ('
+ . $backordersExpr . ' != ' . \Magento\CatalogInventory\Model\Stock::BACKORDERS_NO
+ . ' OR '
+ . $minQtyExpr . ' <= stock_item.qty'
+ . ')'
+ . ')';
+
$this->getSelect()
->joinInner(
- ['stock' => $stockStatusTable],
- 'selection.product_id = stock.product_id',
- []
- )->joinInner(
- ['stock_item' => $stockItemTable],
+ ['stock_item' => $this->stockItem->getMainTable()],
'selection.product_id = stock_item.product_id',
[]
- )
- ->where(
- '('
- . 'selection.selection_can_change_qty > 0'
- . ' or '
- . 'selection.selection_qty <= stock.qty'
- . ' or '
- .'stock_item.manage_stock = 0'
- . ')'
- )
- ->where('stock.stock_status = 1');
+ )->where($where);
return $this;
}
@@ -267,7 +350,10 @@ public function addPriceFilter($product, $searchMin, $useRegularPrice = false)
}
/**
+ * Get Catalog Rule Processor.
+ *
* @return \Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor
+ *
* @deprecated 100.2.0
*/
private function getCatalogRuleProcessor()
diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php
index 927b8fbff8d85..a28d721cc9a4e 100644
--- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php
+++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php
@@ -54,7 +54,7 @@ public function create(
) {
$arguments['bundleProduct'] = $bundleProduct;
$arguments['saleableItem'] = $selection;
- $arguments['quantity'] = $quantity ? floatval($quantity) : 1.;
+ $arguments['quantity'] = $quantity ? (float)$quantity : 1.;
return $this->objectManager->create(self::SELECTION_CLASS_DEFAULT, $arguments);
}
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminBundleProductActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminBundleProductActionGroup.xml
index a5e62fca9483c..836826734f02d 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminBundleProductActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminBundleProductActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminClearFiltersActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminClearFiltersActionGroup.xml
old mode 100644
new mode 100755
index f3e5eff3834e3..b3ac72d3f416e
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminClearFiltersActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminClearFiltersActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/BundleProductFilterActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/BundleProductFilterActionGroup.xml
index 8ab7af1d0318e..177f9203ed146 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/BundleProductFilterActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/BundleProductFilterActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/CreateBundleProductActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/CreateBundleProductActionGroup.xml
index af8fc1459d9e3..72e729111948f 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/CreateBundleProductActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/CreateBundleProductActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
@@ -15,11 +15,12 @@
-
-
+
+
+
-
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/EnableDisableProductActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/EnableDisableProductActionGroup.xml
index 2ae9748c773e8..e3ac6483bc7bd 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/EnableDisableProductActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/EnableDisableProductActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/SetBundleProductAttributesActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/SetBundleProductAttributesActionGroup.xml
new file mode 100644
index 0000000000000..50af5993af5bc
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/SetBundleProductAttributesActionGroup.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml
index 48697d43ec824..f28ffbdc40acc 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml
index 7123a573bc2e1..60d11345731c1 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Data/BundleLinkData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml
index e10fe4e33c208..a53ae9be4b75b 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Data/BundleOptionData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
bundle-option-dropdown
true
diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml
index 380b5b8959025..e6866ae74a7e1 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Data/CustomAttributeData.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
price_type
0
diff --git a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml
index f48810e0534fe..af93200f946d2 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Data/ProductData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
BundleProduct
BundleProduct2
@@ -23,6 +23,7 @@
bundleproduct2
10
20
+ 30
4
bundle
10
diff --git a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml
index ca39253aa54a0..254f542316d10 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_link-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
application/json
diff --git a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_option-meta.xml b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_option-meta.xml
index c912ea5eac41a..4e1dc7ac9cb50 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_option-meta.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_option-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
application/json
diff --git a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_options-meta.xml b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_options-meta.xml
index 12cba3fc179fe..df931c74191f9 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_options-meta.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Metadata/bundle_options-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
application/json
diff --git a/app/code/Magento/Bundle/Test/Mftf/Page/AdminCatalogProductPage.xml b/app/code/Magento/Bundle/Test/Mftf/Page/AdminCatalogProductPage.xml
index cb97521499e23..782c97aab1a29 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Page/AdminCatalogProductPage.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Page/AdminCatalogProductPage.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Page/AdminProductCreatePage.xml b/app/code/Magento/Bundle/Test/Mftf/Page/AdminProductCreatePage.xml
index f0048e2fc95d4..562ded6c8e40f 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Page/AdminProductCreatePage.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Page/AdminProductCreatePage.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml
index 25f1d95dc863c..814d03c52f4be 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/AdminProductFormBundleSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
@@ -49,7 +49,9 @@
-
+
+
+
@@ -61,9 +63,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml
index 1a8709bd84e9e..7a188fd58e1af 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/BundleStorefrontSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml
index f724f9bbfe1bd..8d9f29814f762 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontCategoryProductSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontCategoryProductSection.xml
index c76f822a0913f..3d5dc61d88a87 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontCategoryProductSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontCategoryProductSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductActionSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductActionSection.xml
index abc9bc6dab540..9dc4aed26bef0 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductActionSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductActionSection.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml
index 41c00b5eda184..735571375866e 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontProductInfoMainSection.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml
index d94e196ea5ad1..401d360a34c64 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddBundleItemsTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddDefaultImageBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddDefaultImageBundleProductTest.xml
index e1f90790b30a9..21e6be98b3169 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddDefaultImageBundleProductTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddDefaultImageBundleProductTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddDefaultVideoBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddDefaultVideoBundleProductTest.xml
new file mode 100644
index 0000000000000..3c00344697699
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAddDefaultVideoBundleProductTest.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml
index 795982eb4b939..1d2f21b7d15f9 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml
new file mode 100644
index 0000000000000..3a70b189b4dce
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminBundleProductSetEditContentTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBundleProductSetEditContentTest.xml
new file mode 100644
index 0000000000000..65733a5bcc037
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBundleProductSetEditContentTest.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml
index bf62212babd43..86db6f372b5f8 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteABundleProduct.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminEditRelatedBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminEditRelatedBundleProductTest.xml
new file mode 100644
index 0000000000000..08faa9d2444df
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminEditRelatedBundleProductTest.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminFilterProductListByBundleProduct.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminFilterProductListByBundleProduct.xml
index 9faf9e69bc873..40a6e1b75c60a 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminFilterProductListByBundleProduct.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminFilterProductListByBundleProduct.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml
index 6cb86d8028352..c0edbf14e894b 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminMassDeleteBundleProducts.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml
index 643f13dfd61ed..f87897bd579a3 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminProductBundleCreationTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml
index ccd729ac841cd..1438958b92b61 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultImageBundleProductTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultVideoBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultVideoBundleProductTest.xml
new file mode 100644
index 0000000000000..e3cb68b6664e2
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminRemoveDefaultVideoBundleProductTest.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdvanceCatalogSearchBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdvanceCatalogSearchBundleProductTest.xml
new file mode 100644
index 0000000000000..0b220efaad49f
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdvanceCatalogSearchBundleProductTest.xml
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml
index a579460906d0e..574c0dccdb07f 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/BundleProductFixedPricingTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml
index 7a7b4673eda6d..0cfd1f99a8ce0 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/EnableDisableBundleProductStatusTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/EndToEndB2CAdminTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/EndToEndB2CAdminTest.xml
index 9402d1d48012f..9040d675be34f 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/EndToEndB2CAdminTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/EndToEndB2CAdminTest.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml
index 89867341e96d3..0fb8a7b88250c 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/NewBundleProductSelectionTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/NewBundleProductSelectionTest.xml
index 8a0a1ceaf52c7..e0a6a9afd648e 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/NewBundleProductSelectionTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/NewBundleProductSelectionTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/NewProductsListWidgetBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/NewProductsListWidgetBundleProductTest.xml
new file mode 100644
index 0000000000000..8efe32a7d84c0
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/NewProductsListWidgetBundleProductTest.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdminEditDataTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdminEditDataTest.xml
index c0d659f1665a8..40132ea956584 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdminEditDataTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAdminEditDataTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleCartTest.xml
index 655081df61073..695c3a8bf7dbb 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleCartTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleCartTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductDetailsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductDetailsTest.xml
index a475ef16ed5c5..285503465a011 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductDetailsTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductDetailsTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductShownInCategoryListAndGrid.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductShownInCategoryListAndGrid.xml
index 577079965cabb..9ad4b6828d6e4 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductShownInCategoryListAndGrid.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundleProductShownInCategoryListAndGrid.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSelectAndSetBundleOptionsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSelectAndSetBundleOptionsTest.xml
index 26e5e436ed567..5e6e891541420 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSelectAndSetBundleOptionsTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSelectAndSetBundleOptionsTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontEditBundleProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontEditBundleProductTest.xml
index a50a73c7f6bb4..f94cd83f4e7d7 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontEditBundleProductTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontEditBundleProductTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml
index 6c476183a35b3..ccd6a58223b3c 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml
index 1b1a46d1c8ba4..31a5f9bab7758 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml
@@ -7,10 +7,11 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
+
diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
index c252e5f99612f..07d2e1b995cd1 100644
--- a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
@@ -280,6 +280,7 @@ public function testGetJsonConfigFixedPriceBundle()
$this->assertEquals(110, $jsonConfig['prices']['oldPrice']['amount']);
$this->assertEquals(100, $jsonConfig['prices']['basePrice']['amount']);
$this->assertEquals(100, $jsonConfig['prices']['finalPrice']['amount']);
+ $this->assertEquals([1], $jsonConfig['positions']);
}
/**
diff --git a/app/code/Magento/Bundle/Test/Unit/Model/ResourceModel/Selection/CollectionTest.php b/app/code/Magento/Bundle/Test/Unit/Model/ResourceModel/Selection/CollectionTest.php
deleted file mode 100644
index e595f9a47f060..0000000000000
--- a/app/code/Magento/Bundle/Test/Unit/Model/ResourceModel/Selection/CollectionTest.php
+++ /dev/null
@@ -1,156 +0,0 @@
-storeManager = $this->getMockBuilder(StoreManagerInterface::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->store = $this->getMockBuilder(StoreInterface::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->universalFactory = $this->getMockBuilder(UniversalFactory::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->entity = $this->getMockBuilder(AbstractEntity::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->adapter = $this->getMockBuilder(AdapterInterface::class)
- ->disableOriginalConstructor()
- ->getMock();
- $this->select = $this->getMockBuilder(Select::class)
- ->disableOriginalConstructor()
- ->getMock();
- $factory = $this->getMockBuilder(ProductLimitationFactory::class)
- ->disableOriginalConstructor()
- ->setMethods(['create'])
- ->getMock();
-
- $this->storeManager->expects($this->any())
- ->method('getStore')
- ->willReturn($this->store);
- $this->store->expects($this->any())
- ->method('getId')
- ->willReturn(1);
- $this->universalFactory->expects($this->any())
- ->method('create')
- ->willReturn($this->entity);
- $this->entity->expects($this->any())
- ->method('getConnection')
- ->willReturn($this->adapter);
- $this->entity->expects($this->any())
- ->method('getDefaultAttributes')
- ->willReturn([]);
- $this->adapter->expects($this->any())
- ->method('select')
- ->willReturn($this->select);
-
- $this->model = $objectManager->getObject(
- \Magento\Bundle\Model\ResourceModel\Selection\Collection::class,
- [
- 'storeManager' => $this->storeManager,
- 'universalFactory' => $this->universalFactory,
- 'productLimitationFactory' => $factory
- ]
- );
- }
-
- public function testAddQuantityFilter()
- {
- $statusTableName = 'cataloginventory_stock_status';
- $itemTableName = 'cataloginventory_stock_item';
- $this->entity->expects($this->exactly(2))
- ->method('getTable')
- ->willReturnMap([
- ['cataloginventory_stock_item', $itemTableName],
- ['cataloginventory_stock_status', $statusTableName],
- ]);
- $this->select->expects($this->exactly(2))
- ->method('joinInner')
- ->withConsecutive(
- [
- ['stock' => $statusTableName],
- 'selection.product_id = stock.product_id',
- [],
- ],
- [
- ['stock_item' => $itemTableName],
- 'selection.product_id = stock_item.product_id',
- [],
- ]
- )->willReturnSelf();
- $this->select
- ->expects($this->exactly(2))
- ->method('where')
- ->withConsecutive(
- [
- '('
- . 'selection.selection_can_change_qty > 0'
- . ' or '
- . 'selection.selection_qty <= stock.qty'
- . ' or '
- .'stock_item.manage_stock = 0'
- . ')',
- ],
- [
- 'stock.stock_status = 1',
- ]
- )->willReturnSelf();
-
- $this->assertEquals($this->model, $this->model->addQuantityFilter());
- }
-}
diff --git a/app/code/Magento/Bundle/etc/db_schema_whitelist.json b/app/code/Magento/Bundle/etc/db_schema_whitelist.json
index efb535d50caa3..2834d707cae0f 100644
--- a/app/code/Magento/Bundle/etc/db_schema_whitelist.json
+++ b/app/code/Magento/Bundle/etc/db_schema_whitelist.json
@@ -1,212 +1,212 @@
{
- "catalog_product_bundle_option": {
- "column": {
- "option_id": true,
- "parent_id": true,
- "required": true,
- "position": true,
- "type": true
- },
- "index": {
- "CATALOG_PRODUCT_BUNDLE_OPTION_PARENT_ID": true
- },
- "constraint": {
- "PRIMARY": true,
- "CAT_PRD_BNDL_OPT_PARENT_ID_CAT_PRD_ENTT_ENTT_ID": true
- }
- },
- "catalog_product_bundle_option_value": {
- "column": {
- "value_id": true,
- "option_id": true,
- "store_id": true,
- "title": true,
- "parent_product_id": true
- },
- "constraint": {
- "PRIMARY": true,
- "CAT_PRD_BNDL_OPT_VAL_OPT_ID_CAT_PRD_BNDL_OPT_OPT_ID": true,
- "CAT_PRD_BNDL_OPT_VAL_OPT_ID_PARENT_PRD_ID_STORE_ID": true,
- "CATALOG_PRODUCT_BUNDLE_OPTION_VALUE_OPTION_ID_STORE_ID": true
- }
- },
- "catalog_product_bundle_selection": {
- "column": {
- "selection_id": true,
- "option_id": true,
- "parent_product_id": true,
- "product_id": true,
- "position": true,
- "is_default": true,
- "selection_price_type": true,
- "selection_price_value": true,
- "selection_qty": true,
- "selection_can_change_qty": true
- },
- "index": {
- "CATALOG_PRODUCT_BUNDLE_SELECTION_OPTION_ID": true,
- "CATALOG_PRODUCT_BUNDLE_SELECTION_PRODUCT_ID": true
- },
- "constraint": {
- "PRIMARY": true,
- "CAT_PRD_BNDL_SELECTION_OPT_ID_CAT_PRD_BNDL_OPT_OPT_ID": true,
- "CAT_PRD_BNDL_SELECTION_PRD_ID_CAT_PRD_ENTT_ENTT_ID": true,
- "CAT_PRD_BNDL_SELECTION_PRD_ID_SEQUENCE_PRD_SEQUENCE_VAL": true
- }
- },
- "catalog_product_bundle_selection_price": {
- "column": {
- "selection_id": true,
- "website_id": true,
- "selection_price_type": true,
- "selection_price_value": true,
- "parent_product_id": true
- },
- "index": {
- "CATALOG_PRODUCT_BUNDLE_SELECTION_PRICE_WEBSITE_ID": true
- },
- "constraint": {
- "PRIMARY": true,
- "PK_CATALOG_PRODUCT_BUNDLE_SELECTION_PRICE": true,
- "CAT_PRD_BNDL_SELECTION_PRICE_WS_ID_STORE_WS_WS_ID": true,
- "FK_DCF37523AA05D770A70AA4ED7C2616E4": true,
- "DCF37523AA05D770A70AA4ED7C2616E4": true
- }
- },
- "catalog_product_bundle_price_index": {
- "column": {
- "entity_id": true,
- "website_id": true,
- "customer_group_id": true,
- "min_price": true,
- "max_price": true
- },
- "index": {
- "CATALOG_PRODUCT_BUNDLE_PRICE_INDEX_WEBSITE_ID": true,
- "CATALOG_PRODUCT_BUNDLE_PRICE_INDEX_CUSTOMER_GROUP_ID": true
- },
- "constraint": {
- "PRIMARY": true,
- "CAT_PRD_BNDL_PRICE_IDX_CSTR_GROUP_ID_CSTR_GROUP_CSTR_GROUP_ID": true,
- "CAT_PRD_BNDL_PRICE_IDX_ENTT_ID_CAT_PRD_ENTT_ENTT_ID": true,
- "CAT_PRD_BNDL_PRICE_IDX_WS_ID_STORE_WS_WS_ID": true,
- "CAT_PRD_BNDL_PRICE_IDX_ENTT_ID_SEQUENCE_PRD_SEQUENCE_VAL": true
- }
- },
- "catalog_product_bundle_stock_index": {
- "column": {
- "entity_id": true,
- "website_id": true,
- "stock_id": true,
- "option_id": true,
- "stock_status": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "catalog_product_index_price_bundle_idx": {
- "column": {
- "entity_id": true,
- "customer_group_id": true,
- "website_id": true,
- "tax_class_id": true,
- "price_type": true,
- "special_price": true,
- "tier_percent": true,
- "orig_price": true,
- "price": true,
- "min_price": true,
- "max_price": true,
- "tier_price": true,
- "base_tier": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "catalog_product_index_price_bundle_tmp": {
- "column": {
- "entity_id": true,
- "customer_group_id": true,
- "website_id": true,
- "tax_class_id": true,
- "price_type": true,
- "special_price": true,
- "tier_percent": true,
- "orig_price": true,
- "price": true,
- "min_price": true,
- "max_price": true,
- "tier_price": true,
- "base_tier": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "catalog_product_index_price_bundle_sel_idx": {
- "column": {
- "entity_id": true,
- "customer_group_id": true,
- "website_id": true,
- "option_id": true,
- "selection_id": true,
- "group_type": true,
- "is_required": true,
- "price": true,
- "tier_price": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "catalog_product_index_price_bundle_sel_tmp": {
- "column": {
- "entity_id": true,
- "customer_group_id": true,
- "website_id": true,
- "option_id": true,
- "selection_id": true,
- "group_type": true,
- "is_required": true,
- "price": true,
- "tier_price": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "catalog_product_index_price_bundle_opt_idx": {
- "column": {
- "entity_id": true,
- "customer_group_id": true,
- "website_id": true,
- "option_id": true,
- "min_price": true,
- "alt_price": true,
- "max_price": true,
- "tier_price": true,
- "alt_tier_price": true
- },
- "constraint": {
- "PRIMARY": true
- }
- },
- "catalog_product_index_price_bundle_opt_tmp": {
- "column": {
- "entity_id": true,
- "customer_group_id": true,
- "website_id": true,
- "option_id": true,
- "min_price": true,
- "alt_price": true,
- "max_price": true,
- "tier_price": true,
- "alt_tier_price": true
- },
- "constraint": {
- "PRIMARY": true
+ "catalog_product_bundle_option": {
+ "column": {
+ "option_id": true,
+ "parent_id": true,
+ "required": true,
+ "position": true,
+ "type": true
+ },
+ "index": {
+ "CATALOG_PRODUCT_BUNDLE_OPTION_PARENT_ID": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "CAT_PRD_BNDL_OPT_PARENT_ID_CAT_PRD_ENTT_ENTT_ID": true
+ }
+ },
+ "catalog_product_bundle_option_value": {
+ "column": {
+ "value_id": true,
+ "option_id": true,
+ "store_id": true,
+ "title": true,
+ "parent_product_id": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "CAT_PRD_BNDL_OPT_VAL_OPT_ID_CAT_PRD_BNDL_OPT_OPT_ID": true,
+ "CAT_PRD_BNDL_OPT_VAL_OPT_ID_PARENT_PRD_ID_STORE_ID": true,
+ "CATALOG_PRODUCT_BUNDLE_OPTION_VALUE_OPTION_ID_STORE_ID": true
+ }
+ },
+ "catalog_product_bundle_selection": {
+ "column": {
+ "selection_id": true,
+ "option_id": true,
+ "parent_product_id": true,
+ "product_id": true,
+ "position": true,
+ "is_default": true,
+ "selection_price_type": true,
+ "selection_price_value": true,
+ "selection_qty": true,
+ "selection_can_change_qty": true
+ },
+ "index": {
+ "CATALOG_PRODUCT_BUNDLE_SELECTION_OPTION_ID": true,
+ "CATALOG_PRODUCT_BUNDLE_SELECTION_PRODUCT_ID": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "CAT_PRD_BNDL_SELECTION_OPT_ID_CAT_PRD_BNDL_OPT_OPT_ID": true,
+ "CAT_PRD_BNDL_SELECTION_PRD_ID_CAT_PRD_ENTT_ENTT_ID": true,
+ "CAT_PRD_BNDL_SELECTION_PRD_ID_SEQUENCE_PRD_SEQUENCE_VAL": true
+ }
+ },
+ "catalog_product_bundle_selection_price": {
+ "column": {
+ "selection_id": true,
+ "website_id": true,
+ "selection_price_type": true,
+ "selection_price_value": true,
+ "parent_product_id": true
+ },
+ "index": {
+ "CATALOG_PRODUCT_BUNDLE_SELECTION_PRICE_WEBSITE_ID": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "PK_CATALOG_PRODUCT_BUNDLE_SELECTION_PRICE": true,
+ "CAT_PRD_BNDL_SELECTION_PRICE_WS_ID_STORE_WS_WS_ID": true,
+ "FK_DCF37523AA05D770A70AA4ED7C2616E4": true,
+ "DCF37523AA05D770A70AA4ED7C2616E4": true
+ }
+ },
+ "catalog_product_bundle_price_index": {
+ "column": {
+ "entity_id": true,
+ "website_id": true,
+ "customer_group_id": true,
+ "min_price": true,
+ "max_price": true
+ },
+ "index": {
+ "CATALOG_PRODUCT_BUNDLE_PRICE_INDEX_WEBSITE_ID": true,
+ "CATALOG_PRODUCT_BUNDLE_PRICE_INDEX_CUSTOMER_GROUP_ID": true
+ },
+ "constraint": {
+ "PRIMARY": true,
+ "CAT_PRD_BNDL_PRICE_IDX_CSTR_GROUP_ID_CSTR_GROUP_CSTR_GROUP_ID": true,
+ "CAT_PRD_BNDL_PRICE_IDX_ENTT_ID_CAT_PRD_ENTT_ENTT_ID": true,
+ "CAT_PRD_BNDL_PRICE_IDX_WS_ID_STORE_WS_WS_ID": true,
+ "CAT_PRD_BNDL_PRICE_IDX_ENTT_ID_SEQUENCE_PRD_SEQUENCE_VAL": true
+ }
+ },
+ "catalog_product_bundle_stock_index": {
+ "column": {
+ "entity_id": true,
+ "website_id": true,
+ "stock_id": true,
+ "option_id": true,
+ "stock_status": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
+ },
+ "catalog_product_index_price_bundle_idx": {
+ "column": {
+ "entity_id": true,
+ "customer_group_id": true,
+ "website_id": true,
+ "tax_class_id": true,
+ "price_type": true,
+ "special_price": true,
+ "tier_percent": true,
+ "orig_price": true,
+ "price": true,
+ "min_price": true,
+ "max_price": true,
+ "tier_price": true,
+ "base_tier": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
+ },
+ "catalog_product_index_price_bundle_tmp": {
+ "column": {
+ "entity_id": true,
+ "customer_group_id": true,
+ "website_id": true,
+ "tax_class_id": true,
+ "price_type": true,
+ "special_price": true,
+ "tier_percent": true,
+ "orig_price": true,
+ "price": true,
+ "min_price": true,
+ "max_price": true,
+ "tier_price": true,
+ "base_tier": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
+ },
+ "catalog_product_index_price_bundle_sel_idx": {
+ "column": {
+ "entity_id": true,
+ "customer_group_id": true,
+ "website_id": true,
+ "option_id": true,
+ "selection_id": true,
+ "group_type": true,
+ "is_required": true,
+ "price": true,
+ "tier_price": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
+ },
+ "catalog_product_index_price_bundle_sel_tmp": {
+ "column": {
+ "entity_id": true,
+ "customer_group_id": true,
+ "website_id": true,
+ "option_id": true,
+ "selection_id": true,
+ "group_type": true,
+ "is_required": true,
+ "price": true,
+ "tier_price": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
+ },
+ "catalog_product_index_price_bundle_opt_idx": {
+ "column": {
+ "entity_id": true,
+ "customer_group_id": true,
+ "website_id": true,
+ "option_id": true,
+ "min_price": true,
+ "alt_price": true,
+ "max_price": true,
+ "tier_price": true,
+ "alt_tier_price": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
+ },
+ "catalog_product_index_price_bundle_opt_tmp": {
+ "column": {
+ "entity_id": true,
+ "customer_group_id": true,
+ "website_id": true,
+ "option_id": true,
+ "min_price": true,
+ "alt_price": true,
+ "max_price": true,
+ "tier_price": true,
+ "alt_tier_price": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
}
- }
}
\ No newline at end of file
diff --git a/app/code/Magento/Bundle/view/frontend/web/js/product-summary.js b/app/code/Magento/Bundle/view/frontend/web/js/product-summary.js
index d8d4cb1e99b7f..1e7fe6b6673d6 100644
--- a/app/code/Magento/Bundle/view/frontend/web/js/product-summary.js
+++ b/app/code/Magento/Bundle/view/frontend/web/js/product-summary.js
@@ -56,8 +56,9 @@ define([
// Clear Summary box
this.element.html('');
-
- $.each(this.cache.currentElement.selected, $.proxy(this._renderOption, this));
+ this.cache.currentElement.positions.forEach(function (optionId) {
+ this._renderOption(optionId, this.cache.currentElement.selected[optionId]);
+ }, this);
this.element
.parents(this.options.bundleSummaryContainer)
.toggleClass('empty', !this.cache.currentElementCount); // Zero elements equal '.empty' container
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItemLinks.php b/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItemLinks.php
index f90945d19f948..f55028a7d1a5b 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItemLinks.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItemLinks.php
@@ -7,15 +7,15 @@
namespace Magento\BundleGraphQl\Model\Resolver;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\BundleGraphQl\Model\Resolver\Links\Collection;
use Magento\Framework\GraphQl\Config\Element\Field;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
class BundleItemLinks implements ResolverInterface
{
@@ -42,16 +42,14 @@ public function __construct(
}
/**
- * {@inheritDoc}
+ * @inheritdoc
*/
- public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value
+ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
if (!isset($value['option_id']) || !isset($value['parent_id'])) {
- $result = function () {
- return null;
- };
- return $this->valueFactory->create($result);
+ throw new GraphQlInputException(__('"option_id" and "parent_id" values should be specified'));
}
+
$this->linkCollection->addIdFilters((int)$value['option_id'], (int)$value['parent_id']);
$result = function () use ($value) {
return $this->linkCollection->getLinksForOptionId((int)$value['option_id']);
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItems.php b/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItems.php
index 9474f825fe5e8..b67bd69ecf924 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItems.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/BundleItems.php
@@ -13,12 +13,11 @@
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\GraphQl\Config\Element\Field;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
class BundleItems implements ResolverInterface
{
@@ -35,21 +34,21 @@ class BundleItems implements ResolverInterface
/**
* @var MetadataPool
*/
- private $metdataPool;
+ private $metadataPool;
/**
* @param Collection $bundleOptionCollection
* @param ValueFactory $valueFactory
- * @param MetadataPool $metdataPool
+ * @param MetadataPool $metadataPool
*/
public function __construct(
Collection $bundleOptionCollection,
ValueFactory $valueFactory,
- MetadataPool $metdataPool
+ MetadataPool $metadataPool
) {
$this->bundleOptionCollection = $bundleOptionCollection;
$this->valueFactory = $valueFactory;
- $this->metdataPool = $metdataPool;
+ $this->metadataPool = $metadataPool;
}
/**
@@ -57,9 +56,9 @@ public function __construct(
*
* {@inheritDoc}
*/
- public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value
+ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
- $linkField = $this->metdataPool->getMetadata(ProductInterface::class)->getLinkField();
+ $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
if ($value['type_id'] !== Type::TYPE_CODE
|| !isset($value[$linkField])
|| !isset($value[ProductInterface::SKU])
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/Options/Label.php b/app/code/Magento/BundleGraphQl/Model/Resolver/Options/Label.php
index a4757108ee5a4..bcddd5d084629 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/Options/Label.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/Options/Label.php
@@ -7,10 +7,10 @@
namespace Magento\BundleGraphQl\Model\Resolver\Options;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
-use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\Product;
+use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\Deferred\Product as ProductDataProvider;
use Magento\Framework\GraphQl\Config\Element\Field;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
@@ -19,29 +19,28 @@
*/
class Label implements ResolverInterface
{
-
/**
* @var ValueFactory
*/
private $valueFactory;
/**
- * @var Product
+ * @var ProductDataProvider
*/
private $product;
/**
* @param ValueFactory $valueFactory
- * @param Product $product
+ * @param ProductDataProvider $product
*/
- public function __construct(ValueFactory $valueFactory, Product $product)
+ public function __construct(ValueFactory $valueFactory, ProductDataProvider $product)
{
$this->valueFactory = $valueFactory;
$this->product = $product;
}
/**
- * @inheritDoc
+ * @inheritdoc
*/
public function resolve(
Field $field,
@@ -49,12 +48,9 @@ public function resolve(
ResolveInfo $info,
array $value = null,
array $args = null
- ): Value {
+ ) {
if (!isset($value['sku'])) {
- $result = function () {
- return null;
- };
- return $this->valueFactory->create($result);
+ throw new GraphQlInputException(__('"sku" value should be specified'));
}
$this->product->addProductSku($value['sku']);
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicPrice.php b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicPrice.php
index e8dc3decc2adf..978e1c455fc0a 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicPrice.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicPrice.php
@@ -5,36 +5,20 @@
*/
declare(strict_types=1);
-
namespace Magento\BundleGraphQl\Model\Resolver\Product\Fields;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Bundle\Model\Product\Type as Bundle;
use Magento\Framework\GraphQl\Config\Element\Field;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
-use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
class DynamicPrice implements ResolverInterface
{
/**
- * @var ValueFactory
- */
- private $valueFactory;
-
- /**
- * @param ValueFactory $valueFactory
- */
- public function __construct(ValueFactory $valueFactory)
- {
- $this->valueFactory = $valueFactory;
- }
-
- /**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function resolve(
Field $field,
@@ -42,16 +26,12 @@ public function resolve(
ResolveInfo $info,
array $value = null,
array $args = null
- ): Value {
+ ) {
$result = null;
if ($value['type_id'] === Bundle::TYPE_CODE) {
$result = isset($value['price_type']) ? !$value['price_type'] : null;
}
- return $this->valueFactory->create(
- function () use ($result) {
- return $result;
- }
- );
+ return $result;
}
}
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicSku.php b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicSku.php
index 37e1557d36df1..73f84c278a634 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicSku.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicSku.php
@@ -5,36 +5,20 @@
*/
declare(strict_types=1);
-
namespace Magento\BundleGraphQl\Model\Resolver\Product\Fields;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Bundle\Model\Product\Type as Bundle;
use Magento\Framework\GraphQl\Config\Element\Field;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
-use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
class DynamicSku implements ResolverInterface
{
/**
- * @var ValueFactory
- */
- private $valueFactory;
-
- /**
- * @param ValueFactory $valueFactory
- */
- public function __construct(ValueFactory $valueFactory)
- {
- $this->valueFactory = $valueFactory;
- }
-
- /**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function resolve(
Field $field,
@@ -42,18 +26,12 @@ public function resolve(
ResolveInfo $info,
array $value = null,
array $args = null
- ): Value {
- $result = function () {
- return null;
- };
+ ) {
+ $result = null;
if ($value['type_id'] === Bundle::TYPE_CODE) {
$result = isset($value['sku_type']) ? !$value['sku_type'] : null;
}
- return $this->valueFactory->create(
- function () use ($result) {
- return $result;
- }
- );
+ return $result;
}
}
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicWeight.php b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicWeight.php
index 5f79bba449e54..a4bb8ef64fc98 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicWeight.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/DynamicWeight.php
@@ -5,36 +5,20 @@
*/
declare(strict_types=1);
-
namespace Magento\BundleGraphQl\Model\Resolver\Product\Fields;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Bundle\Model\Product\Type as Bundle;
use Magento\Framework\GraphQl\Config\Element\Field;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
-use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
class DynamicWeight implements ResolverInterface
{
/**
- * @var ValueFactory
- */
- private $valueFactory;
-
- /**
- * @param ValueFactory $valueFactory
- */
- public function __construct(ValueFactory $valueFactory)
- {
- $this->valueFactory = $valueFactory;
- }
-
- /**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function resolve(
Field $field,
@@ -42,18 +26,12 @@ public function resolve(
ResolveInfo $info,
array $value = null,
array $args = null
- ): Value {
- $result = function () {
- return null;
- };
+ ) {
+ $result = null;
if ($value['type_id'] === Bundle::TYPE_CODE) {
$result = isset($value['weight_type']) ? !$value['weight_type'] : null;
}
- return $this->valueFactory->create(
- function () use ($result) {
- return $result;
- }
- );
+ return $result;
}
}
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/PriceView.php b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/PriceView.php
index ef8e93748c73f..b7351b09d437e 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/PriceView.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/PriceView.php
@@ -5,19 +5,16 @@
*/
declare(strict_types=1);
-
namespace Magento\BundleGraphQl\Model\Resolver\Product\Fields;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Bundle\Model\Product\Type as Bundle;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\EnumLookup;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
-use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
class PriceView implements ResolverInterface
{
@@ -26,23 +23,16 @@ class PriceView implements ResolverInterface
*/
private $enumLookup;
- /**
- * @var ValueFactory
- */
- private $valueFactory;
-
/**
* @param EnumLookup $enumLookup
- * @param ValueFactory $valueFactory
*/
- public function __construct(EnumLookup $enumLookup, ValueFactory $valueFactory)
+ public function __construct(EnumLookup $enumLookup)
{
$this->enumLookup = $enumLookup;
- $this->valueFactory = $valueFactory;
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function resolve(
Field $field,
@@ -50,19 +40,13 @@ public function resolve(
ResolveInfo $info,
array $value = null,
array $args = null
- ): Value {
- $result = function () {
- return null;
- };
+ ) {
+ $result = null;
if ($value['type_id'] === Bundle::TYPE_CODE) {
$result = isset($value['price_view'])
? $this->enumLookup->getEnumValueFromField('PriceViewEnum', $value['price_view']) : null;
}
- return $this->valueFactory->create(
- function () use ($result) {
- return $result;
- }
- );
+ return $result;
}
}
diff --git a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/ShipBundleItems.php b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/ShipBundleItems.php
index e2bd12a84e2b4..6babf6520e10e 100644
--- a/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/ShipBundleItems.php
+++ b/app/code/Magento/BundleGraphQl/Model/Resolver/Product/Fields/ShipBundleItems.php
@@ -5,19 +5,16 @@
*/
declare(strict_types=1);
-
namespace Magento\BundleGraphQl\Model\Resolver\Product\Fields;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Bundle\Model\Product\Type as Bundle;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\EnumLookup;
-use Magento\Framework\GraphQl\Query\Resolver\Value;
-use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
use Magento\Framework\GraphQl\Query\ResolverInterface;
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
class ShipBundleItems implements ResolverInterface
{
@@ -26,23 +23,16 @@ class ShipBundleItems implements ResolverInterface
*/
private $enumLookup;
- /**
- * @var ValueFactory
- */
- private $valueFactory;
-
/**
* @param EnumLookup $enumLookup
- * @param ValueFactory $valueFactory
*/
- public function __construct(EnumLookup $enumLookup, ValueFactory $valueFactory)
+ public function __construct(EnumLookup $enumLookup)
{
$this->enumLookup = $enumLookup;
- $this->valueFactory = $valueFactory;
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function resolve(
Field $field,
@@ -50,19 +40,10 @@ public function resolve(
ResolveInfo $info,
array $value = null,
array $args = null
- ): Value {
- $result = function () {
- return null;
- };
- if ($value['type_id'] === Bundle::TYPE_CODE) {
- $result = isset($value['shipment_type'])
- ? $this->enumLookup->getEnumValueFromField('ShipBundleItemsEnum', $value['shipment_type']) : null;
- }
+ ) {
+ $result = isset($value['shipment_type']) && $value['type_id'] === Bundle::TYPE_CODE
+ ? $this->enumLookup->getEnumValueFromField('ShipBundleItemsEnum', $value['shipment_type']) : null;
- return $this->valueFactory->create(
- function () use ($result) {
- return $result;
- }
- );
+ return $result;
}
}
diff --git a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php
index e0c94097e4d3f..2cefc60a42976 100644
--- a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php
+++ b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php
@@ -322,7 +322,7 @@ function ($title, $storeName) {
*/
protected function getTypeValue($type)
{
- return isset($this->typeMapping[$type]) ? $this->typeMapping[$type] : self::VALUE_DYNAMIC;
+ return $this->typeMapping[$type] ?? self::VALUE_DYNAMIC;
}
/**
@@ -333,7 +333,7 @@ protected function getTypeValue($type)
*/
protected function getPriceViewValue($type)
{
- return isset($this->priceViewMapping[$type]) ? $this->priceViewMapping[$type] : self::VALUE_PRICE_RANGE;
+ return $this->priceViewMapping[$type] ?? self::VALUE_PRICE_RANGE;
}
/**
@@ -344,7 +344,7 @@ protected function getPriceViewValue($type)
*/
protected function getPriceTypeValue($type)
{
- return isset($this->priceTypeMapping[$type]) ? $this->priceTypeMapping[$type] : null;
+ return $this->priceTypeMapping[$type] ?? null;
}
/**
@@ -355,7 +355,7 @@ protected function getPriceTypeValue($type)
*/
private function getShipmentTypeValue($type)
{
- return isset($this->shipmentTypeMapping[$type]) ? $this->shipmentTypeMapping[$type] : null;
+ return $this->shipmentTypeMapping[$type] ?? null;
}
/**
diff --git a/app/code/Magento/Captcha/Controller/Refresh/Index.php b/app/code/Magento/Captcha/Controller/Refresh/Index.php
index e89a80646ed8e..e401e03e9551f 100644
--- a/app/code/Magento/Captcha/Controller/Refresh/Index.php
+++ b/app/code/Magento/Captcha/Controller/Refresh/Index.php
@@ -8,9 +8,10 @@
*/
namespace Magento\Captcha\Controller\Refresh;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\App\Action\Context;
-class Index extends \Magento\Framework\App\Action\Action
+class Index extends \Magento\Framework\App\Action\Action implements HttpPostActionInterface
{
/**
* @var \Magento\Captcha\Helper\Data
diff --git a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php
index e496c36f4de75..91f3a785df36b 100644
--- a/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php
+++ b/app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Captcha\Model\Customer\Plugin;
use Magento\Captcha\Helper\Data as CaptchaHelper;
@@ -81,27 +82,37 @@ public function aroundExecute(
if ($content) {
$loginParams = $this->serializer->unserialize($content);
}
- $username = isset($loginParams['username']) ? $loginParams['username'] : null;
- $captchaString = isset($loginParams[$captchaInputName]) ? $loginParams[$captchaInputName] : null;
- $loginFormId = isset($loginParams[$captchaFormIdField]) ? $loginParams[$captchaFormIdField] : null;
+ $username = $loginParams['username'] ?? null;
+ $captchaString = $loginParams[$captchaInputName] ?? null;
+ $loginFormId = $loginParams[$captchaFormIdField] ?? null;
- foreach ($this->formIds as $formId) {
- $captchaModel = $this->helper->getCaptcha($formId);
- if ($captchaModel->isRequired($username) && !in_array($loginFormId, $this->formIds)) {
- $resultJson = $this->resultJsonFactory->create();
- return $resultJson->setData(['errors' => true, 'message' => __('Provided form does not exist')]);
- }
+ if (!in_array($loginFormId, $this->formIds) && $this->helper->getCaptcha($loginFormId)->isRequired($username)) {
+ return $this->returnJsonError(__('Provided form does not exist'));
+ }
- if ($formId == $loginFormId) {
- $captchaModel->logAttempt($username);
- if (!$captchaModel->isCorrect($captchaString)) {
- $this->sessionManager->setUsername($username);
- /** @var \Magento\Framework\Controller\Result\Json $resultJson */
- $resultJson = $this->resultJsonFactory->create();
- return $resultJson->setData(['errors' => true, 'message' => __('Incorrect CAPTCHA')]);
+ foreach ($this->formIds as $formId) {
+ if ($formId === $loginFormId) {
+ $captchaModel = $this->helper->getCaptcha($formId);
+ if ($captchaModel->isRequired($username)) {
+ $captchaModel->logAttempt($username);
+ if (!$captchaModel->isCorrect($captchaString)) {
+ $this->sessionManager->setUsername($username);
+ return $this->returnJsonError(__('Incorrect CAPTCHA'));
+ }
}
}
}
return $proceed();
}
+
+ /**
+ *
+ * @param \Magento\Framework\Phrase $phrase
+ * @return \Magento\Framework\Controller\Result\Json
+ */
+ private function returnJsonError(\Magento\Framework\Phrase $phrase): \Magento\Framework\Controller\Result\Json
+ {
+ $resultJson = $this->resultJsonFactory->create();
+ return $resultJson->setData(['errors' => true, 'message' => $phrase]);
+ }
}
diff --git a/app/code/Magento/Captcha/Model/DefaultModel.php b/app/code/Magento/Captcha/Model/DefaultModel.php
index e5c72ba1ae82e..cf6690df5c85d 100644
--- a/app/code/Magento/Captcha/Model/DefaultModel.php
+++ b/app/code/Magento/Captcha/Model/DefaultModel.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Captcha\Model;
+use Magento\Captcha\Helper\Data;
+
/**
* Implementation of \Zend\Captcha\Image
*
@@ -29,7 +31,7 @@ class DefaultModel extends \Zend\Captcha\Image implements \Magento\Captcha\Model
const DEFAULT_WORD_LENGTH_TO = 5;
/**
- * @var \Magento\Captcha\Helper\Data
+ * @var Data
* @since 100.2.0
*/
protected $captchaData;
@@ -125,8 +127,8 @@ public function getBlockName()
*/
public function isRequired($login = null)
{
- if ($this->isUserAuth()
- && !$this->isShownToLoggedInUser()
+ if (($this->isUserAuth()
+ && !$this->isShownToLoggedInUser())
|| !$this->isEnabled()
|| !in_array(
$this->formId,
@@ -431,12 +433,14 @@ public function getWordLen()
*/
private function isShowAlways()
{
- if ((string)$this->captchaData->getConfig('mode') == \Magento\Captcha\Helper\Data::MODE_ALWAYS) {
+ $captchaMode = (string)$this->captchaData->getConfig('mode');
+
+ if ($captchaMode === Data::MODE_ALWAYS) {
return true;
}
- if ((string)$this->captchaData->getConfig('mode') == \Magento\Captcha\Helper\Data::MODE_AFTER_FAIL
- && $this->getAllowedAttemptsForSameLogin() == 0
+ if ($captchaMode === Data::MODE_AFTER_FAIL
+ && $this->getAllowedAttemptsForSameLogin() === 0
) {
return true;
}
diff --git a/app/code/Magento/Captcha/Observer/CaptchaStringResolver.php b/app/code/Magento/Captcha/Observer/CaptchaStringResolver.php
index 9b97225e60de9..39579616fa928 100644
--- a/app/code/Magento/Captcha/Observer/CaptchaStringResolver.php
+++ b/app/code/Magento/Captcha/Observer/CaptchaStringResolver.php
@@ -18,6 +18,6 @@ public function resolve(\Magento\Framework\App\RequestInterface $request, $formI
{
$captchaParams = $request->getPost(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE);
- return isset($captchaParams[$formId]) ? $captchaParams[$formId] : '';
+ return $captchaParams[$formId] ?? '';
}
}
diff --git a/app/code/Magento/Captcha/Observer/CheckGuestCheckoutObserver.php b/app/code/Magento/Captcha/Observer/CheckGuestCheckoutObserver.php
deleted file mode 100644
index 7ccaa76b6c7c8..0000000000000
--- a/app/code/Magento/Captcha/Observer/CheckGuestCheckoutObserver.php
+++ /dev/null
@@ -1,82 +0,0 @@
-_helper = $helper;
- $this->_actionFlag = $actionFlag;
- $this->captchaStringResolver = $captchaStringResolver;
- $this->_typeOnepage = $typeOnepage;
- $this->jsonHelper = $jsonHelper;
- }
-
- /**
- * Check Captcha On Checkout as Guest Page
- *
- * @param \Magento\Framework\Event\Observer $observer
- * @return $this
- */
- public function execute(\Magento\Framework\Event\Observer $observer)
- {
- $formId = 'guest_checkout';
- $captchaModel = $this->_helper->getCaptcha($formId);
- $checkoutMethod = $this->_typeOnepage->getQuote()->getCheckoutMethod();
- if ($checkoutMethod == \Magento\Checkout\Model\Type\Onepage::METHOD_GUEST
- && $captchaModel->isRequired()
- ) {
- $controller = $observer->getControllerAction();
- if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId))) {
- $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
- $result = ['error' => 1, 'message' => __('Incorrect CAPTCHA')];
- $controller->getResponse()->representJson($this->jsonHelper->jsonEncode($result));
- }
- }
-
- return $this;
- }
-}
diff --git a/app/code/Magento/Captcha/Observer/CheckRegisterCheckoutObserver.php b/app/code/Magento/Captcha/Observer/CheckRegisterCheckoutObserver.php
deleted file mode 100644
index 8e110a9f4653d..0000000000000
--- a/app/code/Magento/Captcha/Observer/CheckRegisterCheckoutObserver.php
+++ /dev/null
@@ -1,82 +0,0 @@
-_helper = $helper;
- $this->_actionFlag = $actionFlag;
- $this->captchaStringResolver = $captchaStringResolver;
- $this->_typeOnepage = $typeOnepage;
- $this->jsonHelper = $jsonHelper;
- }
-
- /**
- * Check Captcha On Checkout Register Page
- *
- * @param \Magento\Framework\Event\Observer $observer
- * @return $this
- */
- public function execute(\Magento\Framework\Event\Observer $observer)
- {
- $formId = 'register_during_checkout';
- $captchaModel = $this->_helper->getCaptcha($formId);
- $checkoutMethod = $this->_typeOnepage->getQuote()->getCheckoutMethod();
- if ($checkoutMethod == \Magento\Checkout\Model\Type\Onepage::METHOD_REGISTER
- && $captchaModel->isRequired()
- ) {
- $controller = $observer->getControllerAction();
- if (!$captchaModel->isCorrect($this->captchaStringResolver->resolve($controller->getRequest(), $formId))) {
- $this->_actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
- $result = ['error' => 1, 'message' => __('Incorrect CAPTCHA')];
- $controller->getResponse()->representJson($this->jsonHelper->jsonEncode($result));
- }
- }
-
- return $this;
- }
-}
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml
new file mode 100644
index 0000000000000..71a876bbbcdbf
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaFormsDisplayingData.xml b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaFormsDisplayingData.xml
new file mode 100644
index 0000000000000..9db8110c0f64b
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaFormsDisplayingData.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ Create user
+ Login
+ Forgot password
+ Contact Us
+ Change password
+ Register during Checkout
+ Check Out as Guest
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/CaptchaFormsDisplayingSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/CaptchaFormsDisplayingSection.xml
new file mode 100644
index 0000000000000..4c974e6fced05
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/CaptchaFormsDisplayingSection.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/CaptchaFormsDisplayingTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/CaptchaFormsDisplayingTest.xml
new file mode 100644
index 0000000000000..8f764899706ac
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/CaptchaFormsDisplayingTest.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{CaptchaData.checkoutAsGuest}}
+ $formItems
+
+
+ {{CaptchaData.register}}
+ $formItems
+
+
+
+
+ {{CaptchaData.createUser}}
+ $createUser
+
+
+
+ {{CaptchaData.login}}
+ login
+
+
+
+ {{CaptchaData.passwd}}
+ $forgotpassword
+
+
+
+ {{CaptchaData.contactUs}}
+ $contactUs
+
+
+
+ {{CaptchaData.changePasswd}}
+ $userEdit
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php
index be9574fff2cfa..ec2a49f3fc566 100644
--- a/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php
+++ b/app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php
@@ -3,22 +3,23 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Captcha\Test\Unit\Model\Customer\Plugin;
class AjaxLoginTest extends \PHPUnit\Framework\TestCase
{
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Checkout\Model\Session
*/
protected $sessionManagerMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Captcha\Helper\Data
*/
protected $captchaHelperMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Controller\Result\JsonFactory
*/
protected $jsonFactoryMock;
@@ -38,12 +39,12 @@ class AjaxLoginTest extends \PHPUnit\Framework\TestCase
protected $requestMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Customer\Controller\Ajax\Login
*/
protected $loginControllerMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Serialize\Serializer\Json
*/
protected $serializerMock;
@@ -57,6 +58,9 @@ class AjaxLoginTest extends \PHPUnit\Framework\TestCase
*/
protected $model;
+ /**
+ * @inheritdoc
+ */
protected function setUp()
{
$this->sessionManagerMock = $this->createPartialMock(\Magento\Checkout\Model\Session::class, ['setUsername']);
@@ -72,8 +76,12 @@ protected function setUp()
$this->loginControllerMock->expects($this->any())->method('getRequest')
->will($this->returnValue($this->requestMock));
- $this->captchaHelperMock->expects($this->once())->method('getCaptcha')
- ->with('user_login')->will($this->returnValue($this->captchaMock));
+
+ $this->captchaHelperMock
+ ->expects($this->exactly(1))
+ ->method('getCaptcha')
+ ->will($this->returnValue($this->captchaMock));
+
$this->formIds = ['user_login'];
$this->serializerMock = $this->createMock(\Magento\Framework\Serialize\Serializer\Json::class);
@@ -86,6 +94,9 @@ protected function setUp()
);
}
+ /**
+ * Test aroundExecute.
+ */
public function testAroundExecute()
{
$username = 'name';
@@ -103,14 +114,24 @@ public function testAroundExecute()
$this->captchaMock->expects($this->once())->method('logAttempt')->with($username);
$this->captchaMock->expects($this->once())->method('isCorrect')->with($captchaString)
->will($this->returnValue(true));
- $this->serializerMock->expects(($this->once()))->method('unserialize')->will($this->returnValue($requestData));
+ $this->serializerMock->expects($this->once())->method('unserialize')->will($this->returnValue($requestData));
$closure = function () {
return 'result';
};
+
+ $this->captchaHelperMock
+ ->expects($this->exactly(1))
+ ->method('getCaptcha')
+ ->with('user_login')
+ ->will($this->returnValue($this->captchaMock));
+
$this->assertEquals('result', $this->model->aroundExecute($this->loginControllerMock, $closure));
}
+ /**
+ * Test aroundExecuteIncorrectCaptcha.
+ */
public function testAroundExecuteIncorrectCaptcha()
{
$username = 'name';
@@ -128,18 +149,21 @@ public function testAroundExecuteIncorrectCaptcha()
$this->captchaMock->expects($this->once())->method('logAttempt')->with($username);
$this->captchaMock->expects($this->once())->method('isCorrect')
->with($captchaString)->will($this->returnValue(false));
- $this->serializerMock->expects(($this->once()))->method('unserialize')->will($this->returnValue($requestData));
+ $this->serializerMock->expects($this->once())->method('unserialize')->will($this->returnValue($requestData));
$this->sessionManagerMock->expects($this->once())->method('setUsername')->with($username);
$this->jsonFactoryMock->expects($this->once())->method('create')
->will($this->returnValue($this->resultJsonMock));
- $this->resultJsonMock->expects($this->once())->method('setData')
- ->with(['errors' => true, 'message' => __('Incorrect CAPTCHA')])->will($this->returnValue('response'));
+ $this->resultJsonMock
+ ->expects($this->once())
+ ->method('setData')
+ ->with(['errors' => true, 'message' => __('Incorrect CAPTCHA')])
+ ->will($this->returnSelf());
$closure = function () {
};
- $this->assertEquals('response', $this->model->aroundExecute($this->loginControllerMock, $closure));
+ $this->assertEquals($this->resultJsonMock, $this->model->aroundExecute($this->loginControllerMock, $closure));
}
/**
@@ -151,7 +175,7 @@ public function testAroundExecuteCaptchaIsNotRequired($username, $requestContent
{
$this->requestMock->expects($this->once())->method('getContent')
->will($this->returnValue(json_encode($requestContent)));
- $this->serializerMock->expects(($this->once()))->method('unserialize')
+ $this->serializerMock->expects($this->once())->method('unserialize')
->will($this->returnValue($requestContent));
$this->captchaMock->expects($this->once())->method('isRequired')->with($username)
@@ -168,16 +192,39 @@ public function testAroundExecuteCaptchaIsNotRequired($username, $requestContent
/**
* @return array
*/
- public function aroundExecuteCaptchaIsNotRequired()
+ public function aroundExecuteCaptchaIsNotRequired(): array
{
return [
[
'username' => 'name',
'requestData' => ['username' => 'name', 'captcha_string' => 'string'],
],
+ [
+ 'username' => 'name',
+ 'requestData' =>
+ [
+ 'username' => 'name',
+ 'captcha_string' => 'string',
+ 'captcha_form_id' => $this->formIds[0]
+ ],
+ ],
[
'username' => null,
- 'requestData' => ['captcha_string' => 'string'],
+ 'requestData' =>
+ [
+ 'username' => null,
+ 'captcha_string' => 'string',
+ 'captcha_form_id' => $this->formIds[0]
+ ],
+ ],
+ [
+ 'username' => 'name',
+ 'requestData' =>
+ [
+ 'username' => 'name',
+ 'captcha_string' => 'string',
+ 'captcha_form_id' => null
+ ],
],
];
}
diff --git a/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php b/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php
index 0500b29f787c2..1edbcc029e4ce 100644
--- a/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php
+++ b/app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php
@@ -24,7 +24,7 @@ class DefaultTest extends \PHPUnit\Framework\TestCase
'enable' => '1',
'font' => 'linlibertine',
'mode' => 'after_fail',
- 'forms' => 'user_forgotpassword,user_create,guest_checkout,register_during_checkout',
+ 'forms' => 'user_forgotpassword,user_create',
'failed_attempts_login' => '3',
'failed_attempts_ip' => '1000',
'timeout' => '7',
@@ -35,8 +35,6 @@ class DefaultTest extends \PHPUnit\Framework\TestCase
'always_for' => [
'user_create',
'user_forgotpassword',
- 'guest_checkout',
- 'register_during_checkout',
'contact_us',
],
];
@@ -362,8 +360,7 @@ public function isShownToLoggedInUserDataProvider()
return [
[true, 'contact_us'],
[false, 'user_create'],
- [false, 'user_forgotpassword'],
- [false, 'guest_checkout']
+ [false, 'user_forgotpassword']
];
}
}
diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckGuestCheckoutObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckGuestCheckoutObserverTest.php
deleted file mode 100644
index d3f29fae8a592..0000000000000
--- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckGuestCheckoutObserverTest.php
+++ /dev/null
@@ -1,211 +0,0 @@
-createMock(Onepage::class);
- $captchaHelperMock = $this->createMock(CaptchaDataHelper::class);
- $this->objectManager = new ObjectManager($this);
- $this->actionFlagMock = $this->createMock(ActionFlag::class);
- $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class);
- $this->captchaModelMock = $this->createMock(CaptchaModel::class);
- $this->quoteModelMock = $this->createMock(Quote::class);
- $this->controllerMock = $this->createMock(Action::class);
- $this->requestMock = $this->createMock(Http::class);
- $this->responseMock = $this->createMock(HttpResponse::class);
- $this->observer = new Observer(['controller_action' => $this->controllerMock]);
- $this->jsonHelperMock = $this->createMock(JsonHelper::class);
-
- $this->checkGuestCheckoutObserver = $this->objectManager->getObject(
- CheckGuestCheckoutObserver::class,
- [
- 'helper' => $captchaHelperMock,
- 'actionFlag' => $this->actionFlagMock,
- 'captchaStringResolver' => $this->captchaStringResolverMock,
- 'typeOnepage' => $onepageModelTypeMock,
- 'jsonHelper' => $this->jsonHelperMock
- ]
- );
-
- $captchaHelperMock->expects($this->once())
- ->method('getCaptcha')
- ->with(self::FORM_ID)
- ->willReturn($this->captchaModelMock);
- $onepageModelTypeMock->expects($this->once())
- ->method('getQuote')
- ->willReturn($this->quoteModelMock);
- }
-
- public function testCheckGuestCheckoutForRegister()
- {
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_REGISTER);
- $this->captchaModelMock->expects($this->never())
- ->method('isRequired');
-
- $this->checkGuestCheckoutObserver->execute($this->observer);
- }
-
- public function testCheckGuestCheckoutWithNoCaptchaRequired()
- {
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_GUEST);
- $this->captchaModelMock->expects($this->once())
- ->method('isRequired')
- ->willReturn(false);
- $this->captchaModelMock->expects($this->never())
- ->method('isCorrect');
-
- $this->checkGuestCheckoutObserver->execute($this->observer);
- }
-
- public function testCheckGuestCheckoutWithIncorrectCaptcha()
- {
- $captchaValue = 'some_word';
- $encodedJsonValue = '{}';
-
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_GUEST);
- $this->captchaModelMock->expects($this->once())
- ->method('isRequired')
- ->willReturn(true);
- $this->controllerMock->expects($this->once())
- ->method('getRequest')
- ->willReturn($this->requestMock);
- $this->controllerMock->expects($this->once())
- ->method('getResponse')
- ->willReturn($this->responseMock);
- $this->controllerMock->expects($this->once())
- ->method('getResponse')
- ->willReturn($this->responseMock);
- $this->captchaStringResolverMock->expects($this->once())
- ->method('resolve')
- ->with($this->requestMock, self::FORM_ID)
- ->willReturn($captchaValue);
- $this->captchaModelMock->expects($this->once())
- ->method('isCorrect')
- ->with($captchaValue)
- ->willReturn(false);
- $this->actionFlagMock->expects($this->once())
- ->method('set')
- ->with('', Action::FLAG_NO_DISPATCH, true);
- $this->jsonHelperMock->expects($this->once())
- ->method('jsonEncode')
- ->willReturn($encodedJsonValue);
- $this->responseMock->expects($this->once())
- ->method('representJson')
- ->with($encodedJsonValue);
-
- $this->checkGuestCheckoutObserver->execute($this->observer);
- }
-
- public function testCheckGuestCheckoutWithCorrectCaptcha()
- {
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_GUEST);
- $this->captchaModelMock->expects($this->once())
- ->method('isRequired')
- ->willReturn(true);
- $this->controllerMock->expects($this->once())
- ->method('getRequest')
- ->willReturn($this->requestMock);
- $this->captchaStringResolverMock->expects($this->once())
- ->method('resolve')
- ->with($this->requestMock, self::FORM_ID)
- ->willReturn('some_word');
- $this->captchaModelMock->expects($this->once())
- ->method('isCorrect')
- ->with('some_word')
- ->willReturn(true);
- $this->actionFlagMock->expects($this->never())
- ->method('set');
-
- $this->checkGuestCheckoutObserver->execute($this->observer);
- }
-}
diff --git a/app/code/Magento/Captcha/Test/Unit/Observer/CheckRegisterCheckoutObserverTest.php b/app/code/Magento/Captcha/Test/Unit/Observer/CheckRegisterCheckoutObserverTest.php
deleted file mode 100644
index 89012ef653838..0000000000000
--- a/app/code/Magento/Captcha/Test/Unit/Observer/CheckRegisterCheckoutObserverTest.php
+++ /dev/null
@@ -1,211 +0,0 @@
-createMock(Onepage::class);
- $captchaHelperMock = $this->createMock(CaptchaDataHelper::class);
- $this->objectManager = new ObjectManager($this);
- $this->actionFlagMock = $this->createMock(ActionFlag::class);
- $this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class);
- $this->captchaModelMock = $this->createMock(CaptchaModel::class);
- $this->quoteModelMock = $this->createMock(Quote::class);
- $this->controllerMock = $this->createMock(Action::class);
- $this->requestMock = $this->createMock(Http::class);
- $this->responseMock = $this->createMock(HttpResponse::class);
- $this->observer = new Observer(['controller_action' => $this->controllerMock]);
- $this->jsonHelperMock = $this->createMock(JsonHelper::class);
-
- $this->checkRegisterCheckoutObserver = $this->objectManager->getObject(
- CheckRegisterCheckoutObserver::class,
- [
- 'helper' => $captchaHelperMock,
- 'actionFlag' => $this->actionFlagMock,
- 'captchaStringResolver' => $this->captchaStringResolverMock,
- 'typeOnepage' => $onepageModelTypeMock,
- 'jsonHelper' => $this->jsonHelperMock
- ]
- );
-
- $captchaHelperMock->expects($this->once())
- ->method('getCaptcha')
- ->with(self::FORM_ID)
- ->willReturn($this->captchaModelMock);
- $onepageModelTypeMock->expects($this->once())
- ->method('getQuote')
- ->willReturn($this->quoteModelMock);
- }
-
- public function testCheckRegisterCheckoutForGuest()
- {
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_GUEST);
- $this->captchaModelMock->expects($this->never())
- ->method('isRequired');
-
- $this->checkRegisterCheckoutObserver->execute($this->observer);
- }
-
- public function testCheckRegisterCheckoutWithNoCaptchaRequired()
- {
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_REGISTER);
- $this->captchaModelMock->expects($this->once())
- ->method('isRequired')
- ->willReturn(false);
- $this->captchaModelMock->expects($this->never())
- ->method('isCorrect');
-
- $this->checkRegisterCheckoutObserver->execute($this->observer);
- }
-
- public function testCheckRegisterCheckoutWithIncorrectCaptcha()
- {
- $captchaValue = 'some_word';
- $encodedJsonValue = '{}';
-
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_REGISTER);
- $this->captchaModelMock->expects($this->once())
- ->method('isRequired')
- ->willReturn(true);
- $this->controllerMock->expects($this->once())
- ->method('getRequest')
- ->willReturn($this->requestMock);
- $this->controllerMock->expects($this->once())
- ->method('getResponse')
- ->willReturn($this->responseMock);
- $this->controllerMock->expects($this->once())
- ->method('getResponse')
- ->willReturn($this->responseMock);
- $this->captchaStringResolverMock->expects($this->once())
- ->method('resolve')
- ->with($this->requestMock, self::FORM_ID)
- ->willReturn($captchaValue);
- $this->captchaModelMock->expects($this->once())
- ->method('isCorrect')
- ->with($captchaValue)
- ->willReturn(false);
- $this->actionFlagMock->expects($this->once())
- ->method('set')
- ->with('', Action::FLAG_NO_DISPATCH, true);
- $this->jsonHelperMock->expects($this->once())
- ->method('jsonEncode')
- ->willReturn($encodedJsonValue);
- $this->responseMock->expects($this->once())
- ->method('representJson')
- ->with($encodedJsonValue);
-
- $this->checkRegisterCheckoutObserver->execute($this->observer);
- }
-
- public function testCheckRegisterCheckoutWithCorrectCaptcha()
- {
- $this->quoteModelMock->expects($this->once())
- ->method('getCheckoutMethod')
- ->willReturn(Onepage::METHOD_REGISTER);
- $this->captchaModelMock->expects($this->once())
- ->method('isRequired')
- ->willReturn(true);
- $this->controllerMock->expects($this->once())
- ->method('getRequest')
- ->willReturn($this->requestMock);
- $this->captchaStringResolverMock->expects($this->once())
- ->method('resolve')
- ->with($this->requestMock, self::FORM_ID)
- ->willReturn('some_word');
- $this->captchaModelMock->expects($this->once())
- ->method('isCorrect')
- ->with('some_word')
- ->willReturn(true);
- $this->actionFlagMock->expects($this->never())
- ->method('set');
-
- $this->checkRegisterCheckoutObserver->execute($this->observer);
- }
-}
diff --git a/app/code/Magento/Captcha/etc/config.xml b/app/code/Magento/Captcha/etc/config.xml
index 71c474de90ff4..dd748dd05ccda 100644
--- a/app/code/Magento/Captcha/etc/config.xml
+++ b/app/code/Magento/Captcha/etc/config.xml
@@ -53,8 +53,6 @@
1
1
- 1
- 1
1
@@ -77,12 +75,6 @@
Forgot password
-
- Check Out as Guest
-
-
- Register during Checkout
-
Contact Us
diff --git a/app/code/Magento/Captcha/etc/db_schema_whitelist.json b/app/code/Magento/Captcha/etc/db_schema_whitelist.json
index 95fd6411b44dd..1f5b1b624e48b 100644
--- a/app/code/Magento/Captcha/etc/db_schema_whitelist.json
+++ b/app/code/Magento/Captcha/etc/db_schema_whitelist.json
@@ -1,13 +1,13 @@
{
- "captcha_log": {
- "column": {
- "type": true,
- "value": true,
- "count": true,
- "updated_at": true
- },
- "constraint": {
- "PRIMARY": true
+ "captcha_log": {
+ "column": {
+ "type": true,
+ "value": true,
+ "count": true,
+ "updated_at": true
+ },
+ "constraint": {
+ "PRIMARY": true
+ }
}
- }
}
\ No newline at end of file
diff --git a/app/code/Magento/Captcha/etc/di.xml b/app/code/Magento/Captcha/etc/di.xml
index 955896eb12744..3a929f5e6cc00 100644
--- a/app/code/Magento/Captcha/etc/di.xml
+++ b/app/code/Magento/Captcha/etc/di.xml
@@ -33,7 +33,6 @@
- user_login
- - guest_checkout
diff --git a/app/code/Magento/Captcha/etc/events.xml b/app/code/Magento/Captcha/etc/events.xml
index e3ddd19de2d12..970c0d077260c 100644
--- a/app/code/Magento/Captcha/etc/events.xml
+++ b/app/code/Magento/Captcha/etc/events.xml
@@ -18,10 +18,6 @@
-
-
-
-
diff --git a/app/code/Magento/Captcha/etc/frontend/di.xml b/app/code/Magento/Captcha/etc/frontend/di.xml
index 225e62c8e8203..0c4ab0cda0735 100644
--- a/app/code/Magento/Captcha/etc/frontend/di.xml
+++ b/app/code/Magento/Captcha/etc/frontend/di.xml
@@ -17,7 +17,6 @@
- user_login
- - guest_checkout
diff --git a/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml
index 4ed56fd56cc3a..7180372f004e5 100644
--- a/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml
+++ b/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml
@@ -36,29 +36,7 @@
-
- Magento_Captcha/js/view/checkout/loginCaptcha
- additional-login-form-fields
- - guest_checkout
- - checkoutConfig
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Magento_Captcha/js/view/checkout/loginCaptcha
- - additional-login-form-fields
- - guest_checkout
+ - user_login
- checkoutConfig
diff --git a/app/code/Magento/Captcha/view/frontend/requirejs-config.js b/app/code/Magento/Captcha/view/frontend/requirejs-config.js
index 3b322711f8b1f..0f3394e41e7c2 100644
--- a/app/code/Magento/Captcha/view/frontend/requirejs-config.js
+++ b/app/code/Magento/Captcha/view/frontend/requirejs-config.js
@@ -6,7 +6,7 @@
var config = {
map: {
'*': {
- captcha: 'Magento_Captcha/captcha'
+ captcha: 'Magento_Captcha/js/captcha'
}
}
};
diff --git a/app/code/Magento/Captcha/view/frontend/web/captcha.js b/app/code/Magento/Captcha/view/frontend/web/js/captcha.js
similarity index 100%
rename from app/code/Magento/Captcha/view/frontend/web/captcha.js
rename to app/code/Magento/Captcha/view/frontend/web/js/captcha.js
diff --git a/app/code/Magento/Captcha/view/frontend/web/onepage.js b/app/code/Magento/Captcha/view/frontend/web/onepage.js
deleted file mode 100644
index 7f5f11d20572b..0000000000000
--- a/app/code/Magento/Captcha/view/frontend/web/onepage.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-/**
- * @deprecated since version 2.2.0
- */
-define(['jquery'], function ($) {
- 'use strict';
-
- $(document).on('login', function () {
- var type;
-
- $('[data-captcha="guest_checkout"], [data-captcha="register_during_checkout"]').hide();
- $('[role="guest_checkout"], [role="register_during_checkout"]').hide();
- type = $('#login\\:guest').is(':checked') ? 'guest_checkout' : 'register_during_checkout';
- $('[role="' + type + '"], [data-captcha="' + type + '"]').show();
- }).on('billingSave', function () {
- $('.captcha-reload:visible').trigger('click');
- });
-});
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php b/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php
index ad1ccea6f2c5a..1e0015d2be2c6 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Category/Checkboxes/Tree.php
@@ -30,7 +30,7 @@ class Tree extends \Magento\Catalog\Block\Adminhtml\Category\Tree
*/
protected function _prepareLayout()
{
- $this->setTemplate('catalog/category/checkboxes/tree.phtml');
+ $this->setTemplate('Magento_Catalog::catalog/category/checkboxes/tree.phtml');
}
/**
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Category/Edit/DeleteButton.php b/app/code/Magento/Catalog/Block/Adminhtml/Category/Edit/DeleteButton.php
index 20411a4c4d767..2eef1188e3910 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Category/Edit/DeleteButton.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Category/Edit/DeleteButton.php
@@ -27,7 +27,8 @@ public function getButtonData()
return [
'id' => 'delete',
'label' => __('Delete'),
- 'on_click' => "categoryDelete('" . $this->getDeleteUrl() . "')",
+ 'on_click' => "deleteConfirm('" .__('Are you sure you want to delete this category?') ."', '"
+ . $this->getDeleteUrl() . "', {data: {}})",
'class' => 'delete',
'sort_order' => 10
];
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php b/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php
index 0026e52e039ef..cd6c5021f0cc9 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Form/Renderer/Config/YearRange.php
@@ -32,10 +32,9 @@ protected function _getElementHtml(AbstractElement $element)
$from = $element->setValue(isset($values[0]) ? $values[0] : null)->getElementHtml();
$to = $element->setValue(isset($values[1]) ? $values[1] : null)->getElementHtml();
- return __(
- 'from '
- ) . $from . __(
- 'to '
- ) . $to;
+ return '' . __('from') . ' '
+ . $from .
+ '' . __('to') . ' '
+ . $to;
}
}
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php
index 750bf6f8a0216..4aa01b467d451 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Action/Attribute/Tab/Inventory.php
@@ -74,7 +74,7 @@ public function getFieldSuffix()
public function getStoreId()
{
$storeId = $this->getRequest()->getParam('store');
- return intval($storeId);
+ return (int) $storeId;
}
/**
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php
index a7129f509316b..3d131a6e08810 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Ajax/Serializer.php
@@ -41,7 +41,7 @@ public function __construct(
public function _construct()
{
parent::_construct();
- $this->setTemplate('catalog/product/edit/serializer.phtml');
+ $this->setTemplate('Magento_Catalog::catalog/product/edit/serializer.phtml');
return $this;
}
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php
index 0557a215383d3..36740f5853d74 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery.php
@@ -11,11 +11,16 @@
*/
namespace Magento\Catalog\Block\Adminhtml\Product\Helper\Form;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\Registry;
use Magento\Catalog\Model\Product;
use Magento\Eav\Model\Entity\Attribute;
use Magento\Catalog\Api\Data\ProductInterface;
+/**
+ * Adminhtml gallery block
+ */
class Gallery extends \Magento\Framework\View\Element\AbstractBlock
{
/**
@@ -66,27 +71,37 @@ class Gallery extends \Magento\Framework\View\Element\AbstractBlock
*/
protected $registry;
+ /**
+ * @var DataPersistorInterface
+ */
+ private $dataPersistor;
+
/**
* @param \Magento\Framework\View\Element\Context $context
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param Registry $registry
* @param \Magento\Framework\Data\Form $form
* @param array $data
+ * @param DataPersistorInterface|null $dataPersistor
*/
public function __construct(
\Magento\Framework\View\Element\Context $context,
\Magento\Store\Model\StoreManagerInterface $storeManager,
Registry $registry,
\Magento\Framework\Data\Form $form,
- $data = []
+ $data = [],
+ DataPersistorInterface $dataPersistor = null
) {
$this->storeManager = $storeManager;
$this->registry = $registry;
$this->form = $form;
+ $this->dataPersistor = $dataPersistor ?: ObjectManager::getInstance()->get(DataPersistorInterface::class);
parent::__construct($context, $data);
}
/**
+ * Returns element html.
+ *
* @return string
*/
public function getElementHtml()
@@ -102,7 +117,24 @@ public function getElementHtml()
*/
public function getImages()
{
- return $this->getDataObject()->getData('media_gallery') ?: null;
+ $images = $this->getDataObject()->getData('media_gallery') ?: null;
+ if ($images === null) {
+ $images = ((array)$this->dataPersistor->get('catalog_product'))['product']['media_gallery'] ?? null;
+ }
+
+ return $images;
+ }
+
+ /**
+ * Get value for given type.
+ *
+ * @param string $type
+ * @return string|null
+ */
+ public function getImageValue(string $type)
+ {
+ $product = (array)$this->dataPersistor->get('catalog_product');
+ return $product['product'][$type] ?? null;
}
/**
@@ -117,11 +149,13 @@ public function getContentHtml()
$content->setId($this->getHtmlId() . '_content')->setElement($this);
$content->setFormName($this->formName);
$galleryJs = $content->getJsObjectName();
- $content->getUploader()->getConfig()->setMegiaGallery($galleryJs);
+ $content->getUploader()->getConfig()->setMediaGallery($galleryJs);
return $content->toHtml();
}
/**
+ * Returns html id
+ *
* @return string
*/
protected function getHtmlId()
@@ -130,6 +164,8 @@ protected function getHtmlId()
}
/**
+ * Returns name
+ *
* @return string
*/
public function getName()
@@ -138,6 +174,8 @@ public function getName()
}
/**
+ * Returns suffix for field name
+ *
* @return string
*/
public function getFieldNameSuffix()
@@ -146,6 +184,8 @@ public function getFieldNameSuffix()
}
/**
+ * Returns data scope html id
+ *
* @return string
*/
public function getDataScopeHtmlId()
@@ -230,7 +270,6 @@ public function getDataObject()
/**
* Retrieve attribute field name
*
- *
* @param Attribute $attribute
* @return string
*/
@@ -244,6 +283,8 @@ public function getAttributeFieldName($attribute)
}
/**
+ * Returns html content of the block
+ *
* @return string
*/
public function toHtml()
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php
index 8d51f78ff5b68..e1208e25cc7c8 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php
@@ -18,6 +18,9 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\FileSystemException;
+/**
+ * Block for gallery content.
+ */
class Content extends \Magento\Backend\Block\Widget
{
/**
@@ -58,6 +61,8 @@ public function __construct(
}
/**
+ * Prepare layout.
+ *
* @return AbstractBlock
*/
protected function _prepareLayout()
@@ -103,6 +108,8 @@ public function getUploaderHtml()
}
/**
+ * Returns js object name
+ *
* @return string
*/
public function getJsObjectName()
@@ -111,6 +118,8 @@ public function getJsObjectName()
}
/**
+ * Returns buttons for add image action.
+ *
* @return string
*/
public function getAddImagesButton()
@@ -124,6 +133,8 @@ public function getAddImagesButton()
}
/**
+ * Returns image json
+ *
* @return string
*/
public function getImagesJson()
@@ -169,6 +180,8 @@ private function sortImagesByPosition($images)
}
/**
+ * Returns image values json
+ *
* @return string
*/
public function getImagesValuesJson()
@@ -193,9 +206,11 @@ public function getImageTypes()
$imageTypes = [];
foreach ($this->getMediaAttributes() as $attribute) {
/* @var $attribute \Magento\Eav\Model\Entity\Attribute */
+ $value = $this->getElement()->getDataObject()->getData($attribute->getAttributeCode())
+ ?: $this->getElement()->getImageValue($attribute->getAttributeCode());
$imageTypes[$attribute->getAttributeCode()] = [
'code' => $attribute->getAttributeCode(),
- 'value' => $this->getElement()->getDataObject()->getData($attribute->getAttributeCode()),
+ 'value' => $value,
'label' => $attribute->getFrontend()->getLabel(),
'scope' => __($this->getElement()->getScopeLabel($attribute)),
'name' => $this->getElement()->getAttributeFieldName($attribute),
@@ -241,6 +256,8 @@ public function getImageTypesJson()
}
/**
+ * Returns image helper object.
+ *
* @return \Magento\Catalog\Helper\Image
* @deprecated 101.0.3
*/
diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php b/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php
index 10aebf270579d..0d64ecc9bff90 100644
--- a/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php
+++ b/app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php
@@ -7,7 +7,6 @@
namespace Magento\Catalog\Block\Product\ProductList;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
-use Magento\Framework\View\Element\AbstractBlock;
/**
* Catalog product upsell items block
@@ -170,8 +169,8 @@ public function getRowCount()
*/
public function setColumnCount($columns)
{
- if (intval($columns) > 0) {
- $this->_columnCount = intval($columns);
+ if ((int) $columns > 0) {
+ $this->_columnCount = (int) $columns;
}
return $this;
}
@@ -213,8 +212,8 @@ public function getIterableItem()
*/
public function setItemLimit($type, $limit)
{
- if (intval($limit) > 0) {
- $this->_itemLimits[$type] = intval($limit);
+ if ((int) $limit > 0) {
+ $this->_itemLimits[$type] = (int) $limit;
}
return $this;
}
diff --git a/app/code/Magento/Catalog/Block/Product/View/Gallery.php b/app/code/Magento/Catalog/Block/Product/View/Gallery.php
index ab01fc6d134e9..706d9b83b9711 100644
--- a/app/code/Magento/Catalog/Block/Product/View/Gallery.php
+++ b/app/code/Magento/Catalog/Block/Product/View/Gallery.php
@@ -23,6 +23,8 @@
use Magento\Framework\Stdlib\ArrayUtils;
/**
+ * Product gallery block
+ *
* @api
* @since 100.0.2
*/
@@ -139,7 +141,7 @@ public function getGalleryImagesJson()
'thumb' => $image->getData('small_image_url'),
'img' => $image->getData('medium_image_url'),
'full' => $image->getData('large_image_url'),
- 'caption' => $image->getData('label'),
+ 'caption' => ($image->getLabel() ?: $this->getProduct()->getName()),
'position' => $image->getData('position'),
'isMain' => $this->isMainImage($image),
'type' => str_replace('external-', '', $image->getMediaType()),
@@ -196,6 +198,8 @@ public function isMainImage($image)
}
/**
+ * Returns image attribute
+ *
* @param string $imageId
* @param string $attributeName
* @param string $default
@@ -205,7 +209,7 @@ public function getImageAttribute($imageId, $attributeName, $default = null)
{
$attributes =
$this->getConfigView()->getMediaAttributes('Magento_Catalog', Image::MEDIA_TYPE_CONFIG_NODE, $imageId);
- return isset($attributes[$attributeName]) ? $attributes[$attributeName] : $default;
+ return $attributes[$attributeName] ?? $default;
}
/**
@@ -222,6 +226,8 @@ private function getConfigView()
}
/**
+ * Returns image gallery config object
+ *
* @return Collection
*/
private function getGalleryImagesConfig()
diff --git a/app/code/Magento/Catalog/Block/Product/Widget/NewWidget.php b/app/code/Magento/Catalog/Block/Product/Widget/NewWidget.php
index 704271b58f483..b4c24231a7415 100644
--- a/app/code/Magento/Catalog/Block/Product/Widget/NewWidget.php
+++ b/app/code/Magento/Catalog/Block/Product/Widget/NewWidget.php
@@ -139,7 +139,7 @@ public function getCacheKeyInfo()
[
$this->getDisplayType(),
$this->getProductsPerPage(),
- intval($this->getRequest()->getParam($this->getData('page_var_name'), 1)),
+ (int) $this->getRequest()->getParam($this->getData('page_var_name'), 1),
$this->serializer->serialize($this->getRequest()->getParams())
]
);
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
index 6456b6d578bbb..733e270174e4c 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
@@ -6,12 +6,14 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
/**
* Class Add Category
*
* @package Magento\Catalog\Controller\Adminhtml\Category
*/
-class Add extends \Magento\Catalog\Controller\Adminhtml\Category
+class Add extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface
{
/**
* Forward factory for result
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/CategoriesJson.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/CategoriesJson.php
index b8865f2de8d1e..752257f5b9009 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/CategoriesJson.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/CategoriesJson.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
-class CategoriesJson extends \Magento\Catalog\Controller\Adminhtml\Category
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
+
+class CategoriesJson extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpPostActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Delete.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Delete.php
index 0a54475b15f9c..39122d139c90b 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Delete.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Delete.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
-class Delete extends \Magento\Catalog\Controller\Adminhtml\Category
+use Magento\Framework\App\Action\HttpPostActionInterface;
+
+class Delete extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpPostActionInterface
{
/**
* @var \Magento\Catalog\Api\CategoryRepositoryInterface
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
index 6ff478e49a30c..0450ff1607a09 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
-class Edit extends \Magento\Catalog\Controller\Adminhtml\Category
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Edit extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
index 4cc0f2d89d179..d1efa0014d42d 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
@@ -5,12 +5,13 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category\Image;
+use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;
/**
* Class Upload
*/
-class Upload extends \Magento\Backend\App\Action
+class Upload extends \Magento\Backend\App\Action implements HttpPostActionInterface
{
/**
* Image uploader
@@ -54,14 +55,6 @@ public function execute()
try {
$result = $this->imageUploader->saveFileToTmpDir($imageId);
-
- $result['cookie'] = [
- 'name' => $this->_getSession()->getName(),
- 'value' => $this->_getSession()->getSessionId(),
- 'lifetime' => $this->_getSession()->getCookieLifetime(),
- 'path' => $this->_getSession()->getCookiePath(),
- 'domain' => $this->_getSession()->getCookieDomain(),
- ];
} catch (\Exception $e) {
$result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()];
}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php
index 902d71775a3d8..5089b37f90c58 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
-class Index extends \Magento\Catalog\Controller\Adminhtml\Category
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface
{
/**
* @var \Magento\Backend\Model\View\Result\ForwardFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Move.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Move.php
index df2c80eda141c..ba6bfddca9c6c 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Move.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Move.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
-class Move extends \Magento\Catalog\Controller\Adminhtml\Category
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
+
+class Move extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpPostActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
@@ -26,7 +28,7 @@ class Move extends \Magento\Catalog\Controller\Adminhtml\Category
/**
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
- * @param \Magento\Framework\View\LayoutFactory $layoutFactory,
+ * @param \Magento\Framework\View\LayoutFactory $layoutFactory
* @param \Psr\Log\LoggerInterface $logger
*/
public function __construct(
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php
index 9384397b67f93..046ebbb119e5b 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
-class RefreshPath extends \Magento\Catalog\Controller\Adminhtml\Category
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class RefreshPath extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
index cc03ab870739b..11c0a73a73708 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
@@ -6,6 +6,7 @@
namespace Magento\Catalog\Controller\Adminhtml\Category;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Catalog\Api\Data\CategoryAttributeInterface;
use Magento\Store\Model\StoreManagerInterface;
@@ -14,7 +15,7 @@
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Save extends \Magento\Catalog\Controller\Adminhtml\Category
+class Save extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpPostActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\RawFactory
@@ -280,7 +281,7 @@ public function imagePreprocessing($data)
continue;
}
- $data[$attributeCode] = false;
+ $data[$attributeCode] = '';
}
return $data;
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Validate.php
index 4eda49068ac3a..66a5fb1008a78 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Validate.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Validate.php
@@ -5,10 +5,14 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Category;
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
+use Magento\Catalog\Controller\Adminhtml\Category as CategoryAction;
+
/**
* Catalog category validate
*/
-class Validate extends \Magento\Catalog\Controller\Adminhtml\Category
+class Validate extends CategoryAction implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php
index 7eb391dedf81c..3cba09b1e8e9a 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Edit.php
@@ -6,10 +6,18 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Ui\Component\MassAction\Filter;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
+use Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute as AttributeAction;
-class Edit extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute
+/**
+ * Form for mass updatings products' attributes.
+ * Can be accessed by GET since it's a form,
+ * can be accessed by POST since it's used as a processor of a mass-action button.
+ */
+class Edit extends AttributeAction implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php
index 0fbf9054ef1bd..0730e7a7c5dc1 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Save.php
@@ -6,13 +6,14 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Backend\App\Action;
/**
* Class Save
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute
+class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute implements HttpPostActionInterface
{
/**
* @var \Magento\Catalog\Model\Indexer\Product\Flat\Processor
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Validate.php
index a873f08d082d7..30a6629dd1c29 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Validate.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Action/Attribute/Validate.php
@@ -6,7 +6,11 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute;
-class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
+use Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute as AttributeAction;
+
+class Validate extends AttributeAction implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* @var \Magento\Framework\Controller\Result\JsonFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Delete.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Delete.php
index bef6aee0e2afd..faa9e4ddf49b4 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Delete.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Delete.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute;
-class Delete extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute
+use Magento\Framework\App\Action\HttpPostActionInterface;
+
+class Delete extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute implements HttpPostActionInterface
{
/**
* @return \Magento\Backend\Model\View\Result\Redirect
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Edit.php
index a99cbdbade181..a41cd71aea463 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Edit.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Edit.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute;
-class Edit extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Edit extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute implements HttpGetActionInterface
{
/**
* @return \Magento\Framework\Controller\ResultInterface
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Index.php
index 9bdc54b289c20..34267121f9b8b 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Index.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute;
-class Index extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute implements HttpGetActionInterface
{
/**
* @return \Magento\Backend\Model\View\Result\Page
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/NewAction.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/NewAction.php
index e954d9730591c..fdfde7e806096 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/NewAction.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/NewAction.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute;
-class NewAction extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class NewAction extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute implements HttpGetActionInterface
{
/**
* @var \Magento\Backend\Model\View\Result\ForwardFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
index 817de6828e48d..84ad6d2116726 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php
@@ -7,6 +7,7 @@
namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Backend\App\Action\Context;
use Magento\Backend\Model\View\Result\Redirect;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
@@ -33,7 +34,7 @@
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Save extends Attribute
+class Save extends Attribute implements HttpPostActionInterface
{
/**
* @var BuildFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php
index db452113ada06..dac92f9b2eb9e 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Validate.php
@@ -7,9 +7,12 @@
namespace Magento\Catalog\Controller\Adminhtml\Product\Attribute;
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\DataObject;
+use Magento\Catalog\Controller\Adminhtml\Product\Attribute as AttributeAction;
-class Validate extends \Magento\Catalog\Controller\Adminhtml\Product\Attribute
+class Validate extends AttributeAction implements HttpGetActionInterface, HttpPostActionInterface
{
const DEFAULT_MESSAGE_KEY = 'message';
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Builder.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Builder.php
index 4fa61b2b372c2..125406061aed7 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Builder.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Builder.php
@@ -11,6 +11,9 @@
use Magento\Store\Model\StoreFactory;
use Psr\Log\LoggerInterface as Logger;
use Magento\Framework\Registry;
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Type as ProductTypes;
class Builder
{
@@ -39,6 +42,11 @@ class Builder
*/
protected $storeFactory;
+ /**
+ * @var ProductRepositoryInterface
+ */
+ private $productRepository;
+
/**
* Constructor
*
@@ -47,13 +55,15 @@ class Builder
* @param Registry $registry
* @param WysiwygModel\Config $wysiwygConfig
* @param StoreFactory|null $storeFactory
+ * @param ProductRepositoryInterface|null $productRepository
*/
public function __construct(
ProductFactory $productFactory,
Logger $logger,
Registry $registry,
WysiwygModel\Config $wysiwygConfig,
- StoreFactory $storeFactory = null
+ StoreFactory $storeFactory = null,
+ ProductRepositoryInterface $productRepository = null
) {
$this->productFactory = $productFactory;
$this->logger = $logger;
@@ -61,6 +71,8 @@ public function __construct(
$this->wysiwygConfig = $wysiwygConfig;
$this->storeFactory = $storeFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
->get(\Magento\Store\Model\StoreFactory::class);
+ $this->productRepository = $productRepository ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(ProductRepositoryInterface::class);
}
/**
@@ -68,40 +80,62 @@ public function __construct(
*
* @param RequestInterface $request
* @return \Magento\Catalog\Model\Product
+ * @throws \RuntimeException
*/
public function build(RequestInterface $request)
{
- $productId = (int)$request->getParam('id');
- /** @var $product \Magento\Catalog\Model\Product */
- $product = $this->productFactory->create();
- $product->setStoreId($request->getParam('store', 0));
- $store = $this->storeFactory->create();
- $store->load($request->getParam('store', 0));
-
+ $productId = (int) $request->getParam('id');
+ $storeId = $request->getParam('store', 0);
+ $attributeSetId = (int) $request->getParam('set');
$typeId = $request->getParam('type');
- if (!$productId && $typeId) {
- $product->setTypeId($typeId);
- }
- $product->setData('_edit_mode', true);
if ($productId) {
try {
- $product->load($productId);
+ $product = $this->productRepository->getById($productId, true, $storeId);
} catch (\Exception $e) {
- $product->setTypeId(\Magento\Catalog\Model\Product\Type::DEFAULT_TYPE);
+ $product = $this->createEmptyProduct(ProductTypes::DEFAULT_TYPE, $attributeSetId, $storeId);
$this->logger->critical($e);
}
+ } else {
+ $product = $this->createEmptyProduct($typeId, $attributeSetId, $storeId);
}
- $setId = (int)$request->getParam('set');
- if ($setId) {
- $product->setAttributeSetId($setId);
- }
+ $store = $this->storeFactory->create();
+ $store->load($storeId);
$this->registry->register('product', $product);
$this->registry->register('current_product', $product);
$this->registry->register('current_store', $store);
- $this->wysiwygConfig->setStoreId($request->getParam('store'));
+
+ $this->wysiwygConfig->setStoreId($storeId);
+
+ return $product;
+ }
+
+ /**
+ * @param int $typeId
+ * @param int $attributeSetId
+ * @param int $storeId
+ * @return \Magento\Catalog\Model\Product
+ */
+ private function createEmptyProduct($typeId, $attributeSetId, $storeId): Product
+ {
+ /** @var $product \Magento\Catalog\Model\Product */
+ $product = $this->productFactory->create();
+ $product->setData('_edit_mode', true);
+
+ if ($typeId !== null) {
+ $product->setTypeId($typeId);
+ }
+
+ if ($storeId !== null) {
+ $product->setStoreId($storeId);
+ }
+
+ if ($attributeSetId) {
+ $product->setAttributeSetId($attributeSetId);
+ }
+
return $product;
}
}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Edit.php
index 1b9316a95ad59..c31ceabcda655 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Edit.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Edit.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
-class Edit extends \Magento\Catalog\Controller\Adminhtml\Product
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Edit extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpGetActionInterface
{
/**
* Array of actions which can be processed without secret key validation
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery/Upload.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery/Upload.php
index b5660ea87934c..ff7311e931755 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery/Upload.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Gallery/Upload.php
@@ -6,9 +6,10 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Gallery;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
-class Upload extends \Magento\Backend\App\Action
+class Upload extends \Magento\Backend\App\Action implements HttpPostActionInterface
{
/**
* Authorization level of a basic admin session
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Index.php
index ea66ecf6b1622..7755a512eb9b4 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Index.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
-class Index extends \Magento\Catalog\Controller\Adminhtml\Product
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
index 95339870b4d61..d82f4a04fb252 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
@@ -104,7 +104,7 @@ class Helper
* @param \Magento\Backend\Helper\Js $jsHelper
* @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter
* @param CustomOptionFactory|null $customOptionFactory
- * @param ProductLinkFactory |null $productLinkFactory
+ * @param ProductLinkFactory|null $productLinkFactory
* @param ProductRepositoryInterface|null $productRepository
* @param LinkTypeProvider|null $linkTypeProvider
* @param AttributeFilter|null $attributeFilter
@@ -159,6 +159,7 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra
}
$productData = $this->normalize($productData);
+ $productData = $this->convertSpecialFromDateStringToObject($productData);
if (!empty($productData['is_downloadable'])) {
$productData['product_has_weight'] = 0;
@@ -452,4 +453,19 @@ private function fillProductOptions(Product $product, array $productOptions)
return $product->setOptions($customOptions);
}
+
+ /**
+ * Convert string date presentation into object
+ *
+ * @param array $productData
+ * @return array
+ */
+ private function convertSpecialFromDateStringToObject($productData)
+ {
+ if (isset($productData['special_from_date']) && $productData['special_from_date'] != '') {
+ $productData['special_from_date'] = new \DateTime($productData['special_from_date']);
+ }
+
+ return $productData;
+ }
}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php
index f32c6edd57394..8fceba3c45e2c 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php
@@ -6,13 +6,14 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Backend\App\Action\Context;
use Magento\Ui\Component\MassAction\Filter;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Api\ProductRepositoryInterface;
-class MassDelete extends \Magento\Catalog\Controller\Adminhtml\Product
+class MassDelete extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpPostActionInterface
{
/**
* Massactions filter
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php
index e3623aabfa1a3..b7655f7ee2862 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassStatus.php
@@ -6,6 +6,7 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Backend\App\Action;
use Magento\Catalog\Controller\Adminhtml\Product;
use Magento\Framework\Controller\ResultFactory;
@@ -15,7 +16,7 @@
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class MassStatus extends \Magento\Catalog\Controller\Adminhtml\Product
+class MassStatus extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpPostActionInterface
{
/**
* @var \Magento\Catalog\Model\Indexer\Product\Price\Processor
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php
index 0b027105cd7d4..0b1ef98c386c4 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php
@@ -6,11 +6,12 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Backend\App\Action;
use Magento\Catalog\Controller\Adminhtml\Product;
use Magento\Framework\App\ObjectManager;
-class NewAction extends \Magento\Catalog\Controller\Adminhtml\Product
+class NewAction extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpGetActionInterface
{
/**
* @var Initialization\StockDataFilter
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Reload.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Reload.php
index ff87e7f57413f..a0963e60d888d 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Reload.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Reload.php
@@ -5,12 +5,13 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;
/**
* Backend reload of product create/edit form
*/
-class Reload extends \Magento\Catalog\Controller\Adminhtml\Product
+class Reload extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpPostActionInterface
{
/**
* {@inheritdoc}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php
index ff3ce60d92787..e84d9ff12906e 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Save.php
@@ -7,7 +7,9 @@
namespace Magento\Catalog\Controller\Adminhtml\Product;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Backend\App\Action;
+use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Controller\Adminhtml\Product;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\App\Request\DataPersistorInterface;
@@ -16,7 +18,7 @@
* Class Save
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Save extends \Magento\Catalog\Controller\Adminhtml\Product
+class Save extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpPostActionInterface
{
/**
* @var Initialization\Helper
@@ -53,6 +55,16 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product
*/
private $storeManager;
+ /**
+ * @var \Magento\Framework\Escaper|null
+ */
+ private $escaper;
+
+ /**
+ * @var null|\Psr\Log\LoggerInterface
+ */
+ private $logger;
+
/**
* Save constructor.
*
@@ -62,6 +74,8 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Product
* @param \Magento\Catalog\Model\Product\Copier $productCopier
* @param \Magento\Catalog\Model\Product\TypeTransitionManager $productTypeManager
* @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
+ * @param \Magento\Framework\Escaper|null $escaper
+ * @param \Psr\Log\LoggerInterface|null $logger
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
@@ -69,13 +83,17 @@ public function __construct(
Initialization\Helper $initializationHelper,
\Magento\Catalog\Model\Product\Copier $productCopier,
\Magento\Catalog\Model\Product\TypeTransitionManager $productTypeManager,
- \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
+ \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
+ \Magento\Framework\Escaper $escaper = null,
+ \Psr\Log\LoggerInterface $logger = null
) {
$this->initializationHelper = $initializationHelper;
$this->productCopier = $productCopier;
$this->productTypeManager = $productTypeManager;
$this->productRepository = $productRepository;
parent::__construct($context, $productBuilder);
+ $this->escaper = $escaper ?? $this->_objectManager->get(\Magento\Framework\Escaper::class);
+ $this->logger = $logger ?? $this->_objectManager->get(\Psr\Log\LoggerInterface::class);
}
/**
@@ -102,7 +120,6 @@ public function execute()
$this->productBuilder->build($this->getRequest())
);
$this->productTypeManager->processProduct($product);
-
if (isset($data['product'][$product->getIdFieldName()])) {
throw new \Magento\Framework\Exception\LocalizedException(
__('The product was unable to be saved. Please try again.')
@@ -110,6 +127,7 @@ public function execute()
}
$originalSku = $product->getSku();
+ $canSaveCustomOptions = $product->getCanSaveCustomOptions();
$product->save();
$this->handleImageRemoveError($data, $product->getId());
$this->getCategoryLinkManagement()->assignProductToCategories(
@@ -119,21 +137,17 @@ public function execute()
$productId = $product->getEntityId();
$productAttributeSetId = $product->getAttributeSetId();
$productTypeId = $product->getTypeId();
-
- $this->copyToStores($data, $productId);
-
+ $extendedData = $data;
+ $extendedData['can_save_custom_options'] = $canSaveCustomOptions;
+ $this->copyToStores($extendedData, $productId);
$this->messageManager->addSuccessMessage(__('You saved the product.'));
$this->getDataPersistor()->clear('catalog_product');
if ($product->getSku() != $originalSku) {
$this->messageManager->addNoticeMessage(
__(
'SKU for product %1 has been changed to %2.',
- $this->_objectManager->get(
- \Magento\Framework\Escaper::class
- )->escapeHtml($product->getName()),
- $this->_objectManager->get(
- \Magento\Framework\Escaper::class
- )->escapeHtml($product->getSku())
+ $this->escaper->escapeHtml($product->getName()),
+ $this->escaper->escapeHtml($product->getSku())
)
);
}
@@ -143,17 +157,20 @@ public function execute()
);
if ($redirectBack === 'duplicate') {
+ $product->unsetData('quantity_and_stock_status');
$newProduct = $this->productCopier->copy($product);
$this->messageManager->addSuccessMessage(__('You duplicated the product.'));
}
} catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
+ $this->logger->critical($e);
$this->messageManager->addExceptionMessage($e);
+ $data = isset($product) ? $this->persistMediaData($product, $data) : $data;
$this->getDataPersistor()->set('catalog_product', $data);
$redirectBack = $productId ? true : 'new';
} catch (\Exception $e) {
- $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
+ $this->logger->critical($e);
$this->messageManager->addErrorMessage($e->getMessage());
+ $data = isset($product) ? $this->persistMediaData($product, $data) : $data;
$this->getDataPersistor()->set('catalog_product', $data);
$redirectBack = $productId ? true : 'new';
}
@@ -186,6 +203,7 @@ public function execute()
/**
* Notify customer when image was not deleted in specific case.
+ *
* TODO: temporary workaround must be eliminated in MAGETWO-45306
*
* @param array $postData
@@ -239,6 +257,7 @@ protected function copyToStores($data, $productId)
->setStoreId($copyFrom)
->load($productId)
->setStoreId($copyTo)
+ ->setCanSaveCustomOptions($data['can_save_custom_options'])
->setCopyFromView(true)
->save();
}
@@ -250,6 +269,8 @@ protected function copyToStores($data, $productId)
}
/**
+ * Get categoryLinkManagement in a backward compatible way.
+ *
* @return \Magento\Catalog\Api\CategoryLinkManagementInterface
*/
private function getCategoryLinkManagement()
@@ -262,6 +283,8 @@ private function getCategoryLinkManagement()
}
/**
+ * Get storeManager in a backward compatible way.
+ *
* @return StoreManagerInterface
* @deprecated 101.0.0
*/
@@ -288,4 +311,36 @@ protected function getDataPersistor()
return $this->dataPersistor;
}
+
+ /**
+ * Persist media gallery on error, in order to show already saved images on next run.
+ *
+ * @param ProductInterface $product
+ * @param array $data
+ * @return array
+ */
+ private function persistMediaData(ProductInterface $product, array $data)
+ {
+ $mediaGallery = $product->getData('media_gallery');
+ if (!empty($mediaGallery['images'])) {
+ foreach ($mediaGallery['images'] as $key => $image) {
+ if (!isset($image['new_file'])) {
+ //Remove duplicates.
+ unset($mediaGallery['images'][$key]);
+ }
+ }
+ $data['product']['media_gallery'] = $mediaGallery;
+ $fields = [
+ 'image',
+ 'small_image',
+ 'thumbnail',
+ 'swatch_image',
+ ];
+ foreach ($fields as $field) {
+ $data['product'][$field] = $product->getData($field);
+ }
+ }
+
+ return $data;
+ }
}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Add.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Add.php
index 480c30322a073..bfe474abba1b8 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Add.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Add.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Set;
-class Add extends \Magento\Catalog\Controller\Adminhtml\Product\Set
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Add extends \Magento\Catalog\Controller\Adminhtml\Product\Set implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Delete.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Delete.php
index f2695311732f0..771cc83f79e80 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Delete.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Delete.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Set;
-class Delete extends \Magento\Catalog\Controller\Adminhtml\Product\Set
+use Magento\Framework\App\Action\HttpPostActionInterface;
+
+class Delete extends \Magento\Catalog\Controller\Adminhtml\Product\Set implements HttpPostActionInterface
{
/**
* @var \Magento\Eav\Api\AttributeSetRepositoryInterface
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Edit.php
index ec540180b0345..6f6870cb0849f 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Edit.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Edit.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Set;
-class Edit extends \Magento\Catalog\Controller\Adminhtml\Product\Set
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Edit extends \Magento\Catalog\Controller\Adminhtml\Product\Set implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Index.php
index 29f7dff4f0d47..aadf724f6006e 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Index.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Index.php
@@ -6,7 +6,9 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Set;
-class Index extends \Magento\Catalog\Controller\Adminhtml\Product\Set
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
+
+class Index extends \Magento\Catalog\Controller\Adminhtml\Product\Set implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\View\Result\PageFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Save.php
index c5dd9ce6d8e77..83620de25b012 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/Save.php
@@ -6,12 +6,13 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product\Set;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\App\ObjectManager;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Set
+class Save extends \Magento\Catalog\Controller\Adminhtml\Product\Set implements HttpPostActionInterface
{
/**
* @var \Magento\Framework\View\LayoutFactory
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Validate.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Validate.php
index e131bfe38c546..77c9cfcd40f05 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Validate.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Validate.php
@@ -6,6 +6,8 @@
*/
namespace Magento\Catalog\Controller\Adminhtml\Product;
+use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Backend\App\Action;
use Magento\Catalog\Controller\Adminhtml\Product;
use Magento\Framework\App\ObjectManager;
@@ -16,7 +18,7 @@
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Validate extends \Magento\Catalog\Controller\Adminhtml\Product
+class Validate extends Product implements HttpPostActionInterface, HttpGetActionInterface
{
/**
* @var \Magento\Framework\Stdlib\DateTime\Filter\Date
diff --git a/app/code/Magento/Catalog/Controller/Category/View.php b/app/code/Magento/Catalog/Controller/Category/View.php
index 226e572505076..19243aabb1b71 100644
--- a/app/code/Magento/Catalog/Controller/Category/View.php
+++ b/app/code/Magento/Catalog/Controller/Category/View.php
@@ -6,15 +6,20 @@
*/
namespace Magento\Catalog\Controller\Category;
+use Magento\Framework\App\Action\HttpPostActionInterface;
+use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Catalog\Model\Layer\Resolver;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\View\Result\PageFactory;
+use Magento\Framework\App\Action\Action;
/**
+ * View a category on storefront. Needs to be accessible by POST because of the store switching.
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class View extends \Magento\Framework\App\Action\Action
+class View extends Action implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* Core registry
diff --git a/app/code/Magento/Catalog/Controller/Product/Compare/Add.php b/app/code/Magento/Catalog/Controller/Product/Compare/Add.php
index 89eb6c9be929f..d99901c915a10 100644
--- a/app/code/Magento/Catalog/Controller/Product/Compare/Add.php
+++ b/app/code/Magento/Catalog/Controller/Product/Compare/Add.php
@@ -6,9 +6,10 @@
*/
namespace Magento\Catalog\Controller\Product\Compare;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\Exception\NoSuchEntityException;
-class Add extends \Magento\Catalog\Controller\Product\Compare
+class Add extends \Magento\Catalog\Controller\Product\Compare implements HttpPostActionInterface
{
/**
* Add item to compare list
@@ -36,7 +37,14 @@ public function execute()
$productName = $this->_objectManager->get(
\Magento\Framework\Escaper::class
)->escapeHtml($product->getName());
- $this->messageManager->addSuccess(__('You added product %1 to the comparison list.', $productName));
+ $this->messageManager->addComplexSuccessMessage(
+ 'addCompareSuccessMessage',
+ [
+ 'product_name' => $productName,
+ 'compare_list_url' => $this->_url->getUrl('catalog/product_compare')
+ ]
+ );
+
$this->_eventManager->dispatch('catalog_product_compare_add_product', ['product' => $product]);
}
diff --git a/app/code/Magento/Catalog/Controller/Product/Compare/Clear.php b/app/code/Magento/Catalog/Controller/Product/Compare/Clear.php
index 568fbf1d05677..2703e9869bd47 100644
--- a/app/code/Magento/Catalog/Controller/Product/Compare/Clear.php
+++ b/app/code/Magento/Catalog/Controller/Product/Compare/Clear.php
@@ -6,9 +6,10 @@
*/
namespace Magento\Catalog\Controller\Product\Compare;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\Controller\ResultFactory;
-class Clear extends \Magento\Catalog\Controller\Product\Compare
+class Clear extends \Magento\Catalog\Controller\Product\Compare implements HttpPostActionInterface
{
/**
* Remove all items from comparison list
diff --git a/app/code/Magento/Catalog/Controller/Product/Compare/Index.php b/app/code/Magento/Catalog/Controller/Product/Compare/Index.php
index 3eba058318a7d..c0aa32a56ed17 100644
--- a/app/code/Magento/Catalog/Controller/Product/Compare/Index.php
+++ b/app/code/Magento/Catalog/Controller/Product/Compare/Index.php
@@ -6,6 +6,7 @@
*/
namespace Magento\Catalog\Controller\Product\Compare;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Data\Form\FormKey\Validator;
use Magento\Framework\View\Result\PageFactory;
@@ -13,7 +14,7 @@
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Index extends \Magento\Catalog\Controller\Product\Compare
+class Index extends \Magento\Catalog\Controller\Product\Compare implements HttpGetActionInterface
{
/**
* @var \Magento\Framework\Url\DecoderInterface
diff --git a/app/code/Magento/Catalog/Controller/Product/Compare/Remove.php b/app/code/Magento/Catalog/Controller/Product/Compare/Remove.php
index 2acbe5ce4d582..eac0ddf94af20 100644
--- a/app/code/Magento/Catalog/Controller/Product/Compare/Remove.php
+++ b/app/code/Magento/Catalog/Controller/Product/Compare/Remove.php
@@ -6,9 +6,10 @@
*/
namespace Magento\Catalog\Controller\Product\Compare;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
use Magento\Framework\Exception\NoSuchEntityException;
-class Remove extends \Magento\Catalog\Controller\Product\Compare
+class Remove extends \Magento\Catalog\Controller\Product\Compare implements HttpPostActionInterface
{
/**
* Remove item from compare list
diff --git a/app/code/Magento/Catalog/Controller/Product/View.php b/app/code/Magento/Catalog/Controller/Product/View.php
index ed437361fddd3..024123e15150d 100644
--- a/app/code/Magento/Catalog/Controller/Product/View.php
+++ b/app/code/Magento/Catalog/Controller/Product/View.php
@@ -6,10 +6,16 @@
*/
namespace Magento\Catalog\Controller\Product;
+use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
+use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface;
use Magento\Framework\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;
+use Magento\Catalog\Controller\Product as ProductAction;
-class View extends \Magento\Catalog\Controller\Product
+/**
+ * View a product on storefront. Needs to be accessible by POST because of the store switching.
+ */
+class View extends ProductAction implements HttpGetActionInterface, HttpPostActionInterface
{
/**
* @var \Magento\Catalog\Helper\Product\View
diff --git a/app/code/Magento/Catalog/Cron/FrontendActionsFlush.php b/app/code/Magento/Catalog/Cron/FrontendActionsFlush.php
index 6e7699abb4776..99e9898eab3c0 100644
--- a/app/code/Magento/Catalog/Cron/FrontendActionsFlush.php
+++ b/app/code/Magento/Catalog/Cron/FrontendActionsFlush.php
@@ -57,8 +57,7 @@ private function getLifeTimeByNamespace($namespace)
];
}
- return isset($configuration['lifetime']) ?
- (int) $configuration['lifetime'] : FrontendStorageConfigurationInterface::DEFAULT_LIFETIME;
+ return (int)$configuration['lifetime'] ?? FrontendStorageConfigurationInterface::DEFAULT_LIFETIME;
}
/**
diff --git a/app/code/Magento/Catalog/Helper/Image.php b/app/code/Magento/Catalog/Helper/Image.php
index 4f128d639b2bb..758e59790d241 100644
--- a/app/code/Magento/Catalog/Helper/Image.php
+++ b/app/code/Magento/Catalog/Helper/Image.php
@@ -859,7 +859,7 @@ public function getFrame()
*/
protected function getAttribute($name)
{
- return isset($this->attributes[$name]) ? $this->attributes[$name] : null;
+ return $this->attributes[$name] ?? null;
}
/**
diff --git a/app/code/Magento/Catalog/Helper/Output.php b/app/code/Magento/Catalog/Helper/Output.php
index ad0f9508cb67e..33e261dc353b4 100644
--- a/app/code/Magento/Catalog/Helper/Output.php
+++ b/app/code/Magento/Catalog/Helper/Output.php
@@ -116,7 +116,7 @@ public function addHandler($method, $handler)
public function getHandlers($method)
{
$method = strtolower($method);
- return isset($this->_handlers[$method]) ? $this->_handlers[$method] : [];
+ return $this->_handlers[$method] ?? [];
}
/**
diff --git a/app/code/Magento/Catalog/Helper/Product/View.php b/app/code/Magento/Catalog/Helper/Product/View.php
index 5753910c125d2..1509e489aee3b 100644
--- a/app/code/Magento/Catalog/Helper/Product/View.php
+++ b/app/code/Magento/Catalog/Helper/Product/View.php
@@ -112,12 +112,9 @@ private function preparePageMetadata(ResultPage $resultPage, $product)
$pageLayout = $resultPage->getLayout();
$pageConfig = $resultPage->getConfig();
- $title = $product->getMetaTitle();
- if ($title) {
- $pageConfig->getTitle()->set($title);
- } else {
- $pageConfig->getTitle()->set($product->getName());
- }
+ $metaTitle = $product->getMetaTitle();
+ $pageConfig->setMetaTitle($metaTitle);
+ $pageConfig->getTitle()->set($metaTitle ?: $product->getName());
$keyword = $product->getMetaKeyword();
$currentCategory = $this->_coreRegistry->registry('current_category');
diff --git a/app/code/Magento/Catalog/Model/Api/SearchCriteria/CollectionProcessor/ConditionProcessor/ConditionBuilder/NativeAttributeCondition.php b/app/code/Magento/Catalog/Model/Api/SearchCriteria/CollectionProcessor/ConditionProcessor/ConditionBuilder/NativeAttributeCondition.php
index d072acf4c719c..71b9a9c470374 100644
--- a/app/code/Magento/Catalog/Model/Api/SearchCriteria/CollectionProcessor/ConditionProcessor/ConditionBuilder/NativeAttributeCondition.php
+++ b/app/code/Magento/Catalog/Model/Api/SearchCriteria/CollectionProcessor/ConditionProcessor/ConditionBuilder/NativeAttributeCondition.php
@@ -77,7 +77,7 @@ private function mapConditionType(string $conditionType, string $field): string
];
}
- return isset($conditionsMap[$conditionType]) ? $conditionsMap[$conditionType] : $conditionType;
+ return $conditionsMap[$conditionType] ?? $conditionType;
}
/**
diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php
index 4f605d0206264..999f08aa1ea6e 100644
--- a/app/code/Magento/Catalog/Model/Category.php
+++ b/app/code/Magento/Catalog/Model/Category.php
@@ -7,11 +7,8 @@
use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Catalog\Api\Data\CategoryInterface;
-use Magento\Catalog\Model\Entity\GetCategoryCustomAttributeCodes;
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
-use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface;
use Magento\Framework\Api\AttributeValueFactory;
-use Magento\Framework\App\ObjectManager;
use Magento\Framework\Convert\ConvertArray;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Profiler;
@@ -214,11 +211,6 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
*/
protected $metadataService;
- /**
- * @var GetCustomAttributeCodesInterface
- */
- private $getCustomAttributeCodes;
-
/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
@@ -241,7 +233,6 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
* @param array $data
- * @param GetCustomAttributeCodesInterface|null $getCustomAttributeCodes
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -265,8 +256,7 @@ public function __construct(
CategoryRepositoryInterface $categoryRepository,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
- array $data = [],
- GetCustomAttributeCodesInterface $getCustomAttributeCodes = null
+ array $data = []
) {
$this->metadataService = $metadataService;
$this->_treeModel = $categoryTreeResource;
@@ -281,9 +271,6 @@ public function __construct(
$this->urlFinder = $urlFinder;
$this->indexerRegistry = $indexerRegistry;
$this->categoryRepository = $categoryRepository;
- $this->getCustomAttributeCodes = $getCustomAttributeCodes ?? ObjectManager::getInstance()->get(
- GetCategoryCustomAttributeCodes::class
- );
parent::__construct(
$context,
$registry,
@@ -313,14 +300,20 @@ protected function _construct()
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
protected function getCustomAttributesCodes()
{
- return $this->getCustomAttributeCodes->execute($this->metadataService);
+ if ($this->customAttributesCodes === null) {
+ $this->customAttributesCodes = $this->getEavAttributesCodes($this->metadataService);
+ $this->customAttributesCodes = array_diff($this->customAttributesCodes, CategoryInterface::ATTRIBUTES);
+ }
+ return $this->customAttributesCodes;
}
/**
+ * Returns model resource
+ *
* @throws \Magento\Framework\Exception\LocalizedException
* @return \Magento\Catalog\Model\ResourceModel\Category
* @deprecated because resource models should be used directly
@@ -657,6 +650,8 @@ public function formatUrlKey($str)
}
/**
+ * Returns image url
+ *
* @param string $attributeCode
* @return bool|string
* @throws \Magento\Framework\Exception\LocalizedException
@@ -717,7 +712,7 @@ public function getParentId()
return $parentId;
}
$parentIds = $this->getParentIds();
- return intval(array_pop($parentIds));
+ return (int) array_pop($parentIds);
}
/**
@@ -805,6 +800,7 @@ public function getChildren($recursive = false, $isActive = true, $sortByPositio
/**
* Retrieve Stores where isset category Path
+ *
* Return comma separated string
*
* @return string
@@ -835,6 +831,7 @@ public function checkId($id)
/**
* Get array categories ids which are part of category path
+ *
* Result array contain id of current category because it is part of the path
*
* @return array
@@ -1038,7 +1035,8 @@ public function getAvailableSortBy()
/**
* Retrieve Available Product Listing Sort By
- * code as key, value - name
+ *
+ * Code as key, value - name
*
* @return array
*/
@@ -1159,6 +1157,8 @@ public function getIdentities()
}
/**
+ * Returns path
+ *
* @codeCoverageIgnoreStart
* @return string|null
*/
@@ -1168,6 +1168,8 @@ public function getPath()
}
/**
+ * Returns position
+ *
* @return int|null
*/
public function getPosition()
@@ -1176,6 +1178,8 @@ public function getPosition()
}
/**
+ * Returns children count
+ *
* @return int
*/
public function getChildrenCount()
@@ -1184,6 +1188,8 @@ public function getChildrenCount()
}
/**
+ * Returns created at
+ *
* @return string|null
*/
public function getCreatedAt()
@@ -1192,6 +1198,8 @@ public function getCreatedAt()
}
/**
+ * Returns updated at
+ *
* @return string|null
*/
public function getUpdatedAt()
@@ -1200,6 +1208,8 @@ public function getUpdatedAt()
}
/**
+ * Returns is active
+ *
* @return bool
* @SuppressWarnings(PHPMD.BooleanGetMethodName)
*/
@@ -1209,6 +1219,8 @@ public function getIsActive()
}
/**
+ * Returns category id
+ *
* @return int|null
*/
public function getCategoryId()
@@ -1217,6 +1229,8 @@ public function getCategoryId()
}
/**
+ * Returns display mode
+ *
* @return string|null
*/
public function getDisplayMode()
@@ -1225,6 +1239,8 @@ public function getDisplayMode()
}
/**
+ * Returns is include in menu
+ *
* @return bool|null
*/
public function getIncludeInMenu()
@@ -1233,6 +1249,8 @@ public function getIncludeInMenu()
}
/**
+ * Returns url key
+ *
* @return string|null
*/
public function getUrlKey()
@@ -1241,6 +1259,8 @@ public function getUrlKey()
}
/**
+ * Returns children data
+ *
* @return \Magento\Catalog\Api\Data\CategoryTreeInterface[]|null
*/
public function getChildrenData()
@@ -1356,6 +1376,8 @@ public function setLevel($level)
}
/**
+ * Set updated at
+ *
* @param string $updatedAt
* @return $this
*/
@@ -1365,6 +1387,8 @@ public function setUpdatedAt($updatedAt)
}
/**
+ * Set created at
+ *
* @param string $createdAt
* @return $this
*/
@@ -1374,6 +1398,8 @@ public function setCreatedAt($createdAt)
}
/**
+ * Set path
+ *
* @param string $path
* @return $this
*/
@@ -1383,6 +1409,8 @@ public function setPath($path)
}
/**
+ * Set available sort by
+ *
* @param string[]|string $availableSortBy
* @return $this
*/
@@ -1392,6 +1420,8 @@ public function setAvailableSortBy($availableSortBy)
}
/**
+ * Set include in menu
+ *
* @param bool $includeInMenu
* @return $this
*/
@@ -1412,6 +1442,8 @@ public function setProductCount($productCount)
}
/**
+ * Set children data
+ *
* @param \Magento\Catalog\Api\Data\CategoryTreeInterface[] $childrenData
* @return $this
*/
@@ -1421,7 +1453,7 @@ public function setChildrenData(array $childrenData = null)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*
* @return \Magento\Catalog\Api\Data\CategoryExtensionInterface|null
*/
@@ -1431,7 +1463,7 @@ public function getExtensionAttributes()
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*
* @param \Magento\Catalog\Api\Data\CategoryExtensionInterface $extensionAttributes
* @return $this
diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
index a2dff83173b37..cd450e26cd832 100644
--- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
+++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
@@ -106,7 +106,7 @@ public function beforeSave($object)
$object->setData($this->additionalData . $attributeName, $value);
$object->setData($attributeName, $imageName);
} elseif (!is_string($value)) {
- $object->setData($attributeName, '');
+ $object->setData($attributeName, null);
}
return parent::beforeSave($object);
diff --git a/app/code/Magento/Catalog/Model/Config.php b/app/code/Magento/Catalog/Model/Config.php
index d2ffd6f440041..5dce940308a4f 100644
--- a/app/code/Magento/Catalog/Model/Config.php
+++ b/app/code/Magento/Catalog/Model/Config.php
@@ -381,7 +381,7 @@ public function getProductTypeName($id)
$this->loadProductTypes();
- return isset($this->_productTypesById[$id]) ? $this->_productTypesById[$id] : false;
+ return $this->_productTypesById[$id] ?? false;
}
/**
diff --git a/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php b/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php
deleted file mode 100644
index b2b9199cc56b4..0000000000000
--- a/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php
+++ /dev/null
@@ -1,37 +0,0 @@
-baseCustomAttributeCodes = $baseCustomAttributeCodes;
- }
-
- /**
- * @inheritdoc
- */
- public function execute(MetadataServiceInterface $metadataService): array
- {
- $customAttributesCodes = $this->baseCustomAttributeCodes->execute($metadataService);
- return array_diff($customAttributesCodes, CategoryInterface::ATTRIBUTES);
- }
-}
diff --git a/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php b/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php
deleted file mode 100644
index 23678ffcf48b7..0000000000000
--- a/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php
+++ /dev/null
@@ -1,37 +0,0 @@
-baseCustomAttributeCodes = $baseCustomAttributeCodes;
- }
-
- /**
- * @inheritdoc
- */
- public function execute(MetadataServiceInterface $metadataService): array
- {
- $customAttributesCodes = $this->baseCustomAttributeCodes->execute($metadataService);
- return array_diff($customAttributesCodes, ProductInterface::ATTRIBUTES);
- }
-}
diff --git a/app/code/Magento/Catalog/Model/FilterProductCustomAttribute.php b/app/code/Magento/Catalog/Model/FilterProductCustomAttribute.php
new file mode 100644
index 0000000000000..b83bb97301b9c
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/FilterProductCustomAttribute.php
@@ -0,0 +1,37 @@
+blackList = $blackList;
+ }
+
+ /**
+ * Delete custom attribute
+ * @param array $attributes
+ * @return array
+ */
+ public function execute(array $attributes): array
+ {
+ return array_diff($attributes, $this->blackList);
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ImageExtractor.php b/app/code/Magento/Catalog/Model/ImageExtractor.php
index d2c11a3762961..dcc70cbcd2a1a 100644
--- a/app/code/Magento/Catalog/Model/ImageExtractor.php
+++ b/app/code/Magento/Catalog/Model/ImageExtractor.php
@@ -9,6 +9,9 @@
use Magento\Catalog\Model\Product\Attribute\Backend\Media\ImageEntryConverter;
use Magento\Framework\View\Xsd\Media\TypeDataExtractorInterface;
+/**
+ * Image extractor from xml configuration
+ */
class ImageExtractor implements TypeDataExtractorInterface
{
/**
@@ -32,12 +35,16 @@ public function process(\DOMElement $mediaNode, $mediaParentTag)
continue;
}
$attributeTagName = $attribute->tagName;
- if ($attributeTagName === 'background') {
- $nodeValue = $this->processImageBackground($attribute->nodeValue);
- } elseif ($attributeTagName === 'width' || $attributeTagName === 'height') {
- $nodeValue = intval($attribute->nodeValue);
+ if ((bool)$attribute->getAttribute('xsi:nil') !== true) {
+ if ($attributeTagName === 'background') {
+ $nodeValue = $this->processImageBackground($attribute->nodeValue);
+ } elseif ($attributeTagName === 'width' || $attributeTagName === 'height') {
+ $nodeValue = (int) $attribute->nodeValue;
+ } else {
+ $nodeValue = $attribute->nodeValue;
+ }
} else {
- $nodeValue = !in_array($attribute->nodeValue, ['false', '0']);
+ $nodeValue = null;
}
$result[$mediaParentTag][$moduleNameImage][Image::MEDIA_TYPE_CONFIG_NODE][$imageId][$attribute->tagName]
= $nodeValue;
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php
index 4b16a4810c0ae..8b952ca844bb9 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php
@@ -7,7 +7,6 @@
namespace Magento\Catalog\Model\Indexer\Category\Flat;
use Magento\Framework\App\ResourceConnection;
-use Magento\Framework\EntityManager\MetadataPool;
class AbstractAction
{
@@ -111,7 +110,7 @@ public function getColumns()
public function getMainStoreTable($storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID)
{
if (is_string($storeId)) {
- $storeId = intval($storeId);
+ $storeId = (int) $storeId;
}
$suffix = sprintf('store_%d', $storeId);
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php
index 9f4e19bf95a8d..005936a75e6d6 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php
@@ -97,7 +97,7 @@ protected function validate(AbstractModel $group)
public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $storeGroup)
{
foreach ($storeGroup->getStores() as $store) {
- $this->tableMaintainer->dropTablesForStore($store->getId());
+ $this->tableMaintainer->dropTablesForStore((int)$store->getId());
}
return $objectResource;
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php
index 114d2a94f5b35..b6f9e6adf4a1c 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreView.php
@@ -51,7 +51,7 @@ public function afterSave(AbstractDb $subject, AbstractDb $objectResource, Abstr
*/
public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $store)
{
- $this->tableMaintainer->dropTablesForStore($store->getId());
+ $this->tableMaintainer->dropTablesForStore((int)$store->getId());
return $objectResource;
}
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php
index 387a8085310e4..50700e672237e 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/Website.php
@@ -39,7 +39,7 @@ public function __construct(
public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $website)
{
foreach ($website->getStoreIds() as $storeId) {
- $this->tableMaintainer->dropTablesForStore($storeId);
+ $this->tableMaintainer->dropTablesForStore((int)$storeId);
}
return $objectResource;
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php
index 105a6dbf30456..3c2629bc570f2 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/TableMaintainer.php
@@ -91,6 +91,8 @@ private function getTable($table)
* @param string $newTableName
*
* @return void
+ *
+ * @throws \Zend_Db_Exception
*/
private function createTable($mainTableName, $newTableName)
{
@@ -135,6 +137,8 @@ public function getMainTable(int $storeId)
* @param $storeId
*
* @return void
+ *
+ * @throws \Zend_Db_Exception
*/
public function createTablesForStore(int $storeId)
{
@@ -206,12 +210,12 @@ public function createMainTmpTable(int $storeId)
*
* @return string
*
- * @throws \Exception
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function getMainTmpTable(int $storeId)
{
if (!isset($this->mainTmpTable[$storeId])) {
- throw new \Exception('Temporary table does not exist');
+ throw new \Magento\Framework\Exception\NoSuchEntityException('Temporary table does not exist');
}
return $this->mainTmpTable[$storeId];
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Category/Action/Rows.php b/app/code/Magento/Catalog/Model/Indexer/Product/Category/Action/Rows.php
index 182f04de4ab0e..a218266c25034 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Category/Action/Rows.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Category/Action/Rows.php
@@ -161,7 +161,7 @@ protected function removeEntries()
$this->getIndexTable($store->getId()),
['product_id IN (?)' => $this->limitationByProducts]
);
- };
+ }
}
/**
@@ -228,7 +228,7 @@ private function getCategoryIdsFromIndex(array $productIds)
->distinct()
)
);
- };
+ }
$parentCategories = $categoryIds;
foreach ($categoryIds as $categoryId) {
$parentIds = explode('/', $this->getPathFromCategoryId($categoryId));
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php
index b6206f96b91e0..6101e5cd362e4 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Model\Indexer\Product\Eav;
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\AbstractEav;
@@ -12,6 +14,11 @@
*/
abstract class AbstractAction
{
+ /**
+ * Config path for enable EAV indexer
+ */
+ const ENABLE_EAV_INDEXER = 'catalog/search/enable_eav_indexer';
+
/**
* EAV Indexers by type
*
@@ -29,17 +36,27 @@ abstract class AbstractAction
*/
protected $_eavDecimalFactory;
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface
+ */
+ private $scopeConfig;
+
/**
* AbstractAction constructor.
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface|null $scopeConfig
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory,
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
+ \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory,
+ \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null
) {
$this->_eavDecimalFactory = $eavDecimalFactory;
$this->_eavSourceFactory = $eavSourceFactory;
+ $this->scopeConfig = $scopeConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
+ \Magento\Framework\App\Config\ScopeConfigInterface::class
+ );
}
/**
@@ -92,6 +109,9 @@ public function getIndexer($type)
*/
public function reindex($ids = null)
{
+ if (!$this->isEavIndexerEnabled()) {
+ return;
+ }
foreach ($this->getIndexers() as $indexer) {
if ($ids === null) {
$indexer->reindexAll();
@@ -149,4 +169,19 @@ protected function processRelations(AbstractEav $indexer, array $ids, bool $only
return array_unique(array_merge($ids, $childIds, $parentIds));
}
+
+ /**
+ * Get EAV indexer status
+ *
+ * @return bool
+ */
+ private function isEavIndexerEnabled(): bool
+ {
+ $eavIndexerStatus = $this->scopeConfig->getValue(
+ self::ENABLE_EAV_INDEXER,
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ );
+
+ return (bool)$eavIndexerStatus;
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php
index bc747e62f641e..802176092d147 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Action/Full.php
@@ -3,12 +3,15 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Model\Indexer\Product\Eav\Action;
use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
/**
* Class Full reindex action
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
{
@@ -32,6 +35,11 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
*/
private $activeTableSwitcher;
+ /**
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface
+ */
+ private $scopeConfig;
+
/**
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\SourceFactory $eavSourceFactory
@@ -39,6 +47,7 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Eav\AbstractAction
* @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator
* @param ActiveTableSwitcher|null $activeTableSwitcher
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface|null $scopeConfig
*/
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\DecimalFactory $eavDecimalFactory,
@@ -46,9 +55,13 @@ public function __construct(
\Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
\Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null,
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Eav\BatchSizeCalculator $batchSizeCalculator = null,
- ActiveTableSwitcher $activeTableSwitcher = null
+ ActiveTableSwitcher $activeTableSwitcher = null,
+ \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null
) {
- parent::__construct($eavDecimalFactory, $eavSourceFactory);
+ $this->scopeConfig = $scopeConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
+ \Magento\Framework\App\Config\ScopeConfigInterface::class
+ );
+ parent::__construct($eavDecimalFactory, $eavSourceFactory, $scopeConfig);
$this->metadataPool = $metadataPool ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
\Magento\Framework\EntityManager\MetadataPool::class
);
@@ -73,6 +86,9 @@ public function __construct(
*/
public function execute($ids = null)
{
+ if (!$this->isEavIndexerEnabled()) {
+ return;
+ }
try {
foreach ($this->getIndexers() as $indexerName => $indexer) {
$connection = $indexer->getConnection();
@@ -129,4 +145,19 @@ protected function syncData($indexer, $destinationTable, $ids = null)
throw $e;
}
}
+
+ /**
+ * Get EAV indexer status
+ *
+ * @return bool
+ */
+ private function isEavIndexerEnabled(): bool
+ {
+ $eavIndexerStatus = $this->scopeConfig->getValue(
+ self::ENABLE_EAV_INDEXER,
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ );
+
+ return (bool)$eavIndexerStatus;
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php
index b5dbdb68606ff..709f27d031ebe 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php
@@ -61,6 +61,7 @@ public function __construct(
* @param int|null $id
* @return \Magento\Catalog\Model\Indexer\Product\Flat\Action\Row
* @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Zend_Db_Statement_Exception
*/
public function execute($id = null)
{
@@ -75,17 +76,43 @@ public function execute($id = null)
if ($tableExists) {
$this->flatItemEraser->removeDeletedProducts($ids, $store->getId());
}
- if (isset($ids[0])) {
- if (!$tableExists) {
- $this->_flatTableBuilder->build(
- $store->getId(),
- [$ids[0]],
- $this->_valueFieldSuffix,
- $this->_tableDropSuffix,
- false
- );
+
+ /* @var $status \Magento\Eav\Model\Entity\Attribute */
+ $status = $this->_productIndexerHelper->getAttribute('status');
+ $statusTable = $status->getBackend()->getTable();
+ $statusConditions = [
+ 'store_id IN(0,' . (int)$store->getId() . ')',
+ 'attribute_id = ' . (int)$status->getId(),
+ 'entity_id = ' . (int)$id
+ ];
+ $select = $this->_connection->select();
+ $select->from(
+ $statusTable,
+ ['value']
+ )->where(
+ implode(' AND ', $statusConditions)
+ )->order(
+ 'store_id DESC'
+ );
+ $result = $this->_connection->query($select);
+ $status = $result->fetch(1);
+
+ if ($status['value'] == \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) {
+ if (isset($ids[0])) {
+ if (!$tableExists) {
+ $this->_flatTableBuilder->build(
+ $store->getId(),
+ [$ids[0]],
+ $this->_valueFieldSuffix,
+ $this->_tableDropSuffix,
+ false
+ );
+ }
+ $this->flatItemWriter->write($store->getId(), $ids[0], $this->_valueFieldSuffix);
}
- $this->flatItemWriter->write($store->getId(), $ids[0], $this->_valueFieldSuffix);
+ }
+ if ($status['value'] == \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED) {
+ $this->flatItemEraser->deleteProductsFromStore($id, $store->getId());
}
}
return $this;
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php
index 7aed842713f5d..e9a907f0b5097 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php
@@ -5,7 +5,11 @@
*/
namespace Magento\Catalog\Model\Indexer\Product\Price;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Indexer\DimensionalIndexerInterface;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
/**
* Abstract action reindex class
@@ -17,7 +21,7 @@ abstract class AbstractAction
/**
* Default Product Type Price indexer resource model
*
- * @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice
+ * @var DefaultPrice
*/
protected $_defaultIndexerResource;
@@ -77,6 +81,16 @@ abstract class AbstractAction
*/
private $tierPriceIndexResource;
+ /**
+ * @var \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory
+ */
+ private $dimensionCollectionFactory;
+
+ /**
+ * @var TableMaintainer
+ */
+ private $tableMaintainer;
+
/**
* @param \Magento\Framework\App\Config\ScopeConfigInterface $config
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -85,8 +99,13 @@ abstract class AbstractAction
* @param \Magento\Framework\Stdlib\DateTime $dateTime
* @param \Magento\Catalog\Model\Product\Type $catalogProductType
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory
- * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource
- * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice $tierPriceIndexResource
+ * @param DefaultPrice $defaultIndexerResource
+ * @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice|null $tierPriceIndexResource
+ * @param DimensionCollectionFactory|null $dimensionCollectionFactory
+ * @param TableMaintainer|null $tableMaintainer
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Framework\App\Config\ScopeConfigInterface $config,
@@ -96,8 +115,10 @@ public function __construct(
\Magento\Framework\Stdlib\DateTime $dateTime,
\Magento\Catalog\Model\Product\Type $catalogProductType,
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Factory $indexerPriceFactory,
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $defaultIndexerResource,
- \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice $tierPriceIndexResource = null
+ DefaultPrice $defaultIndexerResource,
+ \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice $tierPriceIndexResource = null,
+ \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory = null,
+ \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $tableMaintainer = null
) {
$this->_config = $config;
$this->_storeManager = $storeManager;
@@ -108,9 +129,15 @@ public function __construct(
$this->_indexerPriceFactory = $indexerPriceFactory;
$this->_defaultIndexerResource = $defaultIndexerResource;
$this->_connection = $this->_defaultIndexerResource->getConnection();
- $this->tierPriceIndexResource = $tierPriceIndexResource ?: ObjectManager::getInstance()->get(
+ $this->tierPriceIndexResource = $tierPriceIndexResource ?? ObjectManager::getInstance()->get(
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\TierPrice::class
);
+ $this->dimensionCollectionFactory = $dimensionCollectionFactory ?? ObjectManager::getInstance()->get(
+ \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class
+ );
+ $this->tableMaintainer = $tableMaintainer ?? ObjectManager::getInstance()->get(
+ \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer::class
+ );
}
/**
@@ -126,30 +153,29 @@ abstract public function execute($ids);
*
* @param array $processIds
* @return \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @deprecated Used only for backward compatibility for indexer, which not support indexation by dimensions
*/
protected function _syncData(array $processIds = [])
{
- // delete invalid rows
- $select = $this->_connection->select()->from(
- ['index_price' => $this->getIndexTargetTable()],
- null
- )->joinLeft(
- ['ip_tmp' => $this->_defaultIndexerResource->getIdxTable()],
- 'index_price.entity_id = ip_tmp.entity_id AND index_price.website_id = ip_tmp.website_id',
- []
- )->where(
- 'ip_tmp.entity_id IS NULL'
- );
- if (!empty($processIds)) {
- $select->where('index_price.entity_id IN(?)', $processIds);
- }
- $sql = $select->deleteFromSelect('index_price');
- $this->_connection->query($sql);
+ // for backward compatibility split data from old idx table on dimension tables
+ foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
+ $insertSelect = $this->getConnection()->select()->from(
+ ['ip_tmp' => $this->_defaultIndexerResource->getIdxTable()]
+ );
- $this->_insertFromTable(
- $this->_defaultIndexerResource->getIdxTable(),
- $this->getIndexTargetTable()
- );
+ foreach ($dimensions as $dimension) {
+ if ($dimension->getName() === WebsiteDimensionProvider::DIMENSION_NAME) {
+ $insertSelect->where('ip_tmp.website_id = ?', $dimension->getValue());
+ }
+ if ($dimension->getName() === CustomerGroupDimensionProvider::DIMENSION_NAME) {
+ $insertSelect->where('ip_tmp.customer_group_id = ?', $dimension->getValue());
+ }
+ }
+
+ $query = $insertSelect->insertFromSelect($this->tableMaintainer->getMainTable($dimensions));
+ $this->getConnection()->query($query);
+ }
return $this;
}
@@ -157,12 +183,15 @@ protected function _syncData(array $processIds = [])
* Prepare website current dates table
*
* @return \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
+ *
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
*/
protected function _prepareWebsiteDateTable()
{
$baseCurrency = $this->_config->getValue(\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE);
- $select = $this->_connection->select()->from(
+ $select = $this->getConnection()->select()->from(
['cw' => $this->_defaultIndexerResource->getTable('store_website')],
['website_id']
)->join(
@@ -174,7 +203,7 @@ protected function _prepareWebsiteDateTable()
);
$data = [];
- foreach ($this->_connection->fetchAll($select) as $item) {
+ foreach ($this->getConnection()->fetchAll($select) as $item) {
/** @var $website \Magento\Store\Model\Website */
$website = $this->_storeManager->getWebsite($item['website_id']);
@@ -199,6 +228,7 @@ protected function _prepareWebsiteDateTable()
'website_id' => $website->getId(),
'website_date' => $this->_dateTime->formatDate($timestamp, false),
'rate' => $rate,
+ 'default_store_id' => $store->getId()
];
}
}
@@ -207,7 +237,7 @@ protected function _prepareWebsiteDateTable()
$this->_emptyTable($table);
if ($data) {
foreach ($data as $row) {
- $this->_connection->insertOnDuplicate($table, $row, array_keys($row));
+ $this->getConnection()->insertOnDuplicate($table, $row, array_keys($row));
}
}
@@ -230,9 +260,13 @@ protected function _prepareTierPriceIndex($entityIds = null)
/**
* Retrieve price indexers per product type
*
+ * @param bool $fullReindexAction
+ *
* @return \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface[]
+ *
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
- public function getTypeIndexers()
+ public function getTypeIndexers($fullReindexAction = false)
{
if ($this->_indexers === null) {
$this->_indexers = [];
@@ -242,14 +276,20 @@ public function getTypeIndexers()
$typeInfo['price_indexer']
) ? $typeInfo['price_indexer'] : get_class($this->_defaultIndexerResource);
- $isComposite = !empty($typeInfo['composite']);
$indexer = $this->_indexerPriceFactory->create(
- $modelName
- )->setTypeId(
- $typeId
- )->setIsComposite(
- $isComposite
+ $modelName,
+ [
+ 'fullReindexAction' => $fullReindexAction
+ ]
);
+ // left setters for backward compatibility
+ if ($indexer instanceof DefaultPrice) {
+ $indexer->setTypeId(
+ $typeId
+ )->setIsComposite(
+ !empty($typeInfo['composite'])
+ );
+ }
$this->_indexers[$typeId] = $indexer;
}
}
@@ -262,7 +302,9 @@ public function getTypeIndexers()
*
* @param string $productTypeId
* @return \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface
+ *
* @throws \Magento\Framework\Exception\InputException
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
protected function _getIndexer($productTypeId)
{
@@ -283,19 +325,19 @@ protected function _getIndexer($productTypeId)
*/
protected function _insertFromTable($sourceTable, $destTable, $where = null)
{
- $sourceColumns = array_keys($this->_connection->describeTable($sourceTable));
- $targetColumns = array_keys($this->_connection->describeTable($destTable));
- $select = $this->_connection->select()->from($sourceTable, $sourceColumns);
+ $sourceColumns = array_keys($this->getConnection()->describeTable($sourceTable));
+ $targetColumns = array_keys($this->getConnection()->describeTable($destTable));
+ $select = $this->getConnection()->select()->from($sourceTable, $sourceColumns);
if ($where) {
$select->where($where);
}
- $query = $this->_connection->insertFromSelect(
+ $query = $this->getConnection()->insertFromSelect(
$select,
$destTable,
$targetColumns,
\Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
);
- $this->_connection->query($query);
+ $this->getConnection()->query($query);
}
/**
@@ -306,7 +348,7 @@ protected function _insertFromTable($sourceTable, $destTable, $where = null)
*/
protected function _emptyTable($table)
{
- $this->_connection->delete($table);
+ $this->getConnection()->delete($table);
}
/**
@@ -314,46 +356,64 @@ protected function _emptyTable($table)
*
* @param array $changedIds
* @return array Affected ids
+ *
+ * @throws \Magento\Framework\Exception\InputException
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
*/
protected function _reindexRows($changedIds = [])
{
- $this->_emptyTable($this->_defaultIndexerResource->getIdxTable());
$this->_prepareWebsiteDateTable();
$productsTypes = $this->getProductsTypes($changedIds);
- $compositeIds = [];
- $notCompositeIds = [];
+ $parentProductsTypes = $this->getParentProductsTypes($changedIds);
+ $changedIds = array_merge($changedIds, ...array_values($parentProductsTypes));
+ $productsTypes = array_merge_recursive($productsTypes, $parentProductsTypes);
+
+ if ($changedIds) {
+ $this->deleteIndexData($changedIds);
+ }
foreach ($productsTypes as $productType => $entityIds) {
$indexer = $this->_getIndexer($productType);
- if ($indexer->getIsComposite()) {
- $compositeIds += $entityIds;
+ if ($indexer instanceof DimensionalIndexerInterface) {
+ foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
+ $this->tableMaintainer->createMainTmpTable($dimensions);
+ $temporaryTable = $this->tableMaintainer->getMainTmpTable($dimensions);
+ $this->_emptyTable($temporaryTable);
+ $indexer->executeByDimensions($dimensions, \SplFixedArray::fromArray($entityIds, false));
+ // copy to index
+ $this->_insertFromTable(
+ $temporaryTable,
+ $this->tableMaintainer->getMainTable($dimensions)
+ );
+ }
} else {
- $notCompositeIds += $entityIds;
+ // handle 3d-party indexers for backward compatibility
+ $this->_emptyTable($this->_defaultIndexerResource->getIdxTable());
+ $this->_copyRelationIndexData($entityIds);
+ $indexer->reindexEntity($entityIds);
+ $this->_syncData($entityIds);
}
}
- if (!empty($notCompositeIds)) {
- $parentProductsTypes = $this->getParentProductsTypes($notCompositeIds);
- $productsTypes = array_merge_recursive($productsTypes, $parentProductsTypes);
- foreach ($parentProductsTypes as $parentProductsIds) {
- $compositeIds = $compositeIds + $parentProductsIds;
- $changedIds = array_merge($changedIds, $parentProductsIds);
- }
- }
-
- if (!empty($compositeIds)) {
- $this->_copyRelationIndexData($compositeIds, $notCompositeIds);
- }
- $this->_prepareTierPriceIndex($compositeIds + $notCompositeIds);
+ return $changedIds;
+ }
- foreach ($productsTypes as $productType => $entityIds) {
- $indexer = $this->_getIndexer($productType);
- $indexer->reindexEntity($entityIds);
+ /**
+ * @param array $entityIds
+ * @return void
+ */
+ private function deleteIndexData(array $entityIds)
+ {
+ foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
+ $select = $this->getConnection()->select()->from(
+ ['index_price' => $this->tableMaintainer->getMainTable($dimensions)],
+ null
+ )->where('index_price.entity_id IN (?)', $entityIds);
+ $query = $select->deleteFromSelect('index_price');
+ $this->getConnection()->query($query);
}
- $this->_syncData($changedIds);
-
- return $compositeIds + $notCompositeIds;
}
/**
@@ -362,11 +422,15 @@ protected function _reindexRows($changedIds = [])
* @param null|array $parentIds
* @param array $excludeIds
* @return \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
+ * @deprecated Used only for backward compatibility for do not broke custom indexer implementation
+ * which do not work by dimensions.
+ * For indexers, which support dimensions all composite products read data directly from main price indexer table
+ * or replica table for partial or full reindex correspondingly.
*/
protected function _copyRelationIndexData($parentIds, $excludeIds = null)
{
$linkField = $this->getProductIdFieldName();
- $select = $this->_connection->select()->from(
+ $select = $this->getConnection()->select()->from(
$this->_defaultIndexerResource->getTable('catalog_product_relation'),
['child_id']
)->join(
@@ -381,22 +445,45 @@ protected function _copyRelationIndexData($parentIds, $excludeIds = null)
$select->where('child_id NOT IN(?)', $excludeIds);
}
- $children = $this->_connection->fetchCol($select);
+ $children = $this->getConnection()->fetchCol($select);
if ($children) {
- $select = $this->_connection->select()->from(
- $this->getIndexTargetTable()
- )->where(
- 'entity_id IN(?)',
- $children
- );
- $query = $select->insertFromSelect($this->_defaultIndexerResource->getIdxTable(), [], false);
- $this->_connection->query($query);
+ foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
+ $select = $this->getConnection()->select()->from(
+ $this->getIndexTargetTableByDimension($dimensions)
+ )->where(
+ 'entity_id IN(?)',
+ $children
+ );
+ $query = $select->insertFromSelect($this->_defaultIndexerResource->getIdxTable(), [], false);
+ $this->getConnection()->query($query);
+ }
}
return $this;
}
+ /**
+ * Retrieve index table by dimension that will be used for write operations.
+ *
+ * This method is used during both partial and full reindex to identify the table.
+ *
+ * @param \Magento\Framework\Search\Request\Dimension[] $dimensions
+ *
+ * @return string
+ */
+ private function getIndexTargetTableByDimension(array $dimensions)
+ {
+ $indexTargetTable = $this->getIndexTargetTable();
+ if ($indexTargetTable === self::getIndexTargetTable()) {
+ $indexTargetTable = $this->tableMaintainer->getMainTable($dimensions);
+ }
+ if ($indexTargetTable === self::getIndexTargetTable() . '_replica') {
+ $indexTargetTable = $this->tableMaintainer->getMainReplicaTable($dimensions);
+ }
+ return $indexTargetTable;
+ }
+
/**
* Retrieve index table that will be used for write operations.
*
@@ -415,8 +502,8 @@ protected function getIndexTargetTable()
protected function getProductIdFieldName()
{
$table = $this->_defaultIndexerResource->getTable('catalog_product_entity');
- $indexList = $this->_connection->getIndexList($table);
- return $indexList[$this->_connection->getPrimaryKeyName($table)]['COLUMNS_LIST'][0];
+ $indexList = $this->getConnection()->getIndexList($table);
+ return $indexList[$this->getConnection()->getPrimaryKeyName($table)]['COLUMNS_LIST'][0];
}
/**
@@ -427,14 +514,14 @@ protected function getProductIdFieldName()
*/
private function getProductsTypes(array $changedIds = [])
{
- $select = $this->_connection->select()->from(
+ $select = $this->getConnection()->select()->from(
$this->_defaultIndexerResource->getTable('catalog_product_entity'),
['entity_id', 'type_id']
);
if ($changedIds) {
$select->where('entity_id IN (?)', $changedIds);
}
- $pairs = $this->_connection->fetchPairs($select);
+ $pairs = $this->getConnection()->fetchPairs($select);
$byType = [];
foreach ($pairs as $productId => $productType) {
@@ -445,14 +532,15 @@ private function getProductsTypes(array $changedIds = [])
}
/**
- * Get parent products types.
+ * Get parent products types
+ * Used for add composite products to reindex if we have only simple products in changed ids set
*
* @param array $productsIds
* @return array
*/
private function getParentProductsTypes(array $productsIds)
{
- $select = $this->_connection->select()->from(
+ $select = $this->getConnection()->select()->from(
['l' => $this->_defaultIndexerResource->getTable('catalog_product_relation')],
''
)->join(
@@ -463,7 +551,7 @@ private function getParentProductsTypes(array $productsIds)
'l.child_id IN(?)',
$productsIds
);
- $pairs = $this->_connection->fetchPairs($select);
+ $pairs = $this->getConnection()->fetchPairs($select);
$byType = [];
foreach ($pairs as $productId => $productType) {
@@ -472,4 +560,14 @@ private function getParentProductsTypes(array $productsIds)
return $byType;
}
+
+ /**
+ * Get connection
+ *
+ * @return \Magento\Framework\DB\Adapter\AdapterInterface
+ */
+ private function getConnection()
+ {
+ return $this->_defaultIndexerResource->getConnection();
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php
index ba04af8ec1f41..1a75751570658 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php
@@ -6,9 +6,17 @@
namespace Magento\Catalog\Model\Indexer\Product\Price\Action;
use Magento\Framework\App\ObjectManager;
+use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceInterface;
+use Magento\Framework\EntityManager\EntityMetadataInterface;
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Indexer\DimensionalIndexerInterface;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
/**
* Class Full reindex action
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
@@ -33,6 +41,26 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
*/
private $activeTableSwitcher;
+ /**
+ * @var EntityMetadataInterface
+ */
+ private $productMetaDataCached;
+
+ /**
+ * @var \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory
+ */
+ private $dimensionCollectionFactory;
+
+ /**
+ * @var \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer
+ */
+ private $dimensionTableMaintainer;
+
+ /**
+ * @var \Magento\Indexer\Model\ProcessManager
+ */
+ private $processManager;
+
/**
* @param \Magento\Framework\App\Config\ScopeConfigInterface $config
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -46,7 +74,9 @@ class Full extends \Magento\Catalog\Model\Indexer\Product\Price\AbstractAction
* @param \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator|null $batchSizeCalculator
* @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider
* @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
- *
+ * @param \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory|null $dimensionCollectionFactory
+ * @param \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer|null $dimensionTableMaintainer
+ * @param \Magento\Indexer\Model\ProcessManager $processManager
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -61,7 +91,10 @@ public function __construct(
\Magento\Framework\EntityManager\MetadataPool $metadataPool = null,
\Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BatchSizeCalculator $batchSizeCalculator = null,
\Magento\Framework\Indexer\BatchProviderInterface $batchProvider = null,
- \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null
+ \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null,
+ \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory $dimensionCollectionFactory = null,
+ \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer $dimensionTableMaintainer = null,
+ \Magento\Indexer\Model\ProcessManager $processManager = null
) {
parent::__construct(
$config,
@@ -85,6 +118,15 @@ public function __construct(
$this->activeTableSwitcher = $activeTableSwitcher ?: ObjectManager::getInstance()->get(
\Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
);
+ $this->dimensionCollectionFactory = $dimensionCollectionFactory ?: ObjectManager::getInstance()->get(
+ \Magento\Catalog\Model\Indexer\Product\Price\DimensionCollectionFactory::class
+ );
+ $this->dimensionTableMaintainer = $dimensionTableMaintainer ?: ObjectManager::getInstance()->get(
+ \Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer::class
+ );
+ $this->processManager = $processManager ?: ObjectManager::getInstance()->get(
+ \Magento\Indexer\Model\ProcessManager::class
+ );
}
/**
@@ -92,75 +134,335 @@ public function __construct(
*
* @param array|int|null $ids
* @return void
- * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Exception
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function execute($ids = null)
{
try {
- $this->_defaultIndexerResource->getTableStrategy()->setUseIdxTable(false);
- $this->_prepareWebsiteDateTable();
+ //Prepare indexer tables before full reindex
+ $this->prepareTables();
+
+ /** @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $indexer */
+ foreach ($this->getTypeIndexers(true) as $typeId => $priceIndexer) {
+ if ($priceIndexer instanceof DimensionalIndexerInterface) {
+ //New price reindex mechanism
+ $this->reindexProductTypeWithDimensions($priceIndexer, $typeId);
+ continue;
+ }
+
+ $priceIndexer->getTableStrategy()->setUseIdxTable(false);
+
+ //Old price reindex mechanism
+ $this->reindexProductType($priceIndexer, $typeId);
+ }
+
+ //Final replacement of tables from replica to main
+ $this->switchTables();
+ } catch (\Exception $e) {
+ throw new LocalizedException(__($e->getMessage()), $e);
+ }
+ }
+
+ /**
+ * Prepare indexer tables before full reindex
+ *
+ * @return void
+ * @throws \Exception
+ */
+ private function prepareTables()
+ {
+ $this->_defaultIndexerResource->getTableStrategy()->setUseIdxTable(false);
+
+ $this->_prepareWebsiteDateTable();
+
+ $this->truncateReplicaTables();
+ }
+
+ /**
+ * Truncate replica tables by dimensions
+ *
+ * @return void
+ * @throws \Exception
+ */
+ private function truncateReplicaTables()
+ {
+ foreach ($this->dimensionCollectionFactory->create() as $dimension) {
+ $dimensionTable = $this->dimensionTableMaintainer->getMainReplicaTable($dimension);
+ $this->_defaultIndexerResource->getConnection()->truncateTable($dimensionTable);
+ }
+ }
+
+ /**
+ * Reindex new 'Dimensional' price indexer by product type
+ *
+ * @param DimensionalIndexerInterface $priceIndexer
+ * @param string $typeId
+ *
+ * @return void
+ * @throws \Exception
+ */
+ private function reindexProductTypeWithDimensions(DimensionalIndexerInterface $priceIndexer, string $typeId)
+ {
+ $userFunctions = [];
+ foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
+ $userFunctions[] = function () use ($priceIndexer, $dimensions, $typeId) {
+ return $this->reindexByBatches($priceIndexer, $dimensions, $typeId);
+ };
+ }
+ $this->processManager->execute($userFunctions);
+ }
+
+ /**
+ * Reindex new 'Dimensional' price indexer by batches
+ *
+ * @param DimensionalIndexerInterface $priceIndexer
+ * @param array $dimensions
+ * @param string $typeId
+ *
+ * @return void
+ * @throws \Exception
+ */
+ private function reindexByBatches(DimensionalIndexerInterface $priceIndexer, array $dimensions, string $typeId)
+ {
+ foreach ($this->getBatchesForIndexer($typeId) as $batch) {
+ $this->reindexByBatchWithDimensions($priceIndexer, $batch, $dimensions, $typeId);
+ }
+ }
+
+ /**
+ * Get batches for new 'Dimensional' price indexer
+ *
+ * @param string $typeId
+ *
+ * @return \Generator
+ * @throws \Exception
+ */
+ private function getBatchesForIndexer(string $typeId)
+ {
+ $connection = $this->_defaultIndexerResource->getConnection();
+ return $this->batchProvider->getBatches(
+ $connection,
+ $this->getProductMetaData()->getEntityTable(),
+ $this->getProductMetaData()->getIdentifierField(),
+ $this->batchSizeCalculator->estimateBatchSize(
+ $connection,
+ $typeId
+ )
+ );
+ }
+
+ /**
+ * Reindex by batch for new 'Dimensional' price indexer
+ *
+ * @param DimensionalIndexerInterface $priceIndexer
+ * @param array $batch
+ * @param array $dimensions
+ * @param string $typeId
+ *
+ * @return void
+ * @throws \Exception
+ */
+ private function reindexByBatchWithDimensions(
+ DimensionalIndexerInterface $priceIndexer,
+ array $batch,
+ array $dimensions,
+ string $typeId
+ ) {
+ $entityIds = $this->getEntityIdsFromBatch($typeId, $batch);
+
+ if (!empty($entityIds)) {
+ $this->dimensionTableMaintainer->createMainTmpTable($dimensions);
+ $temporaryTable = $this->dimensionTableMaintainer->getMainTmpTable($dimensions);
+ $this->_emptyTable($temporaryTable);
+
+ $priceIndexer->executeByDimensions($dimensions, \SplFixedArray::fromArray($entityIds, false));
- $entityMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
- $replicaTable = $this->activeTableSwitcher->getAdditionalTableName(
- $this->_defaultIndexerResource->getMainTable()
+ // Sync data from temp table to index table
+ $this->_insertFromTable(
+ $temporaryTable,
+ $this->dimensionTableMaintainer->getMainReplicaTable($dimensions)
);
+ }
+ }
- // Prepare replica table for indexation.
- $this->_defaultIndexerResource->getConnection()->truncateTable($replicaTable);
+ /**
+ * Reindex old price indexer by product type
+ *
+ * @param PriceInterface $priceIndexer
+ * @param string $typeId
+ *
+ * @return void
+ * @throws \Exception
+ */
+ private function reindexProductType(PriceInterface $priceIndexer, string $typeId)
+ {
+ foreach ($this->getBatchesForIndexer($typeId) as $batch) {
+ $this->reindexBatch($priceIndexer, $batch, $typeId);
+ }
+ }
- /** @var \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice $indexer */
- foreach ($this->getTypeIndexers() as $indexer) {
- $indexer->getTableStrategy()->setUseIdxTable(false);
- $connection = $indexer->getConnection();
-
- $batches = $this->batchProvider->getBatches(
- $connection,
- $entityMetadata->getEntityTable(),
- $entityMetadata->getIdentifierField(),
- $this->batchSizeCalculator->estimateBatchSize($connection, $indexer->getTypeId())
- );
-
- foreach ($batches as $batch) {
- // Get entity ids from batch
- $select = $connection->select();
- $select->distinct(true);
- $select->from(['e' => $entityMetadata->getEntityTable()], $entityMetadata->getIdentifierField());
- $select->where('type_id = ?', $indexer->getTypeId());
-
- $entityIds = $this->batchProvider->getBatchIds($connection, $select, $batch);
-
- if (!empty($entityIds)) {
- // Temporary table will created if not exists
- $idxTableName = $this->_defaultIndexerResource->getIdxTable();
- $this->_emptyTable($idxTableName);
-
- if ($indexer->getIsComposite()) {
- $this->_copyRelationIndexData($entityIds);
- }
- $this->_prepareTierPriceIndex($entityIds);
-
- // Reindex entities by id
- $indexer->reindexEntity($entityIds);
-
- // Sync data from temp table to index table
- $this->_insertFromTable($idxTableName, $replicaTable);
-
- // Drop temporary index table
- $connection->dropTable($idxTableName);
- }
- }
+ /**
+ * Reindex by batch for old price indexer
+ *
+ * @param PriceInterface $priceIndexer
+ * @param array $batch
+ * @param string $typeId
+ *
+ * @return void
+ * @throws \Exception
+ */
+ private function reindexBatch(PriceInterface $priceIndexer, array $batch, string $typeId)
+ {
+ $entityIds = $this->getEntityIdsFromBatch($typeId, $batch);
+
+ if (!empty($entityIds)) {
+ // Temporary table will created if not exists
+ $idxTableName = $this->_defaultIndexerResource->getIdxTable();
+ $this->_emptyTable($idxTableName);
+
+ if ($priceIndexer->getIsComposite()) {
+ $this->_copyRelationIndexData($entityIds);
}
+
+ // Reindex entities by id
+ $priceIndexer->reindexEntity($entityIds);
+
+ // Sync data from temp table to index table
+ $this->_insertFromTable($idxTableName, $this->getReplicaTable());
+
+ // Drop temporary index table
+ $this->_defaultIndexerResource->getConnection()->dropTable($idxTableName);
+ }
+ }
+
+ /**
+ * Get Entity Ids from batch
+ *
+ * @param string $typeId
+ * @param array $batch
+ *
+ * @return array
+ * @throws \Exception
+ */
+ private function getEntityIdsFromBatch(string $typeId, array $batch)
+ {
+ $connection = $this->_defaultIndexerResource->getConnection();
+
+ // Get entity ids from batch
+ $select = $connection
+ ->select()
+ ->distinct(true)
+ ->from(
+ ['e' => $this->getProductMetaData()->getEntityTable()],
+ $this->getProductMetaData()->getIdentifierField()
+ )
+ ->where('type_id = ?', $typeId);
+
+ return $this->batchProvider->getBatchIds($connection, $select, $batch);
+ }
+
+ /**
+ * Get product meta data
+ *
+ * @return EntityMetadataInterface
+ * @throws \Exception
+ */
+ private function getProductMetaData()
+ {
+ if ($this->productMetaDataCached === null) {
+ $this->productMetaDataCached = $this->metadataPool->getMetadata(ProductInterface::class);
+ }
+
+ return $this->productMetaDataCached;
+ }
+
+ /**
+ * Get replica table
+ *
+ * @return string
+ * @throws \Exception
+ */
+ private function getReplicaTable()
+ {
+ return $this->activeTableSwitcher->getAdditionalTableName(
+ $this->_defaultIndexerResource->getMainTable()
+ );
+ }
+
+ /**
+ * Replacement of tables from replica to main
+ *
+ * @return void
+ */
+ private function switchTables()
+ {
+ // Switch dimension tables
+ $mainTablesByDimension = [];
+
+ foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
+ $mainTablesByDimension[] = $this->dimensionTableMaintainer->getMainTable($dimensions);
+
+ //Move data from indexers with old realisation
+ $this->moveDataFromReplicaTableToReplicaTables($dimensions);
+ }
+
+ if (count($mainTablesByDimension) > 0) {
$this->activeTableSwitcher->switchTable(
$this->_defaultIndexerResource->getConnection(),
- [$this->_defaultIndexerResource->getMainTable()]
+ $mainTablesByDimension
);
- } catch (\Exception $e) {
- throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()), $e);
}
}
/**
+ * Move data from old price indexer mechanism to new indexer mechanism by dimensions.
+ * Used only for backward compatibility
+ *
+ * @param array $dimensions
+ *
+ * @return void
+ */
+ private function moveDataFromReplicaTableToReplicaTables(array $dimensions)
+ {
+ if (!$dimensions) {
+ return;
+ }
+ $select = $this->dimensionTableMaintainer->getConnection()->select()->from(
+ $this->dimensionTableMaintainer->getMainReplicaTable([])
+ );
+
+ $check = clone $select;
+ $check->reset('columns')->columns('count(*)');
+
+ if (!$this->dimensionTableMaintainer->getConnection()->query($check)->fetchColumn()) {
+ return;
+ }
+
+ $replicaTablesByDimension = $this->dimensionTableMaintainer->getMainReplicaTable($dimensions);
+
+ foreach ($dimensions as $dimension) {
+ if ($dimension->getName() === WebsiteDimensionProvider::DIMENSION_NAME) {
+ $select->where('website_id = ?', $dimension->getValue());
+ }
+ if ($dimension->getName() === CustomerGroupDimensionProvider::DIMENSION_NAME) {
+ $select->where('customer_group_id = ?', $dimension->getValue());
+ }
+ }
+
+ $this->dimensionTableMaintainer->getConnection()->query(
+ $this->dimensionTableMaintainer->getConnection()->insertFromSelect(
+ $select,
+ $replicaTablesByDimension,
+ [],
+ \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
+ )
+ );
+ }
+
+ /**
+ * @deprecated
+ *
* @inheritdoc
*/
protected function getIndexTargetTable()
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionCollectionFactory.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionCollectionFactory.php
new file mode 100644
index 0000000000000..31459af81ccc7
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionCollectionFactory.php
@@ -0,0 +1,72 @@
+multiDimensionProviderFactory = $multiDimensionProviderFactory;
+ $this->dimensionProviders = $dimensionProviders;
+ $this->dimensionModeConfiguration = $dimensionModeConfiguration;
+ }
+
+ /**
+ * Create MultiDimensionProvider for specified "dimension mode".
+ * By default return multiplication of dimensions by current set mode
+ *
+ * @param string|null $dimensionsMode
+ * @return MultiDimensionProvider
+ */
+ public function create(string $dimensionsMode = null): MultiDimensionProvider
+ {
+ $dimensionConfiguration = $this->dimensionModeConfiguration->getDimensionConfiguration($dimensionsMode);
+
+ $providers = [];
+ foreach ($dimensionConfiguration as $dimensionName) {
+ if (!isset($this->dimensionProviders[$dimensionName])) {
+ throw new \LogicException(
+ 'Dimension Provider is missing. Cannot handle unknown dimension: ' . $dimensionName
+ );
+ }
+ $providers[] = clone $this->dimensionProviders[$dimensionName];
+ }
+
+ return $this->multiDimensionProviderFactory->create(
+ [
+ 'dimensionProviders' => $providers
+ ]
+ );
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionModeConfiguration.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionModeConfiguration.php
new file mode 100644
index 0000000000000..7a4d8e313462d
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/DimensionModeConfiguration.php
@@ -0,0 +1,102 @@
+ [
+ ],
+ self::DIMENSION_WEBSITE => [
+ WebsiteDimensionProvider::DIMENSION_NAME
+ ],
+ self::DIMENSION_CUSTOMER_GROUP => [
+ CustomerGroupDimensionProvider::DIMENSION_NAME
+ ],
+ self::DIMENSION_WEBSITE_AND_CUSTOMER_GROUP => [
+ WebsiteDimensionProvider::DIMENSION_NAME,
+ CustomerGroupDimensionProvider::DIMENSION_NAME
+ ],
+ ];
+
+ /**
+ * @var ScopeConfigInterface
+ */
+ private $scopeConfig;
+
+ /**
+ * @var string
+ */
+ private $currentMode;
+
+ /**
+ * @param ScopeConfigInterface $scopeConfig
+ */
+ public function __construct(ScopeConfigInterface $scopeConfig)
+ {
+ $this->scopeConfig = $scopeConfig;
+ }
+
+ /**
+ * Return dimension modes configuration.
+ *
+ * @return array
+ */
+ public function getDimensionModes(): array
+ {
+ return $this->modesMapping;
+ }
+
+ /**
+ * Get names of dimensions which used for provided mode.
+ * By default return dimensions for current enabled mode
+ *
+ * @param string|null $mode
+ * @return string[]
+ * @throws \InvalidArgumentException
+ */
+ public function getDimensionConfiguration(string $mode = null): array
+ {
+ if ($mode && !isset($this->modesMapping[$mode])) {
+ throw new \InvalidArgumentException(
+ sprintf('Undefined dimension mode "%s".', $mode)
+ );
+ }
+ return $this->modesMapping[$mode ?? $this->getCurrentMode()];
+ }
+
+ /**
+ * @return string
+ */
+ private function getCurrentMode(): string
+ {
+ if (null === $this->currentMode) {
+ $this->currentMode = $this->scopeConfig->getValue(ModeSwitcherConfiguration::XML_PATH_PRICE_DIMENSIONS_MODE)
+ ?: self::DIMENSION_NONE;
+ }
+
+ return $this->currentMode;
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcher.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcher.php
new file mode 100644
index 0000000000000..c418f2e1f253b
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcher.php
@@ -0,0 +1,211 @@
+tableMaintainer = $tableMaintainer;
+ $this->dimensionCollectionFactory = $dimensionCollectionFactory;
+ $this->dimensionModeConfiguration = $dimensionModeConfiguration;
+ $this->modeSwitcherConfiguration = $modeSwitcherConfiguration;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getDimensionModes(): DimensionModes
+ {
+ $dimensionsList = [];
+ foreach ($this->dimensionModeConfiguration->getDimensionModes() as $dimension => $modes) {
+ $dimensionsList[] = new DimensionMode($dimension, $modes);
+ }
+
+ return new DimensionModes($dimensionsList);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function switchMode(string $currentMode, string $previousMode)
+ {
+ //Create new tables and move data
+ $this->createTables($currentMode);
+ $this->moveData($currentMode, $previousMode);
+
+ //Change config options
+ $this->modeSwitcherConfiguration->saveMode($currentMode);
+
+ //Delete old tables
+ $this->dropTables($previousMode);
+ }
+
+ /**
+ * Create new tables
+ *
+ * @param string $currentMode
+ *
+ * @return void
+ * @throws \Zend_Db_Exception
+ */
+ public function createTables(string $currentMode)
+ {
+ foreach ($this->getDimensionsArray($currentMode) as $dimensions) {
+ if (!empty($dimensions)) {
+ $this->tableMaintainer->createTablesForDimensions($dimensions);
+ }
+ }
+ }
+
+ /**
+ * Move data from old tables to new
+ *
+ * @param string $currentMode
+ * @param string $previousMode
+ *
+ * @return void
+ */
+ public function moveData(string $currentMode, string $previousMode)
+ {
+ $dimensionsArrayForCurrentMode = $this->getDimensionsArray($currentMode);
+ $dimensionsArrayForPreviousMode = $this->getDimensionsArray($previousMode);
+
+ foreach ($dimensionsArrayForCurrentMode as $dimensionsForCurrentMode) {
+ $newTable = $this->tableMaintainer->getMainTable($dimensionsForCurrentMode);
+ if (empty($dimensionsForCurrentMode)) {
+ // new mode is 'none'
+ foreach ($dimensionsArrayForPreviousMode as $dimensionsForPreviousMode) {
+ $oldTable = $this->tableMaintainer->getMainTable($dimensionsForPreviousMode);
+ $this->insertFromOldTablesToNew($newTable, $oldTable);
+ }
+ } else {
+ // new mode is not 'none'
+ foreach ($dimensionsArrayForPreviousMode as $dimensionsForPreviousMode) {
+ $oldTable = $this->tableMaintainer->getMainTable($dimensionsForPreviousMode);
+ $this->insertFromOldTablesToNew($newTable, $oldTable, $dimensionsForCurrentMode);
+ }
+ }
+ }
+ }
+
+ /**
+ * Drop old tables
+ *
+ * @param string $previousMode
+ *
+ * @return void
+ */
+ public function dropTables(string $previousMode)
+ {
+ foreach ($this->getDimensionsArray($previousMode) as $dimensions) {
+ if (empty($dimensions)) {
+ $this->tableMaintainer->truncateTablesForDimensions($dimensions);
+ } else {
+ $this->tableMaintainer->dropTablesForDimensions($dimensions);
+ }
+ }
+ }
+
+ /**
+ * Get dimensions array
+ *
+ * @param string $mode
+ *
+ * @return \Magento\Framework\Indexer\MultiDimensionProvider
+ */
+ private function getDimensionsArray(string $mode): \Magento\Framework\Indexer\MultiDimensionProvider
+ {
+ if (isset($this->dimensionsArray[$mode])) {
+ return $this->dimensionsArray[$mode];
+ }
+
+ $this->dimensionsArray[$mode] = $this->dimensionCollectionFactory->create($mode);
+
+ return $this->dimensionsArray[$mode];
+ }
+
+ /**
+ * Insert from old tables data to new
+ *
+ * @param string $newTable
+ * @param string $oldTable
+ * @param Dimension[] $dimensions
+ *
+ * @return void
+ */
+ private function insertFromOldTablesToNew(string $newTable, string $oldTable, array $dimensions = [])
+ {
+ $select = $this->tableMaintainer->getConnection()->select()->from($oldTable);
+
+ foreach ($dimensions as $dimension) {
+ if ($dimension->getName() === WebsiteDimensionProvider::DIMENSION_NAME) {
+ $select->where('website_id = ?', $dimension->getValue());
+ }
+ if ($dimension->getName() === CustomerGroupDimensionProvider::DIMENSION_NAME) {
+ $select->where('customer_group_id = ?', $dimension->getValue());
+ }
+ }
+ $this->tableMaintainer->getConnection()->query(
+ $this->tableMaintainer->getConnection()->insertFromSelect(
+ $select,
+ $newTable,
+ [],
+ \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE
+ )
+ );
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcherConfiguration.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcherConfiguration.php
new file mode 100644
index 0000000000000..ae00ec51f2960
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/ModeSwitcherConfiguration.php
@@ -0,0 +1,70 @@
+configWriter = $configWriter;
+ $this->cacheTypeList = $cacheTypeList;
+ $this->indexer = $indexer;
+ }
+
+ /**
+ * Save switcher mode and invalidate reindex.
+ *
+ * @param string $mode
+ * @return void
+ * @throws \InvalidArgumentException
+ */
+ public function saveMode(string $mode)
+ {
+ //Change config options
+ $this->configWriter->saveConfig(self::XML_PATH_PRICE_DIMENSIONS_MODE, $mode);
+ $this->cacheTypeList->cleanType('config');
+ $this->indexer->load(\Magento\Catalog\Model\Indexer\Product\Price\Processor::INDEXER_ID);
+ $this->indexer->invalidate();
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php
index 32b2db8a7008c..9b99ee8c8dc8c 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/CustomerGroup.php
@@ -5,9 +5,15 @@
*/
namespace Magento\Catalog\Model\Indexer\Product\Price\Plugin;
+use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration;
use Magento\Customer\Api\GroupRepositoryInterface;
use Magento\Customer\Api\Data\GroupInterface;
-use \Magento\Catalog\Model\Indexer\Product\Price\UpdateIndexInterface;
+use Magento\Catalog\Model\Indexer\Product\Price\UpdateIndexInterface;
+use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
+use Magento\Framework\Indexer\Dimension;
+use Magento\Framework\Indexer\DimensionFactory;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
class CustomerGroup
{
@@ -17,14 +23,46 @@ class CustomerGroup
private $updateIndex;
/**
- * Constructor
+ * @var TableMaintainer
+ */
+ private $tableMaintainer;
+
+ /**
+ * DimensionFactory
*
+ * @var DimensionFactory
+ */
+ private $dimensionFactory;
+
+ /**
+ * @var DimensionModeConfiguration
+ */
+ private $dimensionModeConfiguration;
+
+ /**
+ * @var WebsiteDimensionProvider
+ */
+ private $websiteDimensionProvider;
+
+ /**
* @param UpdateIndexInterface $updateIndex
+ * @param TableMaintainer $tableMaintainer
+ * @param DimensionFactory $dimensionFactory
+ * @param DimensionModeConfiguration $dimensionModeConfiguration
+ * @param WebsiteDimensionProvider $websiteDimensionProvider
*/
public function __construct(
- UpdateIndexInterface $updateIndex
+ UpdateIndexInterface $updateIndex,
+ TableMaintainer $tableMaintainer,
+ DimensionFactory $dimensionFactory,
+ DimensionModeConfiguration $dimensionModeConfiguration,
+ WebsiteDimensionProvider $websiteDimensionProvider
) {
$this->updateIndex = $updateIndex;
+ $this->tableMaintainer = $tableMaintainer;
+ $this->dimensionFactory = $dimensionFactory;
+ $this->dimensionModeConfiguration = $dimensionModeConfiguration;
+ $this->websiteDimensionProvider = $websiteDimensionProvider;
}
/**
@@ -32,7 +70,8 @@ public function __construct(
*
* @param GroupRepositoryInterface $subject
* @param \Closure $proceed
- * @param GroupInterface $result
+ * @param GroupInterface $group
+ *
* @return GroupInterface
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
@@ -43,7 +82,64 @@ public function aroundSave(
) {
$isGroupNew = !$group->getId();
$group = $proceed($group);
+ if ($isGroupNew) {
+ foreach ($this->getAffectedDimensions((string)$group->getId()) as $dimensions) {
+ $this->tableMaintainer->createTablesForDimensions($dimensions);
+ }
+ }
$this->updateIndex->update($group, $isGroupNew);
return $group;
}
+
+ /**
+ * Update price index after customer group deleted
+ *
+ * @param GroupRepositoryInterface $subject
+ * @param bool $result
+ * @param string $groupId
+ *
+ * @return bool
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function afterDeleteById(GroupRepositoryInterface $subject, bool $result, string $groupId)
+ {
+ foreach ($this->getAffectedDimensions($groupId) as $dimensions) {
+ $this->tableMaintainer->dropTablesForDimensions($dimensions);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get affected dimensions
+ *
+ * @param string $groupId
+ * @return Dimension[][]
+ */
+ private function getAffectedDimensions(string $groupId): array
+ {
+ $currentDimensions = $this->dimensionModeConfiguration->getDimensionConfiguration();
+ // do not return dimensions if Customer Group dimension is not present in configuration
+ if (!in_array(CustomerGroupDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) {
+ return [];
+ }
+ $customerGroupDimension = $this->dimensionFactory->create(
+ CustomerGroupDimensionProvider::DIMENSION_NAME,
+ $groupId
+ );
+
+ $dimensions = [];
+ if (in_array(WebsiteDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) {
+ foreach ($this->websiteDimensionProvider as $websiteDimension) {
+ $dimensions[] = [
+ $customerGroupDimension,
+ $websiteDimension
+ ];
+ }
+ } else {
+ $dimensions[] = [$customerGroupDimension];
+ }
+
+ return $dimensions;
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/TableResolver.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/TableResolver.php
new file mode 100644
index 0000000000000..fbeec22783090
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/TableResolver.php
@@ -0,0 +1,140 @@
+priceTableResolver = $priceTableResolver;
+ $this->storeManager = $storeManager;
+ $this->httpContext = $context;
+ $this->dimensionFactory = $dimensionFactory;
+ $this->dimensionModeConfiguration = $dimensionModeConfiguration;
+ }
+
+ /**
+ * Replacing catalog_product_index_price table name on the table name segmented per dimension.
+ *
+ * @param ResourceConnection $subject
+ * @param string $result
+ * @param string|string[] $tableName
+ * @return string
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function afterGetTableName(
+ ResourceConnection $subject,
+ string $result,
+ $tableName
+ ) {
+ if (!is_array($tableName)
+ && $tableName === 'catalog_product_index_price'
+ && $this->dimensionModeConfiguration->getDimensionConfiguration()
+ ) {
+ return $this->priceTableResolver->resolve('catalog_product_index_price', $this->getDimensions());
+ }
+
+ return $result;
+ }
+
+ /**
+ * @return Dimension[]
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ */
+ private function getDimensions(): array
+ {
+ $dimensions = [];
+ foreach ($this->dimensionModeConfiguration->getDimensionConfiguration() as $dimensionName) {
+ if ($dimensionName === WebsiteDimensionProvider::DIMENSION_NAME) {
+ $dimensions[] = $this->createDimensionFromWebsite();
+ }
+ if ($dimensionName === CustomerGroupDimensionProvider::DIMENSION_NAME) {
+ $dimensions[] = $this->createDimensionFromCustomerGroup();
+ }
+ }
+
+ return $dimensions;
+ }
+
+ /**
+ * @return Dimension
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ */
+ private function createDimensionFromWebsite(): Dimension
+ {
+ $storeKey = $this->httpContext->getValue(StoreManagerInterface::CONTEXT_STORE);
+ return $this->dimensionFactory->create(
+ WebsiteDimensionProvider::DIMENSION_NAME,
+ (string)$this->storeManager->getStore($storeKey)->getWebsiteId()
+ );
+ }
+
+ /**
+ * @return Dimension
+ */
+ private function createDimensionFromCustomerGroup(): Dimension
+ {
+ return $this->dimensionFactory->create(
+ CustomerGroupDimensionProvider::DIMENSION_NAME,
+ (string)$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP)
+ );
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php
index 269515e292e17..4831680f07c33 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Plugin/Website.php
@@ -5,33 +5,128 @@
*/
namespace Magento\Catalog\Model\Indexer\Product\Price\Plugin;
+use Magento\Catalog\Model\Indexer\Product\Price\DimensionModeConfiguration;
+use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
+use Magento\Framework\Indexer\Dimension;
+use Magento\Framework\Indexer\DimensionFactory;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
+use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
+use Magento\Framework\Model\AbstractModel;
+
class Website
{
/**
- * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor
+ * @var TableMaintainer
+ */
+ private $tableMaintainer;
+
+ /**
+ * DimensionFactory
+ *
+ * @var DimensionFactory
+ */
+ private $dimensionFactory;
+
+ /**
+ * @var DimensionModeConfiguration
*/
- protected $_processor;
+ private $dimensionModeConfiguration;
/**
- * @param \Magento\Catalog\Model\Indexer\Product\Price\Processor $processor
+ * @var CustomerGroupDimensionProvider
*/
- public function __construct(\Magento\Catalog\Model\Indexer\Product\Price\Processor $processor)
+ private $customerGroupDimensionProvider;
+
+ /**
+ * @param TableMaintainer $tableMaintainer
+ * @param DimensionFactory $dimensionFactory
+ * @param DimensionModeConfiguration $dimensionModeConfiguration
+ * @param CustomerGroupDimensionProvider $customerGroupDimensionProvider
+ */
+ public function __construct(
+ TableMaintainer $tableMaintainer,
+ DimensionFactory $dimensionFactory,
+ DimensionModeConfiguration $dimensionModeConfiguration,
+ CustomerGroupDimensionProvider $customerGroupDimensionProvider
+ ) {
+ $this->tableMaintainer = $tableMaintainer;
+ $this->dimensionFactory = $dimensionFactory;
+ $this->dimensionModeConfiguration = $dimensionModeConfiguration;
+ $this->customerGroupDimensionProvider = $customerGroupDimensionProvider;
+ }
+
+ /**
+ * Update price index after website deleted
+ *
+ * @param AbstractDb $subject
+ * @param AbstractDb $objectResource
+ * @param AbstractModel $website
+ *
+ * @return AbstractDb
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function afterDelete(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $website)
{
- $this->_processor = $processor;
+ foreach ($this->getAffectedDimensions($website->getId()) as $dimensions) {
+ $this->tableMaintainer->dropTablesForDimensions($dimensions);
+ }
+
+ return $objectResource;
}
/**
- * Invalidate price indexer
+ * Update price index after website created
*
- * @param \Magento\Store\Model\ResourceModel\Website $subject
- * @param \Magento\Store\Model\ResourceModel\Website $result
- * @return \Magento\Store\Model\ResourceModel\Website
+ * @param AbstractDb $subject
+ * @param AbstractDb $objectResource
+ * @param AbstractModel $website
*
+ * @return AbstractDb
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
- public function afterDelete(\Magento\Store\Model\ResourceModel\Website $subject, $result)
+ public function afterSave(AbstractDb $subject, AbstractDb $objectResource, AbstractModel $website)
+ {
+ if ($website->isObjectNew()) {
+ foreach ($this->getAffectedDimensions($website->getId()) as $dimensions) {
+ $this->tableMaintainer->createTablesForDimensions($dimensions);
+ }
+ }
+
+ return $objectResource;
+ }
+
+ /**
+ * Get affected dimensions
+ *
+ * @param string $websiteId
+ *
+ * @return Dimension[][]
+ */
+ private function getAffectedDimensions(string $websiteId): array
{
- $this->_processor->markIndexerAsInvalid();
- return $result;
+ $currentDimensions = $this->dimensionModeConfiguration->getDimensionConfiguration();
+ // do not return dimensions if Website dimension is not present in configuration
+ if (!in_array(WebsiteDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) {
+ return [];
+ }
+ $websiteDimension = $this->dimensionFactory->create(
+ WebsiteDimensionProvider::DIMENSION_NAME,
+ $websiteId
+ );
+
+ $dimensions = [];
+ if (in_array(CustomerGroupDimensionProvider::DIMENSION_NAME, $currentDimensions, true)) {
+ foreach ($this->customerGroupDimensionProvider as $customerGroupDimension) {
+ $dimensions[] = [
+ $customerGroupDimension,
+ $websiteDimension
+ ];
+ }
+ } else {
+ $dimensions[] = [$websiteDimension];
+ }
+
+ return $dimensions;
}
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/PriceTableResolver.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/PriceTableResolver.php
new file mode 100644
index 0000000000000..eeaa731aac686
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/PriceTableResolver.php
@@ -0,0 +1,78 @@
+indexScopeResolver = $indexScopeResolver;
+ $this->dimensionModeConfiguration = $dimensionModeConfiguration;
+ }
+
+ /**
+ * Return price table name based on dimension
+ * @param string $index
+ * @param array $dimensions
+ * @return string
+ */
+ public function resolve($index, array $dimensions)
+ {
+ if ($index === 'catalog_product_index_price') {
+ $dimensions = $this->filterDimensions($dimensions);
+ }
+ return $this->indexScopeResolver->resolve($index, $dimensions);
+ }
+
+ /**
+ * @param Dimension[] $dimensions
+ * @return array
+ * @throws \Exception
+ */
+ private function filterDimensions($dimensions): array
+ {
+ $existDimensions = [];
+ $currentDimensions = $this->dimensionModeConfiguration->getDimensionConfiguration();
+ foreach ($dimensions as $dimension) {
+ if ((string)$dimension->getValue() === '') {
+ throw new \InvalidArgumentException(
+ sprintf('Dimension value of "%s" can not be empty', $dimension->getName())
+ );
+ }
+ if (in_array($dimension->getName(), $currentDimensions, true)) {
+ $existDimensions[] = $dimension;
+ }
+ }
+
+ return $existDimensions;
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/TableMaintainer.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/TableMaintainer.php
new file mode 100644
index 0000000000000..e3077baaeb7a6
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/TableMaintainer.php
@@ -0,0 +1,280 @@
+resource = $resource;
+ $this->tableResolver = $tableResolver;
+ $this->connectionName = $connectionName;
+ }
+
+ /**
+ * Get connection for work with price indexer
+ *
+ * @return AdapterInterface
+ */
+ public function getConnection(): AdapterInterface
+ {
+ if (null === $this->connection) {
+ $this->connection = $this->resource->getConnection($this->connectionName);
+ }
+ return $this->connection;
+ }
+
+ /**
+ * Return validated table name
+ *
+ * @param string $table
+ * @return string
+ */
+ private function getTable(string $table): string
+ {
+ return $this->resource->getTableName($table);
+ }
+
+ /**
+ * Create table based on main table
+ *
+ * @param string $mainTableName
+ * @param string $newTableName
+ *
+ * @return void
+ *
+ * @throws \Zend_Db_Exception
+ */
+ private function createTable(string $mainTableName, string $newTableName)
+ {
+ if (!$this->getConnection()->isTableExists($newTableName)) {
+ $this->getConnection()->createTable(
+ $this->getConnection()->createTableByDdl($mainTableName, $newTableName)
+ );
+ }
+ }
+
+ /**
+ * Drop table
+ *
+ * @param string $tableName
+ *
+ * @return void
+ */
+ private function dropTable(string $tableName)
+ {
+ if ($this->getConnection()->isTableExists($tableName)) {
+ $this->getConnection()->dropTable($tableName);
+ }
+ }
+
+ /**
+ * Truncate table
+ *
+ * @param string $tableName
+ *
+ * @return void
+ */
+ private function truncateTable(string $tableName)
+ {
+ if ($this->getConnection()->isTableExists($tableName)) {
+ $this->getConnection()->truncateTable($tableName);
+ }
+ }
+
+ /**
+ * Get array key for tmp table
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return string
+ */
+ private function getArrayKeyForTmpTable(array $dimensions): string
+ {
+ $key = 'temp';
+ foreach ($dimensions as $dimension) {
+ $key .= $dimension->getName() . '_' . $dimension->getValue();
+ }
+ return $key;
+ }
+
+ /**
+ * Return main index table name
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return string
+ */
+ public function getMainTable(array $dimensions): string
+ {
+ return $this->tableResolver->resolve(self::MAIN_INDEX_TABLE, $dimensions);
+ }
+
+ /**
+ * Create main and replica index tables for dimensions
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return void
+ *
+ * @throws \Zend_Db_Exception
+ */
+ public function createTablesForDimensions(array $dimensions)
+ {
+ $mainTableName = $this->getMainTable($dimensions);
+ //Create index table for dimensions based on main replica table
+ //Using main replica table is necessary for backward capability and TableResolver plugin work
+ $this->createTable(
+ $this->getTable(self::MAIN_INDEX_TABLE . $this->additionalTableSuffix),
+ $mainTableName
+ );
+
+ $mainReplicaTableName = $this->getMainTable($dimensions) . $this->additionalTableSuffix;
+ //Create replica table for dimensions based on main replica table
+ $this->createTable(
+ $this->getTable(self::MAIN_INDEX_TABLE . $this->additionalTableSuffix),
+ $mainReplicaTableName
+ );
+ }
+
+ /**
+ * Drop main and replica index tables for dimensions
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return void
+ */
+ public function dropTablesForDimensions(array $dimensions)
+ {
+ $mainTableName = $this->getMainTable($dimensions);
+ $this->dropTable($mainTableName);
+
+ $mainReplicaTableName = $this->getMainTable($dimensions) . $this->additionalTableSuffix;
+ $this->dropTable($mainReplicaTableName);
+ }
+
+ /**
+ * Truncate main and replica index tables for dimensions
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return void
+ */
+ public function truncateTablesForDimensions(array $dimensions)
+ {
+ $mainTableName = $this->getMainTable($dimensions);
+ $this->truncateTable($mainTableName);
+
+ $mainReplicaTableName = $this->getMainTable($dimensions) . $this->additionalTableSuffix;
+ $this->truncateTable($mainReplicaTableName);
+ }
+
+ /**
+ * Return replica index table name
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return string
+ */
+ public function getMainReplicaTable(array $dimensions): string
+ {
+ return $this->getMainTable($dimensions) . $this->additionalTableSuffix;
+ }
+
+ /**
+ * Create temporary index table for dimensions
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return void
+ */
+ public function createMainTmpTable(array $dimensions)
+ {
+ // Create temporary table based on template table catalog_product_index_price_tmp without indexes
+ $templateTableName = $this->resource->getTableName(self::MAIN_INDEX_TABLE . '_tmp');
+ $temporaryTableName = $this->getMainTable($dimensions) . $this->tmpTableSuffix;
+ $this->getConnection()->createTemporaryTableLike($temporaryTableName, $templateTableName, true);
+ $this->mainTmpTable[$this->getArrayKeyForTmpTable($dimensions)] = $temporaryTableName;
+ }
+
+ /**
+ * Return temporary index table name
+ *
+ * @param Dimension[] $dimensions
+ *
+ * @return string
+ *
+ * @throws \LogicException
+ */
+ public function getMainTmpTable(array $dimensions): string
+ {
+ $cacheKey = $this->getArrayKeyForTmpTable($dimensions);
+ if (!isset($this->mainTmpTable[$cacheKey])) {
+ throw new \LogicException(
+ sprintf('Temporary table for provided dimensions "%s" does not exist', $cacheKey)
+ );
+ }
+ return $this->mainTmpTable[$cacheKey];
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index 90af9bee270bd..b29eee9a47f8b 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -9,9 +9,8 @@
use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductLinkRepositoryInterface;
-use Magento\Catalog\Model\Entity\GetProductCustomAttributeCodes;
use Magento\Catalog\Model\Product\Attribute\Backend\Media\EntryConverterPool;
-use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface;
+use Magento\Catalog\Model\FilterProductCustomAttribute;
use Magento\Framework\Api\AttributeValueFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ObjectManager;
@@ -278,6 +277,7 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
/**
* @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
+ * @deprecated Not used anymore due to performance issue (loaded all product attributes)
*/
protected $metadataService;
@@ -345,12 +345,15 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
protected $linkTypeProvider;
/**
- * @var GetCustomAttributeCodesInterface
+ * @var \Magento\Eav\Model\Config
*/
- private $getCustomAttributeCodes;
+ private $eavConfig;
+ /**
+ * @var FilterProductCustomAttribute|null
+ */
+ private $filterCustomAttribute;
/**
- * Product constructor.
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
@@ -386,7 +389,8 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
* @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper
* @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor
* @param array $data
- * @param GetCustomAttributeCodesInterface|null $getCustomAttributeCodes
+ * @param \Magento\Eav\Model\Config|null $config
+ * @param FilterProductCustomAttribute|null $filterCustomAttribute
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
@@ -426,7 +430,8 @@ public function __construct(
\Magento\Framework\Api\DataObjectHelper $dataObjectHelper,
\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor,
array $data = [],
- GetCustomAttributeCodesInterface $getCustomAttributeCodes = null
+ \Magento\Eav\Model\Config $config = null,
+ FilterProductCustomAttribute $filterCustomAttribute = null
) {
$this->metadataService = $metadataService;
$this->_itemOptionFactory = $itemOptionFactory;
@@ -455,9 +460,6 @@ public function __construct(
$this->mediaGalleryEntryConverterPool = $mediaGalleryEntryConverterPool;
$this->dataObjectHelper = $dataObjectHelper;
$this->joinProcessor = $joinProcessor;
- $this->getCustomAttributeCodes = $getCustomAttributeCodes ?? ObjectManager::getInstance()->get(
- GetProductCustomAttributeCodes::class
- );
parent::__construct(
$context,
$registry,
@@ -468,6 +470,9 @@ public function __construct(
$resourceCollection,
$data
);
+ $this->eavConfig = $config ?? ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class);
+ $this->filterCustomAttribute = $filterCustomAttribute
+ ?? ObjectManager::getInstance()->get(FilterProductCustomAttribute::class);
}
/**
@@ -493,11 +498,24 @@ protected function _getResource()
}
/**
- * {@inheritdoc}
+ * Get a list of custom attribute codes that belongs to product attribute set. If attribute set not specified for
+ * product will return all product attribute codes
+ *
+ * @return string[]
*/
protected function getCustomAttributesCodes()
{
- return $this->getCustomAttributeCodes->execute($this->metadataService);
+ if ($this->customAttributesCodes === null) {
+ $this->customAttributesCodes = array_keys($this->eavConfig->getEntityAttributes(
+ self::ENTITY,
+ $this
+ ));
+
+ $this->customAttributesCodes = $this->filterCustomAttribute->execute($this->customAttributesCodes);
+ $this->customAttributesCodes = array_diff($this->customAttributesCodes, ProductInterface::ATTRIBUTES);
+ }
+
+ return $this->customAttributesCodes;
}
/**
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php
index 3779cab431cb7..e26717e47274c 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php
@@ -247,6 +247,8 @@ public function validate($object)
}
/**
+ * Validate price.
+ *
* @param array $priceRow
* @return void
* @throws \Magento\Framework\Exception\LocalizedException
@@ -312,6 +314,8 @@ public function afterLoad($object)
}
/**
+ * Get website id.
+ *
* @param int $storeId
* @return int|null
*/
@@ -327,6 +331,8 @@ private function getWebsiteId($storeId)
}
/**
+ * Set price data.
+ *
* @param \Magento\Catalog\Model\Product $object
* @param array $priceData
*/
@@ -373,122 +379,16 @@ protected function modifyPriceData($object, $data)
*
* @param \Magento\Catalog\Model\Product $object
* @return $this
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
- * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterSave($object)
{
- $websiteId = $this->_storeManager->getStore($object->getStoreId())->getWebsiteId();
- $isGlobal = $this->getAttribute()->isScopeGlobal() || $websiteId == 0;
-
- $priceRows = $object->getData($this->getAttribute()->getName());
- if (null === $priceRows) {
- return $this;
- }
-
- $priceRows = array_filter((array)$priceRows);
-
- $old = [];
- $new = [];
-
- // prepare original data for compare
- $origPrices = $object->getOrigData($this->getAttribute()->getName());
- if (!is_array($origPrices)) {
- $origPrices = [];
- }
- foreach ($origPrices as $data) {
- if ($data['website_id'] > 0 || $data['website_id'] == '0' && $isGlobal) {
- $key = implode(
- '-',
- array_merge(
- [$data['website_id'], $data['cust_group']],
- $this->_getAdditionalUniqueFields($data)
- )
- );
- $old[$key] = $data;
- }
- }
-
- // prepare data for save
- foreach ($priceRows as $data) {
- $hasEmptyData = false;
- foreach ($this->_getAdditionalUniqueFields($data) as $field) {
- if (empty($field)) {
- $hasEmptyData = true;
- break;
- }
- }
-
- if ($hasEmptyData || !isset($data['cust_group']) || !empty($data['delete'])) {
- continue;
- }
- if ($this->getAttribute()->isScopeGlobal() && $data['website_id'] > 0) {
- continue;
- }
- if (!$isGlobal && (int)$data['website_id'] == 0) {
- continue;
- }
-
- $key = implode(
- '-',
- array_merge([$data['website_id'], $data['cust_group']], $this->_getAdditionalUniqueFields($data))
- );
-
- $useForAllGroups = $data['cust_group'] == $this->_groupManagement->getAllCustomersGroup()->getId();
- $customerGroupId = !$useForAllGroups ? $data['cust_group'] : 0;
- $new[$key] = array_merge(
- $this->getAdditionalFields($data),
- [
- 'website_id' => $data['website_id'],
- 'all_groups' => $useForAllGroups ? 1 : 0,
- 'customer_group_id' => $customerGroupId,
- 'value' => isset($data['price']) ? $data['price'] : null,
- ],
- $this->_getAdditionalUniqueFields($data)
- );
- }
-
- $delete = array_diff_key($old, $new);
- $insert = array_diff_key($new, $old);
- $update = array_intersect_key($new, $old);
-
- $isChanged = false;
- $productId = $object->getData($this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField());
-
- if (!empty($delete)) {
- foreach ($delete as $data) {
- $this->_getResource()->deletePriceData($productId, null, $data['price_id']);
- $isChanged = true;
- }
- }
-
- if (!empty($insert)) {
- foreach ($insert as $data) {
- $price = new \Magento\Framework\DataObject($data);
- $price->setData(
- $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField(),
- $productId
- );
- $this->_getResource()->savePriceData($price);
-
- $isChanged = true;
- }
- }
-
- if (!empty($update)) {
- $isChanged |= $this->updateValues($update, $old);
- }
-
- if ($isChanged) {
- $valueChangedKey = $this->getAttribute()->getName() . '_changed';
- $object->setData($valueChangedKey, 1);
- }
-
return $this;
}
/**
+ * Update values.
+ *
* @param array $valuesToUpdate
* @param array $oldValues
* @return boolean
@@ -544,6 +444,8 @@ public function getResource()
}
/**
+ * Get metadata pool.
+ *
* @return \Magento\Framework\EntityManager\MetadataPool
*/
private function getMetadataPool()
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php
new file mode 100644
index 0000000000000..248d8ed221250
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php
@@ -0,0 +1,171 @@
+storeManager = $storeManager;
+ $this->attributeRepository = $attributeRepository;
+ $this->groupManagement = $groupManagement;
+ $this->metadataPoll = $metadataPool;
+ $this->tierPriceResource = $tierPriceResource;
+ }
+
+ /**
+ * Set tier price data for product entity
+ *
+ * @param \Magento\Catalog\Api\Data\ProductInterface|object $entity
+ * @param array $arguments
+ * @return \Magento\Catalog\Api\Data\ProductInterface|object
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\InputException
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function execute($entity, $arguments = [])
+ {
+ $attribute = $this->attributeRepository->get('tier_price');
+ $priceRows = $entity->getData($attribute->getName());
+ if (null !== $priceRows) {
+ if (!is_array($priceRows)) {
+ throw new \Magento\Framework\Exception\InputException(
+ __('Tier prices data should be array, but actually other type is received')
+ );
+ }
+ $websiteId = $this->storeManager->getStore($entity->getStoreId())->getWebsiteId();
+ $isGlobal = $attribute->isScopeGlobal() || $websiteId === 0;
+ $identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField();
+ $priceRows = array_filter($priceRows);
+ $productId = (int) $entity->getData($identifierField);
+
+ // prepare and save data
+ foreach ($priceRows as $data) {
+ $isPriceWebsiteGlobal = (int)$data['website_id'] === 0;
+ if ($isGlobal === $isPriceWebsiteGlobal
+ || !empty($data['price_qty'])
+ || isset($data['cust_group'])
+ ) {
+ $tierPrice = $this->prepareTierPrice($data);
+ $price = new \Magento\Framework\DataObject($tierPrice);
+ $price->setData(
+ $identifierField,
+ $productId
+ );
+ $this->tierPriceResource->savePriceData($price);
+ $valueChangedKey = $attribute->getName() . '_changed';
+ $entity->setData($valueChangedKey, 1);
+ }
+ }
+ }
+
+ return $entity;
+ }
+
+ /**
+ * Get additional tier price fields
+ *
+ * @param array $objectArray
+ * @return array
+ */
+ private function getAdditionalFields(array $objectArray): array
+ {
+ $percentageValue = $this->getPercentage($objectArray);
+ return [
+ 'value' => $percentageValue ? null : $objectArray['price'],
+ 'percentage_value' => $percentageValue ?: null,
+ ];
+ }
+
+ /**
+ * Check whether price has percentage value.
+ *
+ * @param array $priceRow
+ * @return int|null
+ */
+ private function getPercentage(array $priceRow): ?int
+ {
+ return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value'])
+ ? (int)$priceRow['percentage_value']
+ : null;
+ }
+
+ /**
+ * Prepare tier price data by provided price row data
+ *
+ * @param array $data
+ * @return array
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ private function prepareTierPrice(array $data): array
+ {
+ $useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId();
+ $customerGroupId = $useForAllGroups ? 0 : $data['cust_group'];
+ $tierPrice = array_merge(
+ $this->getAdditionalFields($data),
+ [
+ 'website_id' => $data['website_id'],
+ 'all_groups' => (int)$useForAllGroups,
+ 'customer_group_id' => $customerGroupId,
+ 'value' => $data['price'] ?? null,
+ 'qty' => (int)$data['price_qty']
+ ]
+ );
+
+ return $tierPrice;
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php
new file mode 100644
index 0000000000000..a112da79d16fa
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php
@@ -0,0 +1,315 @@
+storeManager = $storeManager;
+ $this->attributeRepository = $attributeRepository;
+ $this->groupManagement = $groupManagement;
+ $this->metadataPoll = $metadataPool;
+ $this->tierPriceResource = $tierPriceResource;
+ }
+
+ /**
+ * Perform action on relation/extension attribute.
+ *
+ * @param \Magento\Catalog\Api\Data\ProductInterface|object $entity
+ * @param array $arguments
+ * @return \Magento\Catalog\Api\Data\ProductInterface|object
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function execute($entity, $arguments = [])
+ {
+ $attribute = $this->attributeRepository->get('tier_price');
+ $priceRows = $entity->getData($attribute->getName());
+ if (null !== $priceRows) {
+ if (!is_array($priceRows)) {
+ throw new \Magento\Framework\Exception\InputException(
+ __('Tier prices data should be array, but actually other type is received')
+ );
+ }
+ $websiteId = $this->storeManager->getStore($entity->getStoreId())->getWebsiteId();
+ $isGlobal = $attribute->isScopeGlobal() || $websiteId === 0;
+ $identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField();
+ $productId = (int) $entity->getData($identifierField);
+
+ // prepare original data to compare
+ $origPrices = $entity->getOrigData($attribute->getName());
+ $old = $this->prepareOriginalDataToCompare($origPrices, $isGlobal);
+ // prepare data for save
+ $new = $this->prepareNewDataForSave($priceRows, $isGlobal);
+
+ $delete = array_diff_key($old, $new);
+ $insert = array_diff_key($new, $old);
+ $update = array_intersect_key($new, $old);
+
+ $isAttributeChanged = $this->deleteValues($productId, $delete);
+ $isAttributeChanged |= $this->insertValues($productId, $insert);
+ $isAttributeChanged |= $this->updateValues($update, $old);
+
+ if ($isAttributeChanged) {
+ $valueChangedKey = $attribute->getName() . '_changed';
+ $entity->setData($valueChangedKey, 1);
+ }
+ }
+
+ return $entity;
+ }
+
+ /**
+ * Get additional tier price fields
+ *
+ * @param array $objectArray
+ * @return array
+ */
+ private function getAdditionalFields(array $objectArray): array
+ {
+ $percentageValue = $this->getPercentage($objectArray);
+ return [
+ 'value' => $percentageValue ? null : $objectArray['price'],
+ 'percentage_value' => $percentageValue ?: null,
+ ];
+ }
+
+ /**
+ * Check whether price has percentage value.
+ *
+ * @param array $priceRow
+ * @return int|null
+ */
+ private function getPercentage(array $priceRow): ?int
+ {
+ return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value'])
+ ? (int)$priceRow['percentage_value']
+ : null;
+ }
+
+ /**
+ * Update existing tier prices for processed product
+ *
+ * @param array $valuesToUpdate
+ * @param array $oldValues
+ * @return bool
+ */
+ private function updateValues(array $valuesToUpdate, array $oldValues): bool
+ {
+ $isChanged = false;
+ foreach ($valuesToUpdate as $key => $value) {
+ if ((!empty($value['value']) && (float)$oldValues[$key]['price'] !== (float)$value['value'])
+ || $this->getPercentage($oldValues[$key]) !== $this->getPercentage($value)
+ ) {
+ $price = new \Magento\Framework\DataObject(
+ [
+ 'value_id' => $oldValues[$key]['price_id'],
+ 'value' => $value['value'],
+ 'percentage_value' => $this->getPercentage($value)
+ ]
+ );
+ $this->tierPriceResource->savePriceData($price);
+ $isChanged = true;
+ }
+ }
+
+ return $isChanged;
+ }
+
+ /**
+ * Insert new tier prices for processed product
+ *
+ * @param int $productId
+ * @param array $valuesToInsert
+ * @return bool
+ */
+ private function insertValues(int $productId, array $valuesToInsert): bool
+ {
+ $isChanged = false;
+ $identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField();
+ foreach ($valuesToInsert as $data) {
+ $price = new \Magento\Framework\DataObject($data);
+ $price->setData(
+ $identifierField,
+ $productId
+ );
+ $this->tierPriceResource->savePriceData($price);
+ $isChanged = true;
+ }
+
+ return $isChanged;
+ }
+
+ /**
+ * Delete tier price values for processed product
+ *
+ * @param int $productId
+ * @param array $valuesToDelete
+ * @return bool
+ */
+ private function deleteValues(int $productId, array $valuesToDelete): bool
+ {
+ $isChanged = false;
+ foreach ($valuesToDelete as $data) {
+ $this->tierPriceResource->deletePriceData($productId, null, $data['price_id']);
+ $isChanged = true;
+ }
+
+ return $isChanged;
+ }
+
+ /**
+ * Get generated price key based on price data
+ *
+ * @param array $priceData
+ * @return string
+ */
+ private function getPriceKey(array $priceData): string
+ {
+ $key = implode(
+ '-',
+ array_merge([$priceData['website_id'], $priceData['cust_group']], [(int)$priceData['price_qty']])
+ );
+
+ return $key;
+ }
+
+ /**
+ * Prepare tier price data by provided price row data
+ *
+ * @param array $data
+ * @return array
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ private function prepareTierPrice(array $data): array
+ {
+ $useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId();
+ $customerGroupId = $useForAllGroups ? 0 : $data['cust_group'];
+ $tierPrice = array_merge(
+ $this->getAdditionalFields($data),
+ [
+ 'website_id' => $data['website_id'],
+ 'all_groups' => (int)$useForAllGroups,
+ 'customer_group_id' => $customerGroupId,
+ 'value' => $data['price'] ?? null,
+ 'qty' => (int)$data['price_qty']
+ ]
+ );
+
+ return $tierPrice;
+ }
+
+ /**
+ * Check by id is website global
+ *
+ * @param int $websiteId
+ * @return bool
+ */
+ private function isWebsiteGlobal(int $websiteId): bool
+ {
+ return $websiteId === 0;
+ }
+
+ /**
+ * Prepare original data to compare.
+ *
+ * @param array|null $origPrices
+ * @param bool $isGlobal
+ * @return array
+ */
+ private function prepareOriginalDataToCompare(?array $origPrices, bool $isGlobal = true): array
+ {
+ $old = [];
+ if (is_array($origPrices)) {
+ foreach ($origPrices as $data) {
+ if ($isGlobal === $this->isWebsiteGlobal((int)$data['website_id'])) {
+ $key = $this->getPriceKey($data);
+ $old[$key] = $data;
+ }
+ }
+ }
+
+ return $old;
+ }
+
+ /**
+ * Prepare new data for save.
+ *
+ * @param array $priceRows
+ * @param bool $isGlobal
+ * @return array
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ private function prepareNewDataForSave(array $priceRows, bool $isGlobal = true): array
+ {
+ $new = [];
+ $priceRows = array_filter($priceRows);
+ foreach ($priceRows as $data) {
+ if (empty($data['delete'])
+ && (!empty($data['price_qty'])
+ || isset($data['cust_group'])
+ || $isGlobal === $this->isWebsiteGlobal((int)$data['website_id']))
+ ) {
+ $key = $this->getPriceKey($data);
+ $new[$key] = $this->prepareTierPrice($data);
+ }
+ }
+
+ return $new;
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php b/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php
index 270a2f229678b..f6d3ca36c1e1e 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php
@@ -119,16 +119,7 @@ public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attrib
$attribute->setIsUserDefined($existingModel->getIsUserDefined());
$attribute->setFrontendInput($existingModel->getFrontendInput());
- if (is_array($attribute->getFrontendLabels())) {
- $defaultFrontendLabel = $attribute->getDefaultFrontendLabel();
- $frontendLabel[0] = !empty($defaultFrontendLabel)
- ? $defaultFrontendLabel
- : $existingModel->getDefaultFrontendLabel();
- foreach ($attribute->getFrontendLabels() as $item) {
- $frontendLabel[$item->getStoreId()] = $item->getLabel();
- }
- $attribute->setDefaultFrontendLabel($frontendLabel);
- }
+ $this->updateDefaultFrontendLabel($attribute, $existingModel);
} else {
$attribute->setAttributeId(null);
@@ -136,22 +127,10 @@ public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attrib
throw InputException::requiredField('frontend_label');
}
- $frontendLabels = [];
- if ($attribute->getDefaultFrontendLabel()) {
- $frontendLabels[0] = $attribute->getDefaultFrontendLabel();
- }
- if ($attribute->getFrontendLabels() && is_array($attribute->getFrontendLabels())) {
- foreach ($attribute->getFrontendLabels() as $label) {
- $frontendLabels[$label->getStoreId()] = $label->getLabel();
- }
- if (!isset($frontendLabels[0]) || !$frontendLabels[0]) {
- throw InputException::invalidFieldValue('frontend_label', null);
- }
+ $frontendLabel = $this->updateDefaultFrontendLabel($attribute, null);
- $attribute->setDefaultFrontendLabel($frontendLabels);
- }
$attribute->setAttributeCode(
- $attribute->getAttributeCode() ?: $this->generateCode($frontendLabels[0])
+ $attribute->getAttributeCode() ?: $this->generateCode($frontendLabel)
);
$this->validateCode($attribute->getAttributeCode());
$this->validateFrontendInput($attribute->getFrontendInput());
@@ -275,4 +254,52 @@ protected function validateFrontendInput($frontendInput)
throw InputException::invalidFieldValue('frontend_input', $frontendInput);
}
}
+
+ /**
+ * This method sets default frontend value using given default frontend value or frontend value from admin store
+ * if default frontend value is not presented.
+ * If both default frontend label and admin store frontend label are not given it throws exception
+ * for attribute creation process or sets existing attribute value for attribute update action.
+ *
+ * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
+ * @param \Magento\Catalog\Api\Data\ProductAttributeInterface|null $existingModel
+ * @return string|null
+ * @throws InputException
+ */
+ private function updateDefaultFrontendLabel($attribute, $existingModel)
+ {
+ $frontendLabel = $attribute->getDefaultFrontendLabel();
+ if (empty($frontendLabel)) {
+ $frontendLabel = $this->extractAdminStoreFrontendLabel($attribute);
+ if (empty($frontendLabel)) {
+ if ($existingModel) {
+ $frontendLabel = $existingModel->getDefaultFrontendLabel();
+ } else {
+ throw InputException::invalidFieldValue('frontend_label', null);
+ }
+ }
+ $attribute->setDefaultFrontendLabel($frontendLabel);
+ }
+ return $frontendLabel;
+ }
+
+ /**
+ * This method extracts frontend label from FrontendLabel object for admin store.
+ *
+ * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute
+ * @return string|null
+ */
+ private function extractAdminStoreFrontendLabel($attribute)
+ {
+ $frontendLabel = [];
+ $frontendLabels = $attribute->getFrontendLabels();
+ if (isset($frontendLabels[0])
+ && $frontendLabels[0] instanceof \Magento\Eav\Api\Data\AttributeFrontendLabelInterface
+ ) {
+ foreach ($attribute->getFrontendLabels() as $label) {
+ $frontendLabel[$label->getStoreId()] = $label->getLabel();
+ }
+ }
+ return $frontendLabel[0] ?? null;
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Product/Compare/Item.php b/app/code/Magento/Catalog/Model/Product/Compare/Item.php
index 3b7e47a46a0a3..fd07380bebd7a 100644
--- a/app/code/Magento/Catalog/Model/Product/Compare/Item.php
+++ b/app/code/Magento/Catalog/Model/Product/Compare/Item.php
@@ -158,8 +158,8 @@ public function addProductData($product)
{
if ($product instanceof Product) {
$this->setProductId($product->getId());
- } elseif (intval($product)) {
- $this->setProductId(intval($product));
+ } elseif ((int) $product) {
+ $this->setProductId((int) $product);
}
return $this;
diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
index bd28b65bb7982..65111979c5d3a 100644
--- a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
+++ b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
@@ -102,6 +102,8 @@ public function __construct(
}
/**
+ * Execute create handler
+ *
* @param object $product
* @param array $arguments
* @return object
@@ -167,23 +169,19 @@ public function execute($product, $arguments = [])
if (empty($attrData) && empty($clearImages) && empty($newImages) && empty($existImages)) {
continue;
}
- if (in_array($attrData, $clearImages)) {
- $product->setData($mediaAttrCode, 'no_selection');
- }
-
- if (in_array($attrData, array_keys($newImages))) {
- $product->setData($mediaAttrCode, $newImages[$attrData]['new_file']);
- $product->setData($mediaAttrCode . '_label', $newImages[$attrData]['label']);
- }
-
- if (in_array($attrData, array_keys($existImages)) && isset($existImages[$attrData]['label'])) {
- $product->setData($mediaAttrCode . '_label', $existImages[$attrData]['label']);
- }
- if (!empty($product->getData($mediaAttrCode))) {
- $product->addAttributeUpdate(
+ $this->processMediaAttribute(
+ $product,
+ $mediaAttrCode,
+ $clearImages,
+ $newImages
+ );
+ if (in_array($mediaAttrCode, ['image', 'small_image', 'thumbnail'])) {
+ $this->processMediaAttributeLabel(
+ $product,
$mediaAttrCode,
- $product->getData($mediaAttrCode),
- $product->getStoreId()
+ $clearImages,
+ $newImages,
+ $existImages
);
}
}
@@ -208,6 +206,8 @@ public function execute($product, $arguments = [])
}
/**
+ * Returns media gallery atribute instance
+ *
* @return \Magento\Catalog\Api\Data\ProductAttributeInterface
* @since 101.0.0
*/
@@ -223,6 +223,8 @@ public function getAttribute()
}
/**
+ * Process delete images
+ *
* @param \Magento\Catalog\Model\Product $product
* @param array $images
* @return void
@@ -234,6 +236,8 @@ protected function processDeletedImages($product, array &$images)
}
/**
+ * Process images
+ *
* @param \Magento\Catalog\Model\Product $product
* @param array $images
* @return void
@@ -296,6 +300,8 @@ protected function processNewImage($product, array &$image)
}
/**
+ * Duplicate attribute
+ *
* @param \Magento\Catalog\Model\Product $product
* @return $this
* @since 101.0.0
@@ -364,6 +370,8 @@ private function getSafeFilename($file)
}
/**
+ * Returns file name according to tmp name
+ *
* @param string $file
* @return string
* @since 101.0.0
@@ -449,4 +457,81 @@ private function getMediaAttributeCodes()
}
return $this->mediaAttributeCodes;
}
+
+ /**
+ * Process media attribute
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @param string $mediaAttrCode
+ * @param array $clearImages
+ * @param array $newImages
+ */
+ private function processMediaAttribute(
+ \Magento\Catalog\Model\Product $product,
+ $mediaAttrCode,
+ array $clearImages,
+ array $newImages
+ ) {
+ $attrData = $product->getData($mediaAttrCode);
+ if (in_array($attrData, $clearImages)) {
+ $product->setData($mediaAttrCode, 'no_selection');
+ }
+
+ if (in_array($attrData, array_keys($newImages))) {
+ $product->setData($mediaAttrCode, $newImages[$attrData]['new_file']);
+ }
+ if (!empty($product->getData($mediaAttrCode))) {
+ $product->addAttributeUpdate(
+ $mediaAttrCode,
+ $product->getData($mediaAttrCode),
+ $product->getStoreId()
+ );
+ }
+ }
+
+ /**
+ * Process media attribute label
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @param string $mediaAttrCode
+ * @param array $clearImages
+ * @param array $newImages
+ * @param array $existImages
+ */
+ private function processMediaAttributeLabel(
+ \Magento\Catalog\Model\Product $product,
+ $mediaAttrCode,
+ array $clearImages,
+ array $newImages,
+ array $existImages
+ ) {
+ $resetLabel = false;
+ $attrData = $product->getData($mediaAttrCode);
+ if (in_array($attrData, $clearImages)) {
+ $product->setData($mediaAttrCode . '_label', null);
+ $resetLabel = true;
+ }
+
+ if (in_array($attrData, array_keys($newImages))) {
+ $product->setData($mediaAttrCode . '_label', $newImages[$attrData]['label']);
+ }
+
+ if (in_array($attrData, array_keys($existImages)) && isset($existImages[$attrData]['label'])) {
+ $product->setData($mediaAttrCode . '_label', $existImages[$attrData]['label']);
+ }
+
+ if ($attrData === 'no_selection' && !empty($product->getData($mediaAttrCode . '_label'))) {
+ $product->setData($mediaAttrCode . '_label', null);
+ $resetLabel = true;
+ }
+ if (!empty($product->getData($mediaAttrCode . '_label'))
+ || $resetLabel === true
+ ) {
+ $product->addAttributeUpdate(
+ $mediaAttrCode . '_label',
+ $product->getData($mediaAttrCode . '_label'),
+ $product->getStoreId()
+ );
+ }
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Product/Image.php b/app/code/Magento/Catalog/Model/Product/Image.php
index 09ba68ddbe2b2..f1ae9ac62dc9b 100644
--- a/app/code/Magento/Catalog/Model/Product/Image.php
+++ b/app/code/Magento/Catalog/Model/Product/Image.php
@@ -484,7 +484,7 @@ public function resize()
*/
public function rotate($angle)
{
- $angle = intval($angle);
+ $angle = (int) $angle;
$this->getImageProcessor()->rotate($angle);
return $this;
}
diff --git a/app/code/Magento/Catalog/Model/Product/Option.php b/app/code/Magento/Catalog/Model/Product/Option.php
index acfc454883e1d..b4a4ec08d390d 100644
--- a/app/code/Magento/Catalog/Model/Product/Option.php
+++ b/app/code/Magento/Catalog/Model/Product/Option.php
@@ -323,7 +323,7 @@ public function getGroupByType($type = null)
self::OPTION_TYPE_TIME => self::OPTION_GROUP_DATE,
];
- return isset($optionGroupsToTypes[$type]) ? $optionGroupsToTypes[$type] : '';
+ return $optionGroupsToTypes[$type] ?? '';
}
/**
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php b/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php
index 7517459da650f..b19906ecd6cc9 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Type/Date.php
@@ -102,11 +102,11 @@ public function validateUserValue($values)
$this->setUserValue(
[
'date' => isset($value['date']) ? $value['date'] : '',
- 'year' => isset($value['year']) ? intval($value['year']) : 0,
- 'month' => isset($value['month']) ? intval($value['month']) : 0,
- 'day' => isset($value['day']) ? intval($value['day']) : 0,
- 'hour' => isset($value['hour']) ? intval($value['hour']) : 0,
- 'minute' => isset($value['minute']) ? intval($value['minute']) : 0,
+ 'year' => isset($value['year']) ? (int) $value['year'] : 0,
+ 'month' => isset($value['month']) ? (int) $value['month'] : 0,
+ 'day' => isset($value['day']) ? (int) $value['day'] : 0,
+ 'hour' => isset($value['hour']) ? (int) $value['hour'] : 0,
+ 'minute' => isset($value['minute']) ? (int) $value['minute'] : 0,
'day_part' => isset($value['day_part']) ? $value['day_part'] : '',
'date_internal' => isset($value['date_internal']) ? $value['date_internal'] : '',
]
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php b/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php
index 2390a049fbeb6..c388be8b6f394 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php
@@ -279,7 +279,7 @@ public function getFormattedOptionValue($optionValue)
*/
public function getCustomizedView($optionInfo)
{
- return isset($optionInfo['value']) ? $optionInfo['value'] : $optionInfo;
+ return $optionInfo['value'] ?? $optionInfo;
}
/**
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php
index 1e5c7f76d829b..99d5016f5cdb9 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/DefaultValidator.php
@@ -9,6 +9,9 @@
use Magento\Catalog\Model\Product\Option;
use Zend_Validate_Exception;
+/**
+ * Product option default validator
+ */
class DefaultValidator extends \Magento\Framework\Validator\AbstractValidator
{
/**
@@ -106,7 +109,9 @@ protected function isValidOptionTitle($title, $storeId)
if ($storeId > \Magento\Store\Model\Store::DEFAULT_STORE_ID && $title === null) {
return true;
}
- if ($this->isEmpty($title)) {
+
+ // checking whether title is null and is empty string
+ if ($title === null || $title === '') {
return false;
}
@@ -132,7 +137,7 @@ protected function validateOptionType(Option $option)
*/
protected function validateOptionValue(Option $option)
{
- return $this->isInRange($option->getPriceType(), $this->priceTypes) && !$this->isNegative($option->getPrice());
+ return $this->isInRange($option->getPriceType(), $this->priceTypes);
}
/**
@@ -166,6 +171,6 @@ protected function isInRange($value, array $range)
*/
protected function isNegative($value)
{
- return intval($value) < 0;
+ return (int) $value < 0;
}
}
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php
index 1e00654249556..2256f031098f1 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Pool.php
@@ -29,6 +29,6 @@ public function __construct(array $validators)
*/
public function get($type)
{
- return isset($this->validators[$type]) ? $this->validators[$type] : $this->validators['default'];
+ return $this->validators[$type] ?? $this->validators['default'];
}
}
diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php
index f04ab497e1d4f..44756890b6ed7 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Select.php
@@ -83,7 +83,7 @@ protected function isValidOptionPrice($priceType, $price, $storeId)
if (!$priceType && !$price) {
return true;
}
- if (!$this->isInRange($priceType, $this->priceTypes) || $this->isNegative($price)) {
+ if (!$this->isInRange($priceType, $this->priceTypes)) {
return false;
}
diff --git a/app/code/Magento/Catalog/Model/Product/PriceModifier.php b/app/code/Magento/Catalog/Model/Product/PriceModifier.php
index 48d53b4614527..c4d5bdfedcd5f 100644
--- a/app/code/Magento/Catalog/Model/Product/PriceModifier.php
+++ b/app/code/Magento/Catalog/Model/Product/PriceModifier.php
@@ -9,6 +9,9 @@
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\NoSuchEntityException;
+/**
+ * Product form price modifier
+ */
class PriceModifier
{
/**
@@ -26,6 +29,8 @@ public function __construct(
}
/**
+ * Remove tier price
+ *
* @param \Magento\Catalog\Model\Product $product
* @param int|string $customerGroupId
* @param int $qty
@@ -46,11 +51,11 @@ public function removeTierPrice(\Magento\Catalog\Model\Product $product, $custom
foreach ($prices as $key => $tierPrice) {
if ($customerGroupId == 'all' && $tierPrice['price_qty'] == $qty
- && $tierPrice['all_groups'] == 1 && intval($tierPrice['website_id']) === intval($websiteId)
+ && $tierPrice['all_groups'] == 1 && (int) $tierPrice['website_id'] === (int) $websiteId
) {
unset($prices[$key]);
} elseif ($tierPrice['price_qty'] == $qty && $tierPrice['cust_group'] == $customerGroupId
- && intval($tierPrice['website_id']) === intval($websiteId)
+ && (int) $tierPrice['website_id'] === (int) $websiteId
) {
unset($prices[$key]);
}
diff --git a/app/code/Magento/Catalog/Model/Product/TierPriceManagement.php b/app/code/Magento/Catalog/Model/Product/TierPriceManagement.php
index 822959bfc8519..f2da1e770279e 100644
--- a/app/code/Magento/Catalog/Model/Product/TierPriceManagement.php
+++ b/app/code/Magento/Catalog/Model/Product/TierPriceManagement.php
@@ -15,6 +15,8 @@
use Magento\Framework\Exception\TemporaryStateExceptionInterface;
/**
+ * Product tier price management
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class TierPriceManagement implements \Magento\Catalog\Api\ProductTierPriceManagementInterface
@@ -82,7 +84,7 @@ public function __construct(
}
/**
- * {@inheritdoc}
+ * @inheritdoc
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
@@ -148,7 +150,7 @@ public function add($sku, $customerGroupId, $price, $qty)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function remove($sku, $customerGroupId, $qty)
{
@@ -163,7 +165,7 @@ public function remove($sku, $customerGroupId, $qty)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function getList($sku, $customerGroupId)
{
@@ -181,7 +183,7 @@ public function getList($sku, $customerGroupId)
$prices = [];
foreach ($product->getData('tier_price') as $price) {
- if ((is_numeric($customerGroupId) && intval($price['cust_group']) === intval($customerGroupId))
+ if ((is_numeric($customerGroupId) && (int) $price['cust_group'] === (int) $customerGroupId)
|| ($customerGroupId === 'all' && $price['all_groups'])
) {
/** @var \Magento\Catalog\Api\Data\ProductTierPriceInterface $tierPrice */
diff --git a/app/code/Magento/Catalog/Model/Product/Type.php b/app/code/Magento/Catalog/Model/Product/Type.php
index dc3971397acb2..4c973be20dee5 100644
--- a/app/code/Magento/Catalog/Model/Product/Type.php
+++ b/app/code/Magento/Catalog/Model/Product/Type.php
@@ -232,7 +232,7 @@ public function getOptions()
public function getOptionText($optionId)
{
$options = $this->getOptionArray();
- return isset($options[$optionId]) ? $options[$optionId] : null;
+ return $options[$optionId] ?? null;
}
/**
@@ -285,7 +285,7 @@ public function getTypesByPriority()
$types = $this->getTypes();
foreach ($types as $typeId => $typeInfo) {
- $priority = isset($typeInfo['index_priority']) ? abs(intval($typeInfo['index_priority'])) : 0;
+ $priority = isset($typeInfo['index_priority']) ? abs((int) $typeInfo['index_priority']) : 0;
if (!empty($typeInfo['composite'])) {
$compositePriority[$typeId] = $priority;
} else {
@@ -307,7 +307,7 @@ public function getTypesByPriority()
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function toOptionArray()
{
diff --git a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
index 1b5cf37f6cbb8..e6804d9246faa 100644
--- a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
+++ b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
@@ -935,7 +935,7 @@ public function getForceChildItemQtyChanges($product)
*/
public function prepareQuoteItemQty($qty, $product)
{
- return floatval($qty);
+ return (float)$qty;
}
/**
diff --git a/app/code/Magento/Catalog/Model/ProductLink/Repository.php b/app/code/Magento/Catalog/Model/ProductLink/Repository.php
index 5bac99dbebbb4..98977de7effaf 100644
--- a/app/code/Magento/Catalog/Model/ProductLink/Repository.php
+++ b/app/code/Magento/Catalog/Model/ProductLink/Repository.php
@@ -10,6 +10,7 @@
use Magento\Catalog\Api\Data\ProductLinkExtensionFactory;
use Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks as LinksInitializer;
use Magento\Catalog\Model\Product\LinkTypeProvider;
+use Magento\Framework\Api\SimpleDataObjectConverter;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\EntityManager\MetadataPool;
@@ -170,7 +171,7 @@ public function getList(\Magento\Catalog\Api\Data\ProductInterface $product)
foreach ($item['custom_attributes'] as $option) {
$name = $option['attribute_code'];
$value = $option['value'];
- $setterName = 'set'.ucfirst($name);
+ $setterName = 'set' . SimpleDataObjectConverter::snakeCaseToUpperCamelCase($name);
// Check if setter exists
if (method_exists($productLinkExtension, $setterName)) {
call_user_func([$productLinkExtension, $setterName], $value);
diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php
index 4c0122694285d..d124bf5e42639 100644
--- a/app/code/Magento/Catalog/Model/ProductRepository.php
+++ b/app/code/Magento/Catalog/Model/ProductRepository.php
@@ -7,9 +7,11 @@
namespace Magento\Catalog\Model;
+use Magento\Catalog\Api\Data\ProductExtension;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product\Gallery\MimeTypeExtensionMap;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
+use Magento\Eav\Model\Entity\Attribute\Exception as AttributeException;
use Magento\Framework\Api\Data\ImageContentInterface;
use Magento\Framework\Api\Data\ImageContentInterfaceFactory;
use Magento\Framework\Api\ImageContentValidatorInterface;
@@ -18,14 +20,17 @@
use Magento\Framework\DB\Adapter\ConnectionException;
use Magento\Framework\DB\Adapter\DeadlockException;
use Magento\Framework\DB\Adapter\LockWaitException;
+use Magento\Framework\EntityManager\Operation\Read\ReadExtensions;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Framework\Exception\TemporaryState\CouldNotSaveException as TemporaryCouldNotSaveException;
use Magento\Framework\Exception\StateException;
use Magento\Framework\Exception\ValidatorException;
/**
+ * Product Repository.
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyFields)
*/
@@ -151,6 +156,11 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
*/
private $serializer;
+ /**
+ * @var ReadExtensions
+ */
+ private $readExtensions;
+
/**
* ProductRepository constructor.
* @param ProductFactory $productFactory
@@ -176,6 +186,7 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
* @param CollectionProcessorInterface $collectionProcessor [optional]
* @param \Magento\Framework\Serialize\Serializer\Json|null $serializer
* @param int $cacheLimit [optional]
+ * @param ReadExtensions|null $readExtensions
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
@@ -202,7 +213,8 @@ public function __construct(
\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor,
CollectionProcessorInterface $collectionProcessor = null,
\Magento\Framework\Serialize\Serializer\Json $serializer = null,
- $cacheLimit = 1000
+ $cacheLimit = 1000,
+ ReadExtensions $readExtensions = null
) {
$this->productFactory = $productFactory;
$this->collectionFactory = $collectionFactory;
@@ -225,10 +237,12 @@ public function __construct(
$this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
->get(\Magento\Framework\Serialize\Serializer\Json::class);
$this->cacheLimit = (int)$cacheLimit;
+ $this->readExtensions = $readExtensions ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(ReadExtensions::class);
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function get($sku, $editMode = false, $storeId = null, $forceReload = false)
{
@@ -258,7 +272,7 @@ public function get($sku, $editMode = false, $storeId = null, $forceReload = fal
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function getById($productId, $editMode = false, $storeId = null, $forceReload = false)
{
@@ -306,10 +320,10 @@ protected function getCacheKey($data)
* Add product to internal cache and truncate cache if it has more than cacheLimit elements.
*
* @param string $cacheKey
- * @param \Magento\Catalog\Api\Data\ProductInterface $product
+ * @param ProductInterface $product
* @return void
*/
- private function cacheProduct($cacheKey, \Magento\Catalog\Api\Data\ProductInterface $product)
+ private function cacheProduct($cacheKey, ProductInterface $product)
{
$this->instancesById[$product->getId()][$cacheKey] = $product;
$this->saveProductInLocalCache($product, $cacheKey);
@@ -326,7 +340,7 @@ private function cacheProduct($cacheKey, \Magento\Catalog\Api\Data\ProductInterf
*
* @param array $productData
* @param bool $createNew
- * @return \Magento\Catalog\Api\Data\ProductInterface|Product
+ * @return ProductInterface|Product
* @throws NoSuchEntityException
*/
protected function initializeProductData(array $productData, $createNew)
@@ -348,6 +362,8 @@ protected function initializeProductData(array $productData, $createNew)
}
/**
+ * Assign product to websites.
+ *
* @param \Magento\Catalog\Model\Product $product
* @return void
*/
@@ -363,6 +379,8 @@ private function assignProductToWebsites(\Magento\Catalog\Model\Product $product
}
/**
+ * Process new gallery media entry.
+ *
* @param ProductInterface $product
* @param array $newEntry
* @return $this
@@ -414,12 +432,12 @@ protected function processNewMediaGalleryEntry(
/**
* Process product links, creating new links, updating and deleting existing links
*
- * @param \Magento\Catalog\Api\Data\ProductInterface $product
+ * @param ProductInterface $product
* @param \Magento\Catalog\Api\Data\ProductLinkInterface[] $newLinks
* @return $this
* @throws NoSuchEntityException
*/
- private function processLinks(\Magento\Catalog\Api\Data\ProductInterface $product, $newLinks)
+ private function processLinks(ProductInterface $product, $newLinks)
{
if ($newLinks === null) {
// If product links were not specified, don't do anything
@@ -514,13 +532,14 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
$newEntries = $mediaGalleryEntries;
}
+ $images = (array)$product->getMediaGallery('images');
+ $images = $this->determineImageRoles($product, $images);
+
$this->getMediaGalleryProcessor()->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
- $images = $product->getMediaGallery('images');
- if ($images) {
- foreach ($images as $image) {
- if (!isset($image['removed']) && !empty($image['types'])) {
- $this->getMediaGalleryProcessor()->setMediaAttribute($product, $image['types'], $image['file']);
- }
+
+ foreach ($images as $image) {
+ if (!isset($image['removed']) && !empty($image['types'])) {
+ $this->getMediaGalleryProcessor()->setMediaAttribute($product, $image['types'], $image['file']);
}
}
@@ -547,11 +566,11 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
}
/**
- * {@inheritdoc}
+ * @inheritdoc
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
- public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveOptions = false)
+ public function save(ProductInterface $product, $saveOptions = false)
{
$tierPrices = $product->getData('tier_price');
@@ -565,12 +584,18 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
if (!$product->hasData(Product::STATUS)) {
$product->setStatus($existingProduct->getStatus());
}
+
+ /** @var ProductExtension $extensionAttributes */
+ $extensionAttributes = $product->getExtensionAttributes();
+ if (empty($extensionAttributes->__toArray())) {
+ $product->setExtensionAttributes($existingProduct->getExtensionAttributes());
+ }
} catch (NoSuchEntityException $e) {
$existingProduct = null;
}
$productDataArray = $this->extensibleDataObjectConverter
- ->toNestedArray($product, [], \Magento\Catalog\Api\Data\ProductInterface::class);
+ ->toNestedArray($product, [], ProductInterface::class);
$productDataArray = array_replace($productDataArray, $product->getData());
$ignoreLinksFlag = $product->getData('ignore_links_flag');
$productLinks = null;
@@ -596,47 +621,11 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
);
}
- try {
- if ($tierPrices !== null) {
- $product->setData('tier_price', $tierPrices);
- }
- $this->removeProductFromLocalCache($product->getSku());
- unset($this->instancesById[$product->getId()]);
- $this->resourceModel->save($product);
- } catch (ConnectionException $exception) {
- throw new \Magento\Framework\Exception\TemporaryState\CouldNotSaveException(
- __('Database connection error'),
- $exception,
- $exception->getCode()
- );
- } catch (DeadlockException $exception) {
- throw new \Magento\Framework\Exception\TemporaryState\CouldNotSaveException(
- __('Database deadlock found when trying to get lock'),
- $exception,
- $exception->getCode()
- );
- } catch (LockWaitException $exception) {
- throw new \Magento\Framework\Exception\TemporaryState\CouldNotSaveException(
- __('Database lock wait timeout exceeded'),
- $exception,
- $exception->getCode()
- );
- } catch (\Magento\Eav\Model\Entity\Attribute\Exception $exception) {
- throw \Magento\Framework\Exception\InputException::invalidFieldValue(
- $exception->getAttributeCode(),
- $product->getData($exception->getAttributeCode()),
- $exception
- );
- } catch (ValidatorException $e) {
- throw new CouldNotSaveException(__($e->getMessage()));
- } catch (LocalizedException $e) {
- throw $e;
- } catch (\Exception $e) {
- throw new \Magento\Framework\Exception\CouldNotSaveException(
- __('The product was unable to be saved. Please try again.'),
- $e
- );
+ if ($tierPrices !== null) {
+ $product->setData('tier_price', $tierPrices);
}
+
+ $this->saveProduct($product);
$this->removeProductFromLocalCache($product->getSku());
unset($this->instancesById[$product->getId()]);
@@ -644,9 +633,9 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
- public function delete(\Magento\Catalog\Api\Data\ProductInterface $product)
+ public function delete(ProductInterface $product)
{
$sku = $product->getSku();
$productId = $product->getId();
@@ -668,7 +657,7 @@ public function delete(\Magento\Catalog\Api\Data\ProductInterface $product)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function deleteById($sku)
{
@@ -677,7 +666,7 @@ public function deleteById($sku)
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria)
{
@@ -694,6 +683,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr
$collection->load();
$collection->addCategoryIds();
+ $this->addExtensionAttributes($collection);
$searchResult = $this->searchResultsFactory->create();
$searchResult->setSearchCriteria($searchCriteria);
$searchResult->setItems($collection->getItems());
@@ -704,7 +694,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr
$this->getCacheKey(
[
false,
- $product->hasData(\Magento\Catalog\Model\Product::STORE_ID) ? $product->getStoreId() : null
+ $product->getStoreId()
]
),
$product
@@ -714,6 +704,20 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr
return $searchResult;
}
+ /**
+ * Add extension attributes to loaded items.
+ *
+ * @param Collection $collection
+ * @return Collection
+ */
+ private function addExtensionAttributes(Collection $collection) : Collection
+ {
+ foreach ($collection->getItems() as $item) {
+ $this->readExtensions->execute($item);
+ }
+ return $collection;
+ }
+
/**
* Helper function that adds a FilterGroup to the collection.
*
@@ -759,6 +763,34 @@ public function cleanCache()
}
/**
+ * Ascertain image roles, if they are not set against the gallery entries
+ *
+ * @param ProductInterface $product
+ * @param array $images
+ * @return array
+ */
+ private function determineImageRoles(ProductInterface $product, array $images) : array
+ {
+ $imagesWithRoles = [];
+ foreach ($images as $image) {
+ if (!isset($image['types'])) {
+ $image['types'] = [];
+ if (isset($image['file'])) {
+ foreach (array_keys($product->getMediaAttributes()) as $attribute) {
+ if ($image['file'] == $product->getData($attribute)) {
+ $image['types'][] = $attribute;
+ }
+ }
+ }
+ }
+ $imagesWithRoles[] = $image;
+ }
+ return $imagesWithRoles;
+ }
+
+ /**
+ * Retrieve media gallery processor.
+ *
* @return Product\Gallery\Processor
*/
private function getMediaGalleryProcessor()
@@ -835,4 +867,55 @@ private function prepareSku(string $sku): string
{
return mb_strtolower(trim($sku));
}
+
+ /**
+ * Save product resource model.
+ *
+ * @param ProductInterface|Product $product
+ * @throws TemporaryCouldNotSaveException
+ * @throws InputException
+ * @throws CouldNotSaveException
+ * @throws LocalizedException
+ */
+ private function saveProduct($product): void
+ {
+ try {
+ $this->removeProductFromLocalCache($product->getSku());
+ unset($this->instancesById[$product->getId()]);
+ $this->resourceModel->save($product);
+ } catch (ConnectionException $exception) {
+ throw new TemporaryCouldNotSaveException(
+ __('Database connection error'),
+ $exception,
+ $exception->getCode()
+ );
+ } catch (DeadlockException $exception) {
+ throw new TemporaryCouldNotSaveException(
+ __('Database deadlock found when trying to get lock'),
+ $exception,
+ $exception->getCode()
+ );
+ } catch (LockWaitException $exception) {
+ throw new TemporaryCouldNotSaveException(
+ __('Database lock wait timeout exceeded'),
+ $exception,
+ $exception->getCode()
+ );
+ } catch (AttributeException $exception) {
+ throw InputException::invalidFieldValue(
+ $exception->getAttributeCode(),
+ $product->getData($exception->getAttributeCode()),
+ $exception
+ );
+ } catch (ValidatorException $e) {
+ throw new CouldNotSaveException(__($e->getMessage()));
+ } catch (LocalizedException $e) {
+ throw $e;
+ } catch (\Exception $e) {
+ throw new CouldNotSaveException(
+ __('The product was unable to be saved. Please try again.'),
+ $e
+ );
+ }
+ }
}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
index fa68ae3f865ef..1523809d9cc33 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
@@ -16,6 +16,8 @@
use Magento\Framework\EntityManager\EntityManager;
/**
+ * Resource model for category entity
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Category extends AbstractResource
@@ -249,7 +251,8 @@ public function deleteChildren(\Magento\Framework\DataObject $object)
/**
* Process category data before saving
- * prepare path and increment children count for parent categories
+ *
+ * Prepare path and increment children count for parent categories
*
* @param \Magento\Framework\DataObject $object
* @return $this
@@ -298,7 +301,8 @@ protected function _beforeSave(\Magento\Framework\DataObject $object)
/**
* Process category data after save category object
- * save related products ids and update path value
+ *
+ * Save related products ids and update path value
*
* @param \Magento\Framework\DataObject $object
* @return $this
@@ -490,7 +494,7 @@ public function getProductsPosition($category)
}
/**
- * Get chlden categories count
+ * Get children categories count
*
* @param int $categoryId
* @return int
@@ -664,7 +668,7 @@ public function getProductCount($category)
$bind = ['category_id' => (int)$category->getId()];
$counts = $this->getConnection()->fetchOne($select, $bind);
- return intval($counts);
+ return (int) $counts;
}
/**
@@ -862,6 +866,7 @@ public function isInRootCategoryList($category)
/**
* Check category is forbidden to delete.
+ *
* If category is root and assigned to store group return false
*
* @param integer $categoryId
@@ -982,6 +987,7 @@ public function changeParent(
/**
* Process positions of old parent category children and new parent category children.
+ *
* Get position for moved category
*
* @param \Magento\Catalog\Model\Category $category
@@ -1062,7 +1068,7 @@ public function load($object, $entityId, $attributes = [])
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function delete($object)
{
@@ -1088,6 +1094,8 @@ public function save(\Magento\Framework\Model\AbstractModel $object)
}
/**
+ * Returns EntityManager object
+ *
* @return EntityManager
*/
private function getEntityManager()
@@ -1100,6 +1108,8 @@ private function getEntityManager()
}
/**
+ * Returns AggregateCount object
+ *
* @return Category\AggregateCount
*/
private function getAggregateCount()
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php
index 01e4b072b0367..9db2c8248ce52 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php
@@ -173,7 +173,7 @@ public function getMainTable()
public function getMainStoreTable($storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID)
{
if (is_string($storeId)) {
- $storeId = intval($storeId);
+ $storeId = (int) $storeId;
}
if ($storeId) {
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat/Collection.php
index 3b3005f1ce65a..03e33365b776b 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat/Collection.php
@@ -12,11 +12,13 @@
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
use Psr\Log\LoggerInterface as Logger;
use Magento\Store\Model\StoreManagerInterface;
+use Magento\Store\Model\ScopeInterface;
/**
* Catalog category flat collection
*
* @author Magento Core Team
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
@@ -48,12 +50,20 @@ class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\Ab
*/
protected $_storeId;
+ /**
+ * Core store config
+ *
+ * @var \Magento\Framework\App\Config\ScopeConfigInterface
+ */
+ private $scopeConfig;
+
/**
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
* @param Logger $logger
* @param FetchStrategyInterface $fetchStrategy
* @param ManagerInterface $eventManager
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
+ * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
* @param AbstractDb $resource
*/
@@ -63,10 +73,12 @@ public function __construct(
FetchStrategyInterface $fetchStrategy,
ManagerInterface $eventManager,
StoreManagerInterface $storeManager,
+ \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
AbstractDb $resource = null
) {
$this->_storeManager = $storeManager;
+ $this->scopeConfig = $scopeConfig;
parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
}
@@ -387,4 +399,21 @@ public function setPage($pageNum, $pageSize)
$this->setCurPage($pageNum)->setPageSize($pageSize);
return $this;
}
+
+ /**
+ * Add navigation max depth filter
+ *
+ * @return $this
+ */
+ public function addNavigationMaxDepthFilter()
+ {
+ $navigationMaxDepth = (int)$this->scopeConfig->getValue(
+ 'catalog/navigation/max_depth',
+ ScopeInterface::SCOPE_STORE
+ );
+ if ($navigationMaxDepth > 0) {
+ $this->addLevelFilter($navigationMaxDepth);
+ }
+ return $this;
+ }
}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/StateDependentCollectionFactory.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/StateDependentCollectionFactory.php
new file mode 100644
index 0000000000000..fc476ab6ff286
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/StateDependentCollectionFactory.php
@@ -0,0 +1,55 @@
+objectManager = $objectManager;
+ $this->catalogCategoryFlatState = $catalogCategoryFlatState;
+ }
+
+ /**
+ * Create class instance with specified parameters
+ *
+ * @param array $data
+ * @return \Magento\Framework\Data\Collection\AbstractDb
+ */
+ public function create(array $data = [])
+ {
+ return $this->objectManager->create(
+ ($this->catalogCategoryFlatState->isAvailable()) ? Flat\Collection::class : Collection::class,
+ $data
+ );
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php b/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php
index bed129e19168f..585da2af529a4 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Layer/Filter/Price.php
@@ -5,6 +5,15 @@
*/
namespace Magento\Catalog\Model\ResourceModel\Layer\Filter;
+use Magento\Framework\App\Http\Context;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Indexer\DimensionFactory;
+use Magento\Framework\Search\Request\IndexScopeResolverInterface;
+use Magento\Store\Model\StoreManagerInterface;
+use Magento\Customer\Model\Context as CustomerContext;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
+
/**
* Catalog Layer Price Filter resource model
*
@@ -41,6 +50,21 @@ class Price extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
*/
private $storeManager;
+ /**
+ * @var IndexScopeResolverInterface|null
+ */
+ private $priceTableResolver;
+
+ /**
+ * @var Context
+ */
+ private $httpContext;
+
+ /**
+ * @var DimensionFactory|null
+ */
+ private $dimensionFactory;
+
/**
* @param \Magento\Framework\Model\ResourceModel\Db\Context $context
* @param \Magento\Framework\Event\ManagerInterface $eventManager
@@ -48,6 +72,9 @@ class Price extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
* @param \Magento\Customer\Model\Session $session
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param null $connectionName
+ * @param IndexScopeResolverInterface|null $priceTableResolver
+ * @param Context|null $httpContext
+ * @param DimensionFactory|null $dimensionFactory
*/
public function __construct(
\Magento\Framework\Model\ResourceModel\Db\Context $context,
@@ -55,12 +82,19 @@ public function __construct(
\Magento\Catalog\Model\Layer\Resolver $layerResolver,
\Magento\Customer\Model\Session $session,
\Magento\Store\Model\StoreManagerInterface $storeManager,
- $connectionName = null
+ $connectionName = null,
+ IndexScopeResolverInterface $priceTableResolver = null,
+ Context $httpContext = null,
+ DimensionFactory $dimensionFactory = null
) {
$this->layer = $layerResolver->get();
$this->session = $session;
$this->storeManager = $storeManager;
$this->_eventManager = $eventManager;
+ $this->priceTableResolver = $priceTableResolver
+ ?? ObjectManager::getInstance()->get(IndexScopeResolverInterface::class);
+ $this->httpContext = $httpContext ?? ObjectManager::getInstance()->get(Context::class);
+ $this->dimensionFactory = $dimensionFactory ?? ObjectManager::getInstance()->get(DimensionFactory::class);
parent::__construct($context, $connectionName);
}
@@ -78,7 +112,7 @@ public function getCount($range)
/**
* Check and set correct variable values to prevent SQL-injections
*/
- $range = floatval($range);
+ $range = (float)$range;
if ($range == 0) {
$range = 1;
}
@@ -118,11 +152,8 @@ protected function _getSelect()
// remove join with main table
$fromPart = $select->getPart(\Magento\Framework\DB\Select::FROM);
- if (!isset(
- $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS]
- ) || !isset(
- $fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS]
- )
+ if (!isset($fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::INDEX_TABLE_ALIAS]) ||
+ !isset($fromPart[\Magento\Catalog\Model\ResourceModel\Product\Collection::MAIN_TABLE_ALIAS])
) {
return $select;
}
@@ -376,6 +407,30 @@ protected function _construct()
$this->_init('catalog_product_index_price', 'entity_id');
}
+ /**
+ * {@inheritdoc}
+ * @return string
+ */
+ public function getMainTable()
+ {
+ $storeKey = $this->httpContext->getValue(StoreManagerInterface::CONTEXT_STORE);
+ $priceTableName = $this->priceTableResolver->resolve(
+ 'catalog_product_index_price',
+ [
+ $this->dimensionFactory->create(
+ WebsiteDimensionProvider::DIMENSION_NAME,
+ (string)$this->storeManager->getStore($storeKey)->getWebsiteId()
+ ),
+ $this->dimensionFactory->create(
+ CustomerGroupDimensionProvider::DIMENSION_NAME,
+ (string)$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP)
+ )
+ ]
+ );
+
+ return $this->getTable($priceTableName);
+ }
+
/**
* Retrieve joined price index table alias
*
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/BaseSelectProcessorInterface.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/BaseSelectProcessorInterface.php
index d97f6bebf4e91..da3c4fb4417f2 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/BaseSelectProcessorInterface.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/BaseSelectProcessorInterface.php
@@ -9,6 +9,7 @@
/**
* Interface BaseSelectProcessorInterface
+ *
* @api
* @since 101.0.3
*/
@@ -20,6 +21,8 @@ interface BaseSelectProcessorInterface
const PRODUCT_TABLE_ALIAS = 'child';
/**
+ * Process the select statement
+ *
* @param Select $select
* @return Select
* @since 101.0.3
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
index 9b87515450a12..fdd98442150ae 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
@@ -12,11 +12,15 @@
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
use Magento\Customer\Api\GroupManagementInterface;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\DB\Select;
use Magento\Framework\EntityManager\MetadataPool;
+use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
use Magento\Store\Model\Store;
use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
+use Magento\Framework\Indexer\DimensionFactory;
/**
* Product collection
@@ -276,9 +280,18 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
*/
private $tableMaintainer;
+ /**
+ * @var PriceTableResolver
+ */
+ private $priceTableResolver;
+
+ /**
+ * @var DimensionFactory
+ */
+ private $dimensionFactory;
+
/**
* Collection constructor
- *
* @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
* @param \Psr\Log\LoggerInterface $logger
* @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
@@ -302,7 +315,8 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
* @param ProductLimitationFactory|null $productLimitationFactory
* @param MetadataPool|null $metadataPool
* @param TableMaintainer|null $tableMaintainer
- *
+ * @param PriceTableResolver|null $priceTableResolver
+ * @param DimensionFactory|null $dimensionFactory
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -328,7 +342,9 @@ public function __construct(
\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
ProductLimitationFactory $productLimitationFactory = null,
MetadataPool $metadataPool = null,
- TableMaintainer $tableMaintainer = null
+ TableMaintainer $tableMaintainer = null,
+ PriceTableResolver $priceTableResolver = null,
+ DimensionFactory $dimensionFactory = null
) {
$this->moduleManager = $moduleManager;
$this->_catalogProductFlatState = $catalogProductFlatState;
@@ -359,6 +375,9 @@ public function __construct(
$connection
);
$this->tableMaintainer = $tableMaintainer ?: ObjectManager::getInstance()->get(TableMaintainer::class);
+ $this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get(PriceTableResolver::class);
+ $this->dimensionFactory = $dimensionFactory
+ ?: ObjectManager::getInstance()->get(DimensionFactory::class);
}
/**
@@ -455,8 +474,7 @@ public function getFlatState()
}
/**
- * Retrieve is flat enabled flag
- * Return always false if magento run admin
+ * Retrieve is flat enabled. Return always false if magento run admin.
*
* @return bool
*/
@@ -487,8 +505,7 @@ protected function _construct()
}
/**
- * Standard resource collection initialization
- * Needed for child classes
+ * Standard resource collection initialization. Needed for child classes.
*
* @param string $model
* @param string $entityModel
@@ -527,8 +544,7 @@ protected function _prepareStaticFields()
}
/**
- * Retrieve collection empty item
- * Redeclared for specifying id field name without getting resource model inside model
+ * Get collection empty item. Redeclared for specifying id field name without getting resource model inside model.
*
* @return \Magento\Framework\DataObject
*/
@@ -614,8 +630,7 @@ public function _loadAttributes($printQuery = false, $logQuery = false)
}
/**
- * Add attribute to entities in collection
- * If $attribute=='*' select all attributes
+ * Add attribute to entities in collection. If $attribute=='*' select all attributes.
*
* @param array|string|integer|\Magento\Framework\App\Config\Element $attribute
* @param bool|string $joinType
@@ -651,8 +666,7 @@ public function addAttributeToSelect($attribute, $joinType = false)
}
/**
- * Processing collection items after loading
- * Adding url rewrites, minimal prices, final prices, tax percents
+ * Processing collection items after loading. Adding url rewrites, minimal prices, final prices, tax percents.
*
* @return $this
*/
@@ -663,6 +677,7 @@ protected function _afterLoad()
}
$this->_prepareUrlDataObject();
+ $this->prepareStoreId();
if (count($this)) {
$this->_eventManager->dispatch('catalog_product_collection_load_after', ['collection' => $this]);
@@ -671,6 +686,23 @@ protected function _afterLoad()
return $this;
}
+ /**
+ * Add Store ID to products from collection.
+ *
+ * @return $this
+ */
+ protected function prepareStoreId()
+ {
+ if ($this->getStoreId() !== null) {
+ /** @var $item \Magento\Catalog\Model\Product */
+ foreach ($this->_items as $item) {
+ $item->setStoreId($this->getStoreId());
+ }
+ }
+
+ return $this;
+ }
+
/**
* Prepare Url Data object
*
@@ -737,8 +769,7 @@ public function addIdFilter($productId, $exclude = false)
}
/**
- * Adding product website names to result collection
- * Add for each product websites information
+ * Adding product website names to result collection. Add for each product websites information.
*
* @return $this
*/
@@ -749,7 +780,7 @@ public function addWebsiteNamesToResult()
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function load($printQuery = false, $logQuery = false)
{
@@ -800,14 +831,14 @@ protected function doAddWebsiteNamesToResult()
foreach ($this as $product) {
if (isset($productWebsites[$product->getId()])) {
$product->setData('websites', $productWebsites[$product->getId()]);
+ $product->setData('website_ids', $productWebsites[$product->getId()]);
}
}
return $this;
}
/**
- * Add store availability filter. Include availability product
- * for store website
+ * Add store availability filter. Include availability product for store website.
*
* @param null|string|bool|int|Store $store
* @return $this
@@ -913,7 +944,7 @@ private function mapConditionType($conditionType)
'eq' => 'in',
'neq' => 'nin'
];
- return isset($conditionsMap[$conditionType]) ? $conditionsMap[$conditionType] : $conditionType;
+ return $conditionsMap[$conditionType] ?? $conditionType;
}
/**
@@ -1061,14 +1092,15 @@ public function getAllAttributeValues($attribute)
$select = clone $this->getSelect();
$attribute = $this->getEntity()->getAttribute($attribute);
- $aiField = $this->getConnection()->getAutoIncrementField($this->getMainTable());
+ $fieldMainTable = $this->getConnection()->getAutoIncrementField($this->getMainTable());
+ $fieldJoinTable = $attribute->getEntity()->getLinkField();
$select->reset()
->from(
['cpe' => $this->getMainTable()],
['entity_id']
)->join(
['cpa' => $attribute->getBackend()->getTable()],
- 'cpe.' . $aiField . ' = cpa.' . $aiField,
+ 'cpe.' . $fieldMainTable . ' = cpa.' . $fieldJoinTable,
['store_id', 'value']
)->where('attribute_id = ?', (int)$attribute->getId());
@@ -1095,11 +1127,11 @@ public function getSelectCountSql()
/**
* Get SQL for get record count
*
- * @param null $select
+ * @param Select $select
* @param bool $resetLeftJoins
- * @return \Magento\Framework\DB\Select
+ * @return Select
*/
- protected function _getSelectCountSql($select = null, $resetLeftJoins = true)
+ protected function _getSelectCountSql(?Select $select = null, $resetLeftJoins = true)
{
$this->_renderFilters();
$countSelect = $select === null ? $this->_getClearSelect() : $this->_buildClearSelect($select);
@@ -1337,8 +1369,7 @@ public function joinUrlRewrite()
}
/**
- * Add URL rewrites data to product
- * If collection loadded - run processing else set flag
+ * Add URL rewrites data to product. If collection loadded - run processing else set flag.
*
* @param int|string $categoryId
* @return $this
@@ -1561,7 +1592,8 @@ public function addAttributeToFilter($attribute, $condition = null, $joinType =
}
/**
- * {@inheritdoc}
+ * @inheritdoc
+ *
* @since 101.0.0
*/
protected function getEntityPkName(\Magento\Eav\Model\Entity\AbstractEntity $entity)
@@ -1680,7 +1712,7 @@ public function addAttributeToSort($attribute, $dir = self::SORT_ORDER_ASC)
return $this;
} elseif ($attribute == 'is_saleable') {
- $this->getSelect()->order("is_saleable " . $dir);
+ $this->getSelect()->order("is_salable " . $dir);
return $this;
}
@@ -1863,7 +1895,12 @@ protected function _productLimitationJoinPrice()
protected function _productLimitationPrice($joinLeft = false)
{
$filters = $this->_productLimitationFilters;
- if (!$filters->isUsingPriceIndex()) {
+ if (!$filters->isUsingPriceIndex() ||
+ !isset($filters['website_id']) ||
+ (string)$filters['website_id'] === '' ||
+ !isset($filters['customer_group_id']) ||
+ (string)$filters['customer_group_id'] === ''
+ ) {
return $this;
}
@@ -1898,7 +1935,23 @@ protected function _productLimitationPrice($joinLeft = false)
'max_price',
'tier_price',
];
- $tableName = ['price_index' => $this->getTable('catalog_product_index_price')];
+
+ $tableName = [
+ 'price_index' => $this->priceTableResolver->resolve(
+ 'catalog_product_index_price',
+ [
+ $this->dimensionFactory->create(
+ CustomerGroupDimensionProvider::DIMENSION_NAME,
+ (string)$filters['customer_group_id']
+ ),
+ $this->dimensionFactory->create(
+ WebsiteDimensionProvider::DIMENSION_NAME,
+ (string)$filters['website_id']
+ )
+ ]
+ )
+ ];
+
if ($joinLeft) {
$select->joinLeft($tableName, $joinCond, $colls);
} else {
@@ -2228,6 +2281,7 @@ public function addPriceDataFieldFilter($comparisonFormat, $fields)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @since 101.0.1
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
public function addMediaGalleryData()
{
@@ -2239,34 +2293,36 @@ public function addMediaGalleryData()
return $this;
}
- /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
- $attribute = $this->getAttribute('media_gallery');
- $select = $this->getMediaGalleryResource()->createBatchBaseSelect(
- $this->getStoreId(),
- $attribute->getAttributeId()
- );
-
- $mediaGalleries = [];
- $linkField = $this->getProductEntityMetadata()->getLinkField();
$items = $this->getItems();
+ $linkField = $this->getProductEntityMetadata()->getLinkField();
- $select->where(
- 'entity.' . $linkField . ' IN (?)',
- array_map(
- function ($item) use ($linkField) {
- return $item->getData($linkField);
- },
- $items
- )
- );
+ $select = $this->getMediaGalleryResource()
+ ->createBatchBaseSelect(
+ $this->getStoreId(),
+ $this->getAttribute('media_gallery')->getAttributeId()
+ )->reset(
+ Select::ORDER // we don't care what order is in current scenario
+ )->where(
+ 'entity.' . $linkField . ' IN (?)',
+ array_map(
+ function ($item) use ($linkField) {
+ return (int) $item->getOrigData($linkField);
+ },
+ $items
+ )
+ );
+
+ $mediaGalleries = [];
foreach ($this->getConnection()->fetchAll($select) as $row) {
$mediaGalleries[$row[$linkField]][] = $row;
}
foreach ($items as $item) {
- $mediaEntries = isset($mediaGalleries[$item->getData($linkField)]) ?
- $mediaGalleries[$item->getData($linkField)] : [];
- $this->getGalleryReadHandler()->addMediaDataToProduct($item, $mediaEntries);
+ $this->getGalleryReadHandler()
+ ->addMediaDataToProduct(
+ $item,
+ $mediaGalleries[$item->getOrigData($linkField)] ?? []
+ );
}
$this->setFlag('media_gallery_added', true);
@@ -2299,7 +2355,10 @@ private function getGalleryReadHandler()
}
/**
+ * Retrieve Media gallery resource.
+ *
* @deprecated 101.0.1
+ *
* @return \Magento\Catalog\Model\ResourceModel\Product\Gallery
*/
private function getMediaGalleryResource()
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
index ee1df8f23424d..ebe04fb63b217 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php
@@ -7,9 +7,13 @@
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
+use Magento\Customer\Model\Indexer\CustomerGroupDimensionProvider;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\DB\Select;
use Magento\Catalog\Model\ResourceModel\Product\LinkedProductSelectBuilderInterface;
+use Magento\Framework\Indexer\DimensionFactory;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
+use Magento\Framework\Search\Request\IndexScopeResolverInterface;
class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuilderInterface
{
@@ -38,6 +42,16 @@ class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuild
*/
private $baseSelectProcessor;
+ /**
+ * @var IndexScopeResolverInterface|null
+ */
+ private $priceTableResolver;
+
+ /**
+ * @var DimensionFactory|null
+ */
+ private $dimensionFactory;
+
/**
* LinkedProductSelectBuilderByIndexPrice constructor.
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -45,13 +59,17 @@ class LinkedProductSelectBuilderByIndexPrice implements LinkedProductSelectBuild
* @param \Magento\Customer\Model\Session $customerSession
* @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
* @param BaseSelectProcessorInterface|null $baseSelectProcessor
+ * @param IndexScopeResolverInterface|null $priceTableResolver
+ * @param DimensionFactory|null $dimensionFactory
*/
public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\App\ResourceConnection $resourceConnection,
\Magento\Customer\Model\Session $customerSession,
\Magento\Framework\EntityManager\MetadataPool $metadataPool,
- BaseSelectProcessorInterface $baseSelectProcessor = null
+ BaseSelectProcessorInterface $baseSelectProcessor = null,
+ IndexScopeResolverInterface $priceTableResolver = null,
+ DimensionFactory $dimensionFactory = null
) {
$this->storeManager = $storeManager;
$this->resource = $resourceConnection;
@@ -59,6 +77,9 @@ public function __construct(
$this->metadataPool = $metadataPool;
$this->baseSelectProcessor = (null !== $baseSelectProcessor)
? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class);
+ $this->priceTableResolver = $priceTableResolver
+ ?? ObjectManager::getInstance()->get(IndexScopeResolverInterface::class);
+ $this->dimensionFactory = $dimensionFactory ?? ObjectManager::getInstance()->get(DimensionFactory::class);
}
/**
@@ -68,6 +89,8 @@ public function build($productId)
{
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
$productTable = $this->resource->getTableName('catalog_product_entity');
+ $websiteId = $this->storeManager->getStore()->getWebsiteId();
+ $customerGroupId = $this->customerSession->getCustomerGroupId();
$priceSelect = $this->resource->getConnection()->select()
->from(['parent' => $productTable], '')
@@ -80,12 +103,20 @@ public function build($productId)
sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
['entity_id']
)->joinInner(
- ['t' => $this->resource->getTableName('catalog_product_index_price')],
+ [
+ 't' => $this->priceTableResolver->resolve('catalog_product_index_price', [
+ $this->dimensionFactory->create(WebsiteDimensionProvider::DIMENSION_NAME, (string)$websiteId),
+ $this->dimensionFactory->create(
+ CustomerGroupDimensionProvider::DIMENSION_NAME,
+ (string)$customerGroupId
+ ),
+ ])
+ ],
sprintf('t.entity_id = %s.entity_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS),
[]
)->where('parent.entity_id = ?', $productId)
- ->where('t.website_id = ?', $this->storeManager->getStore()->getWebsiteId())
- ->where('t.customer_group_id = ?', $this->customerSession->getCustomerGroupId())
+ ->where('t.website_id = ?', $websiteId)
+ ->where('t.customer_group_id = ?', $customerGroupId)
->order('t.min_price ' . Select::SQL_ASC)
->order(BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS . '.' . $linkField . ' ' . Select::SQL_ASC)
->limit(1);
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/BasePriceModifier.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/BasePriceModifier.php
new file mode 100644
index 0000000000000..cf5ba451c380e
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/BasePriceModifier.php
@@ -0,0 +1,38 @@
+priceModifiers = $priceModifiers;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void
+ {
+ foreach ($this->priceModifiers as $priceModifier) {
+ $priceModifier->modifyPrice($priceTable, $entityIds);
+ }
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php
index 24cb4fedd57e5..a499777df871a 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CompositeProductRowSizeEstimator.php
@@ -18,7 +18,7 @@ class CompositeProductRowSizeEstimator implements IndexTableRowSizeEstimatorInte
/**
* Calculated memory size for one record in catalog_product_index_price table
*/
- const MEMORY_SIZE_FOR_ONE_ROW = 250;
+ const MEMORY_SIZE_FOR_ONE_ROW = 200;
/**
* @var WebsiteManagementInterface
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CustomOptionPriceModifier.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CustomOptionPriceModifier.php
new file mode 100644
index 0000000000000..47fc6802d7eaf
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/CustomOptionPriceModifier.php
@@ -0,0 +1,464 @@
+resource = $resource;
+ $this->metadataPool = $metadataPool;
+ $this->connectionName = $connectionName;
+ $this->columnValueExpressionFactory = $columnValueExpressionFactory;
+ $this->dataHelper = $dataHelper;
+ $this->tableStrategy = $tableStrategy;
+ }
+
+ /**
+ * Apply custom option price to temporary index price table
+ *
+ * @param IndexTableStructure $priceTable
+ * @param array $entityIds
+ * @return void
+ * @throws \Exception
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) : void
+ {
+ // no need to run all queries if current products have no custom options
+ if (!$this->checkIfCustomOptionsExist($priceTable)) {
+ return;
+ }
+
+ $connection = $this->getConnection();
+ $finalPriceTable = $priceTable->getTableName();
+
+ $coaTable = $this->getCustomOptionAggregateTable();
+ $this->prepareCustomOptionAggregateTable();
+
+ $copTable = $this->getCustomOptionPriceTable();
+ $this->prepareCustomOptionPriceTable();
+
+ $select = $this->getSelectForOptionsWithMultipleValues($finalPriceTable);
+ $query = $select->insertFromSelect($coaTable);
+ $connection->query($query);
+
+ $select = $this->getSelectForOptionsWithOneValue($finalPriceTable);
+ $query = $select->insertFromSelect($coaTable);
+ $connection->query($query);
+
+ $select = $this->getSelectAggregated($coaTable);
+ $query = $select->insertFromSelect($copTable);
+ $connection->query($query);
+
+ // update tmp price index with prices from custom options (from previous aggregated table)
+ $select = $this->getSelectForUpdate($copTable);
+ $query = $select->crossUpdateFromSelect(['i' => $finalPriceTable]);
+ $connection->query($query);
+
+ $connection->delete($coaTable);
+ $connection->delete($copTable);
+ }
+
+ /**
+ * @param IndexTableStructure $priceTable
+ * @return bool
+ * @throws \Exception
+ */
+ private function checkIfCustomOptionsExist(IndexTableStructure $priceTable): bool
+ {
+ $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
+
+ $select = $this->getConnection()
+ ->select()
+ ->from(
+ ['i' => $priceTable->getTableName()],
+ ['entity_id']
+ )->join(
+ ['e' => $this->getTable('catalog_product_entity')],
+ 'e.entity_id = i.entity_id',
+ []
+ )->join(
+ ['o' => $this->getTable('catalog_product_option')],
+ 'o.product_id = e.' . $metadata->getLinkField(),
+ ['option_id']
+ );
+
+ return !empty($this->getConnection()->fetchRow($select));
+ }
+
+ /**
+ * @return \Magento\Framework\DB\Adapter\AdapterInterface
+ */
+ private function getConnection()
+ {
+ if (null === $this->connection) {
+ $this->connection = $this->resource->getConnection($this->connectionName);
+ }
+
+ return $this->connection;
+ }
+
+ /**
+ * Prepare prices for products with custom options that has multiple values
+ *
+ * @param string $sourceTable
+ * @return \Magento\Framework\DB\Select
+ * @throws \Exception
+ */
+ private function getSelectForOptionsWithMultipleValues(string $sourceTable): Select
+ {
+ $connection = $this->resource->getConnection($this->connectionName);
+ $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
+
+ $select = $connection->select()
+ ->from(
+ ['i' => $sourceTable],
+ ['entity_id', 'customer_group_id', 'website_id']
+ )->join(
+ ['e' => $this->getTable('catalog_product_entity')],
+ 'e.entity_id = i.entity_id',
+ []
+ )->join(
+ ['cwd' => $this->getTable('catalog_product_index_website')],
+ 'i.website_id = cwd.website_id',
+ []
+ )->join(
+ ['o' => $this->getTable('catalog_product_option')],
+ 'o.product_id = e.' . $metadata->getLinkField(),
+ ['option_id']
+ )->join(
+ ['ot' => $this->getTable('catalog_product_option_type_value')],
+ 'ot.option_id = o.option_id',
+ []
+ )->join(
+ ['otpd' => $this->getTable('catalog_product_option_type_price')],
+ 'otpd.option_type_id = ot.option_type_id AND otpd.store_id = 0',
+ []
+ )->group(
+ ['i.entity_id', 'i.customer_group_id', 'i.website_id', 'o.option_id']
+ );
+
+ if ($this->isPriceGlobal()) {
+ $optPriceType = 'otpd.price_type';
+ $optPriceValue = 'otpd.price';
+ } else {
+ $select->joinLeft(
+ ['otps' => $this->getTable('catalog_product_option_type_price')],
+ 'otps.option_type_id = otpd.option_type_id AND otpd.store_id = cwd.default_store_id',
+ []
+ );
+
+ $optPriceType = $connection->getCheckSql(
+ 'otps.option_type_price_id > 0',
+ 'otps.price_type',
+ 'otpd.price_type'
+ );
+ $optPriceValue = $connection->getCheckSql('otps.option_type_price_id > 0', 'otps.price', 'otpd.price');
+ }
+
+ $minPriceRound = $this->columnValueExpressionFactory
+ ->create([
+ 'expression' => "ROUND(i.final_price * ({$optPriceValue} / 100), 4)"
+ ]);
+ $minPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
+ $minPriceMin = $this->columnValueExpressionFactory
+ ->create([
+ 'expression' => "MIN({$minPriceExpr})"
+ ]);
+ $minPrice = $connection->getCheckSql("MIN(o.is_require) = 1", $minPriceMin, '0');
+
+ $tierPriceRound = $this->columnValueExpressionFactory
+ ->create([
+ 'expression' => "ROUND(i.tier_price * ({$optPriceValue} / 100), 4)"
+ ]);
+ $tierPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
+ $tierPriceMin = $this->columnValueExpressionFactory
+ ->create([
+ 'expression' => "MIN({$tierPriceExpr})"
+ ]);
+ $tierPriceValue = $connection->getCheckSql("MIN(o.is_require) > 0", $tierPriceMin, 0);
+ $tierPrice = $connection->getCheckSql("MIN(i.tier_price) IS NOT NULL", $tierPriceValue, "NULL");
+
+ $maxPriceRound = $this->columnValueExpressionFactory
+ ->create([
+ 'expression' => "ROUND(i.final_price * ({$optPriceValue} / 100), 4)"
+ ]);
+ $maxPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $maxPriceRound);
+ $maxPrice = $connection->getCheckSql(
+ "(MIN(o.type)='radio' OR MIN(o.type)='drop_down')",
+ "MAX({$maxPriceExpr})",
+ "SUM({$maxPriceExpr})"
+ );
+
+ $select->columns(
+ [
+ 'min_price' => $minPrice,
+ 'max_price' => $maxPrice,
+ 'tier_price' => $tierPrice,
+ ]
+ );
+
+ return $select;
+ }
+
+ /**
+ * Prepare prices for products with custom options that has single value
+ *
+ * @param string $sourceTable
+ * @return \Magento\Framework\DB\Select
+ * @throws \Exception
+ */
+ private function getSelectForOptionsWithOneValue(string $sourceTable): Select
+ {
+ $connection = $this->resource->getConnection($this->connectionName);
+ $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
+
+ $select = $connection->select()
+ ->from(
+ ['i' => $sourceTable],
+ ['entity_id', 'customer_group_id', 'website_id']
+ )->join(
+ ['e' => $this->getTable('catalog_product_entity')],
+ 'e.entity_id = i.entity_id',
+ []
+ )->join(
+ ['cwd' => $this->getTable('catalog_product_index_website')],
+ 'i.website_id = cwd.website_id',
+ []
+ )->join(
+ ['o' => $this->getTable('catalog_product_option')],
+ 'o.product_id = e.' . $metadata->getLinkField(),
+ ['option_id']
+ )->join(
+ ['opd' => $this->getTable('catalog_product_option_price')],
+ 'opd.option_id = o.option_id AND opd.store_id = 0',
+ []
+ );
+
+ if ($this->isPriceGlobal()) {
+ $optPriceType = 'opd.price_type';
+ $optPriceValue = 'opd.price';
+ } else {
+ $select->joinLeft(
+ ['ops' => $this->getTable('catalog_product_option_price')],
+ 'ops.option_id = opd.option_id AND ops.store_id = cwd.default_store_id',
+ []
+ );
+
+ $optPriceType = $connection->getCheckSql('ops.option_price_id > 0', 'ops.price_type', 'opd.price_type');
+ $optPriceValue = $connection->getCheckSql('ops.option_price_id > 0', 'ops.price', 'opd.price');
+ }
+
+ $minPriceRound = $this->columnValueExpressionFactory
+ ->create([
+ 'expression' => "ROUND(i.final_price * ({$optPriceValue} / 100), 4)"
+ ]);
+ $priceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $minPriceRound);
+ $minPrice = $connection->getCheckSql("{$priceExpr} > 0 AND o.is_require = 1", $priceExpr, 0);
+
+ $maxPrice = $priceExpr;
+
+ $tierPriceRound = $this->columnValueExpressionFactory
+ ->create([
+ 'expression' => "ROUND(i.tier_price * ({$optPriceValue} / 100), 4)"
+ ]);
+ $tierPriceExpr = $connection->getCheckSql("{$optPriceType} = 'fixed'", $optPriceValue, $tierPriceRound);
+ $tierPriceValue = $connection->getCheckSql("{$tierPriceExpr} > 0 AND o.is_require = 1", $tierPriceExpr, 0);
+ $tierPrice = $connection->getCheckSql("i.tier_price IS NOT NULL", $tierPriceValue, "NULL");
+
+ $select->columns(
+ [
+ 'min_price' => $minPrice,
+ 'max_price' => $maxPrice,
+ 'tier_price' => $tierPrice,
+ ]
+ );
+
+ return $select;
+ }
+
+ /**
+ * Aggregate prices with one and multiply options into one table
+ *
+ * @param string $sourceTable
+ * @return \Magento\Framework\DB\Select
+ */
+ private function getSelectAggregated(string $sourceTable): Select
+ {
+ $connection = $this->resource->getConnection($this->connectionName);
+
+ $select = $connection->select()
+ ->from(
+ [$sourceTable],
+ [
+ 'entity_id',
+ 'customer_group_id',
+ 'website_id',
+ 'min_price' => 'SUM(min_price)',
+ 'max_price' => 'SUM(max_price)',
+ 'tier_price' => 'SUM(tier_price)',
+ ]
+ )->group(
+ ['entity_id', 'customer_group_id', 'website_id']
+ );
+
+ return $select;
+ }
+
+ /**
+ * @param string $sourceTable
+ * @return \Magento\Framework\DB\Select
+ */
+ private function getSelectForUpdate(string $sourceTable): Select
+ {
+ $connection = $this->resource->getConnection($this->connectionName);
+
+ $select = $connection->select()->join(
+ ['io' => $sourceTable],
+ 'i.entity_id = io.entity_id AND i.customer_group_id = io.customer_group_id' .
+ ' AND i.website_id = io.website_id',
+ []
+ );
+ $select->columns(
+ [
+ 'min_price' => new ColumnValueExpression('i.min_price + io.min_price'),
+ 'max_price' => new ColumnValueExpression('i.max_price + io.max_price'),
+ 'tier_price' => $connection->getCheckSql(
+ 'i.tier_price IS NOT NULL',
+ 'i.tier_price + io.tier_price',
+ 'NULL'
+ ),
+ ]
+ );
+
+ return $select;
+ }
+
+ /**
+ * @param string $tableName
+ * @return string
+ */
+ private function getTable(string $tableName): string
+ {
+ return $this->resource->getTableName($tableName, $this->connectionName);
+ }
+
+ /**
+ * @return bool
+ */
+ private function isPriceGlobal(): bool
+ {
+ if ($this->isPriceGlobalFlag === null) {
+ $this->isPriceGlobalFlag = $this->dataHelper->isPriceGlobal();
+ }
+
+ return $this->isPriceGlobalFlag;
+ }
+
+ /**
+ * Retrieve table name for custom option temporary aggregation data
+ *
+ * @return string
+ */
+ private function getCustomOptionAggregateTable(): string
+ {
+ return $this->tableStrategy->getTableName('catalog_product_index_price_opt_agr');
+ }
+
+ /**
+ * Retrieve table name for custom option prices data
+ *
+ * @return string
+ */
+ private function getCustomOptionPriceTable(): string
+ {
+ return $this->tableStrategy->getTableName('catalog_product_index_price_opt');
+ }
+
+ /**
+ * Prepare table structure for custom option temporary aggregation data
+ *
+ * @return void
+ */
+ private function prepareCustomOptionAggregateTable()
+ {
+ $this->getConnection()->delete($this->getCustomOptionAggregateTable());
+ }
+
+ /**
+ * Prepare table structure for custom option prices data
+ *
+ * @return void
+ */
+ private function prepareCustomOptionPriceTable()
+ {
+ $this->getConnection()->delete($this->getCustomOptionPriceTable());
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
index 4ca407a53f8ae..168fa8f50acc2 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php
@@ -6,6 +6,7 @@
namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price;
use Magento\Catalog\Model\ResourceModel\Product\Indexer\AbstractIndexer;
+use Magento\Framework\Indexer\DimensionalIndexerInterface;
/**
* Default Product Type Price Indexer Resource model
@@ -16,6 +17,8 @@
* @author Magento Core Team
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @since 100.0.2
+ * @deprecated Not used anymore for price indexation. Class left for backward compatibility
+ * @see DimensionalIndexerInterface
*/
class DefaultPrice extends AbstractIndexer implements PriceInterface
{
@@ -71,7 +74,7 @@ class DefaultPrice extends AbstractIndexer implements PriceInterface
* @param \Magento\Framework\Event\ManagerInterface $eventManager
* @param \Magento\Framework\Module\Manager $moduleManager
* @param string|null $connectionName
- * @param null|IndexTableStructureFactory $indexTableStructureFactory
+ * @param IndexTableStructureFactory $indexTableStructureFactory
* @param PriceModifierInterface[] $priceModifiers
*/
public function __construct(
@@ -307,7 +310,7 @@ protected function prepareFinalPriceDataForType($entityIds, $type)
$query = $select->insertFromSelect($finalPriceTable->getTableName(), [], false);
$this->getConnection()->query($query);
- $this->applyDiscountPrices($finalPriceTable);
+ $this->modifyPriceIndex($finalPriceTable);
return $this;
}
@@ -327,6 +330,7 @@ protected function prepareFinalPriceDataForType($entityIds, $type)
protected function getSelect($entityIds = null, $type = null)
{
$metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
+ $linkField = $metadata->getLinkField();
$connection = $this->getConnection();
$select = $connection->select()->from(
['e' => $this->getTable('catalog_product_entity')],
@@ -356,9 +360,38 @@ protected function getSelect($entityIds = null, $type = null)
'pw.product_id = e.entity_id AND pw.website_id = cw.website_id',
[]
)->joinLeft(
- ['tp' => $this->_getTierPriceIndexTable()],
- 'tp.entity_id = e.entity_id AND tp.website_id = cw.website_id' .
- ' AND tp.customer_group_id = cg.customer_group_id',
+ // we need this only for BCC in case someone expects table `tp` to be present in query
+ ['tp' => $this->getTable('catalog_product_index_tier_price')],
+ 'tp.entity_id = e.entity_id AND tp.customer_group_id = cg.customer_group_id' .
+ ' AND tp.website_id = pw.website_id',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group`
+ ['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' .
+ ' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' .
+ ' AND tier_price_1.website_id = 0',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `Specific Website`
+ //and Customer Group = `Specific Customer Group`
+ ['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0' .
+ ' AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' .
+ ' AND tier_price_2.website_id = cw.website_id',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS`
+ ['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1' .
+ ' AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS`
+ ['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' .
+ ' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' .
+ ' AND tier_price_4.website_id = cw.website_id',
[]
);
@@ -374,7 +407,7 @@ protected function getSelect($entityIds = null, $type = null)
$this->_addAttributeToSelect(
$select,
'status',
- 'e.' . $metadata->getLinkField(),
+ 'e.' . $linkField,
'cs.store_id',
$statusCond,
true
@@ -383,7 +416,7 @@ protected function getSelect($entityIds = null, $type = null)
$taxClassId = $this->_addAttributeToSelect(
$select,
'tax_class_id',
- 'e.' . $metadata->getLinkField(),
+ 'e.' . $linkField,
'cs.store_id'
);
} else {
@@ -394,25 +427,25 @@ protected function getSelect($entityIds = null, $type = null)
$price = $this->_addAttributeToSelect(
$select,
'price',
- 'e.' . $metadata->getLinkField(),
+ 'e.' . $linkField,
'cs.store_id'
);
$specialPrice = $this->_addAttributeToSelect(
$select,
'special_price',
- 'e.' . $metadata->getLinkField(),
+ 'e.' . $linkField,
'cs.store_id'
);
$specialFrom = $this->_addAttributeToSelect(
$select,
'special_from_date',
- 'e.' . $metadata->getLinkField(),
+ 'e.' . $linkField,
'cs.store_id'
);
$specialTo = $this->_addAttributeToSelect(
$select,
'special_to_date',
- 'e.' . $metadata->getLinkField(),
+ 'e.' . $linkField,
'cs.store_id'
);
$currentDate = 'cwd.website_date';
@@ -423,15 +456,12 @@ protected function getSelect($entityIds = null, $type = null)
$specialFromExpr = "{$specialFrom} IS NULL OR {$specialFromDate} <= {$currentDate}";
$specialToExpr = "{$specialTo} IS NULL OR {$specialToDate} >= {$currentDate}";
$specialPriceExpr = $connection->getCheckSql(
- "{$specialPrice} IS NOT NULL AND {$specialFromExpr} AND {$specialToExpr}",
+ "{$specialPrice} IS NOT NULL AND ({$specialFromExpr}) AND ({$specialToExpr})",
$specialPrice,
$maxUnsignedBigint
);
- $tierPrice = new \Zend_Db_Expr('tp.min_price');
- $tierPriceExpr = $connection->getIfNullSql(
- $tierPrice,
- $maxUnsignedBigint
- );
+ $tierPrice = $this->getTotalTierPriceExpression($price);
+ $tierPriceExpr = $connection->getIfNullSql($tierPrice, $maxUnsignedBigint);
$finalPrice = $connection->getLeastSql([
$price,
$specialPriceExpr,
@@ -512,12 +542,12 @@ protected function _prepareCustomOptionPriceTable()
}
/**
- * Apply discount prices to final price index table.
+ * Modify data in price index table.
*
* @param IndexTableStructure $finalPriceTable
* @return void
*/
- private function applyDiscountPrices(IndexTableStructure $finalPriceTable) : void
+ private function modifyPriceIndex(IndexTableStructure $finalPriceTable) : void
{
foreach ($this->priceModifiers as $priceModifier) {
$priceModifier->modifyPrice($finalPriceTable);
@@ -791,4 +821,62 @@ protected function hasEntity()
return $this->hasEntity;
}
+
+ /**
+ * @param \Zend_Db_Expr $priceExpression
+ * @return \Zend_Db_Expr
+ */
+ private function getTotalTierPriceExpression(\Zend_Db_Expr $priceExpression)
+ {
+ $maxUnsignedBigint = '~0';
+
+ return $this->getConnection()->getCheckSql(
+ implode(
+ ' AND ',
+ [
+ 'tier_price_1.value_id is NULL',
+ 'tier_price_2.value_id is NULL',
+ 'tier_price_3.value_id is NULL',
+ 'tier_price_4.value_id is NULL'
+ ]
+ ),
+ 'NULL',
+ $this->getConnection()->getLeastSql([
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_1', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_2', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_3', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_4', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ ])
+ );
+ }
+
+ /**
+ * @param string $tableAlias
+ * @param \Zend_Db_Expr $priceExpression
+ * @return \Zend_Db_Expr
+ */
+ private function getTierPriceExpressionForTable($tableAlias, \Zend_Db_Expr $priceExpression)
+ {
+ return $this->getConnection()->getCheckSql(
+ sprintf('%s.value = 0', $tableAlias),
+ sprintf(
+ 'ROUND(%s * (1 - ROUND(%s.percentage_value * cwd.rate, 4) / 100), 4)',
+ $priceExpression,
+ $tableAlias
+ ),
+ sprintf('ROUND(%s.value * cwd.rate, 4)', $tableAlias)
+ );
+ }
}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php
index 21a7647214c26..9a310c7365ac9 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php
@@ -9,6 +9,8 @@
*/
namespace Magento\Catalog\Model\ResourceModel\Product\Indexer\Price;
+use Magento\Framework\Indexer\DimensionalIndexerInterface;
+
class Factory
{
/**
@@ -40,14 +42,17 @@ public function create($className, array $data = [])
{
$indexerPrice = $this->_objectManager->create($className, $data);
- if (!$indexerPrice instanceof \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __(
- '%1 doesn\'t extend \Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\DefaultPrice',
- $className
- )
- );
+ if ($indexerPrice instanceof PriceInterface || $indexerPrice instanceof DimensionalIndexerInterface) {
+ return $indexerPrice;
}
- return $indexerPrice;
+
+ throw new \Magento\Framework\Exception\LocalizedException(
+ __(
+ 'Price indexer "%1" must implement %2 or %3',
+ $className,
+ PriceInterface::class,
+ DimensionalIndexerInterface::class
+ )
+ );
}
}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/BaseFinalPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/BaseFinalPrice.php
new file mode 100644
index 0000000000000..0005ac8dea58a
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/BaseFinalPrice.php
@@ -0,0 +1,330 @@
+ 'pw.website_id',
+ CustomerGroupDimensionProvider::DIMENSION_NAME => 'cg.customer_group_id',
+ ];
+
+ /**
+ * @var \Magento\Framework\DB\Adapter\AdapterInterface
+ */
+ private $connection;
+
+ /**
+ * @var \Magento\Framework\EntityManager\MetadataPool
+ */
+ private $metadataPool;
+
+ /**
+ * BaseFinalPrice constructor.
+ * @param \Magento\Framework\App\ResourceConnection $resource
+ * @param JoinAttributeProcessor $joinAttributeProcessor
+ * @param \Magento\Framework\Module\Manager $moduleManager
+ * @param string $connectionName
+ */
+ public function __construct(
+ \Magento\Framework\App\ResourceConnection $resource,
+ JoinAttributeProcessor $joinAttributeProcessor,
+ \Magento\Framework\Module\Manager $moduleManager,
+ \Magento\Framework\Event\ManagerInterface $eventManager,
+ \Magento\Framework\EntityManager\MetadataPool $metadataPool,
+ $connectionName = 'indexer'
+ ) {
+ $this->resource = $resource;
+ $this->connectionName = $connectionName;
+ $this->joinAttributeProcessor = $joinAttributeProcessor;
+ $this->moduleManager = $moduleManager;
+ $this->eventManager = $eventManager;
+ $this->metadataPool = $metadataPool;
+ }
+
+ /**
+ * @param Dimension[] $dimensions
+ * @param string $productType
+ * @param array $entityIds
+ * @return Select
+ * @throws \LogicException
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Zend_Db_Select_Exception
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
+ public function getQuery(array $dimensions, string $productType, array $entityIds = []): Select
+ {
+ $connection = $this->getConnection();
+ $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
+ $linkField = $metadata->getLinkField();
+
+ $select = $connection->select()->from(
+ ['e' => $this->getTable('catalog_product_entity')],
+ ['entity_id']
+ )->joinInner(
+ ['cg' => $this->getTable('customer_group')],
+ array_key_exists(CustomerGroupDimensionProvider::DIMENSION_NAME, $dimensions)
+ ? sprintf(
+ '%s = %s',
+ $this->dimensionToFieldMapper[CustomerGroupDimensionProvider::DIMENSION_NAME],
+ $dimensions[CustomerGroupDimensionProvider::DIMENSION_NAME]->getValue()
+ ) : '',
+ ['customer_group_id']
+ )->joinInner(
+ ['pw' => $this->getTable('catalog_product_website')],
+ 'pw.product_id = e.entity_id',
+ ['pw.website_id']
+ )->joinInner(
+ ['cwd' => $this->getTable('catalog_product_index_website')],
+ 'pw.website_id = cwd.website_id',
+ []
+ )->joinLeft(
+ // we need this only for BCC in case someone expects table `tp` to be present in query
+ ['tp' => $this->getTable('catalog_product_index_tier_price')],
+ 'tp.entity_id = e.entity_id AND' .
+ ' tp.customer_group_id = cg.customer_group_id AND tp.website_id = pw.website_id',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `All Websites` and Customer Group = `Specific Customer Group`
+ ['tier_price_1' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_1.' . $linkField . ' = e.' . $linkField . ' AND tier_price_1.all_groups = 0' .
+ ' AND tier_price_1.customer_group_id = cg.customer_group_id AND tier_price_1.qty = 1' .
+ ' AND tier_price_1.website_id = 0',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `Specific Website`
+ //and Customer Group = `Specific Customer Group`
+ ['tier_price_2' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_2.' . $linkField . ' = e.' . $linkField . ' AND tier_price_2.all_groups = 0 ' .
+ 'AND tier_price_2.customer_group_id = cg.customer_group_id AND tier_price_2.qty = 1' .
+ ' AND tier_price_2.website_id = pw.website_id',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `All Websites` and Customer Group = `ALL GROUPS`
+ ['tier_price_3' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_3.' . $linkField . ' = e.' . $linkField . ' AND tier_price_3.all_groups = 1 ' .
+ 'AND tier_price_3.customer_group_id = 0 AND tier_price_3.qty = 1 AND tier_price_3.website_id = 0',
+ []
+ )->joinLeft(
+ // calculate tier price specified as Website = `Specific Website` and Customer Group = `ALL GROUPS`
+ ['tier_price_4' => $this->getTable('catalog_product_entity_tier_price')],
+ 'tier_price_4.' . $linkField . ' = e.' . $linkField . ' AND tier_price_4.all_groups = 1' .
+ ' AND tier_price_4.customer_group_id = 0 AND tier_price_4.qty = 1' .
+ ' AND tier_price_4.website_id = pw.website_id',
+ []
+ );
+
+ foreach ($dimensions as $dimension) {
+ if (!isset($this->dimensionToFieldMapper[$dimension->getName()])) {
+ throw new \LogicException(
+ 'Provided dimension is not valid for Price indexer: ' . $dimension->getName()
+ );
+ }
+ $select->where($this->dimensionToFieldMapper[$dimension->getName()] . ' = ?', $dimension->getValue());
+ }
+
+ if ($this->moduleManager->isEnabled('Magento_Tax')) {
+ $taxClassId = $this->joinAttributeProcessor->process($select, 'tax_class_id');
+ } else {
+ $taxClassId = new \Zend_Db_Expr(0);
+ }
+ $select->columns(['tax_class_id' => $taxClassId]);
+
+ $this->joinAttributeProcessor->process($select, 'status', Status::STATUS_ENABLED);
+
+ $price = $this->joinAttributeProcessor->process($select, 'price');
+ $specialPrice = $this->joinAttributeProcessor->process($select, 'special_price');
+ $specialFrom = $this->joinAttributeProcessor->process($select, 'special_from_date');
+ $specialTo = $this->joinAttributeProcessor->process($select, 'special_to_date');
+ $currentDate = 'cwd.website_date';
+
+ $maxUnsignedBigint = '~0';
+ $specialFromDate = $connection->getDatePartSql($specialFrom);
+ $specialToDate = $connection->getDatePartSql($specialTo);
+ $specialFromExpr = "{$specialFrom} IS NULL OR {$specialFromDate} <= {$currentDate}";
+ $specialToExpr = "{$specialTo} IS NULL OR {$specialToDate} >= {$currentDate}";
+ $specialPriceExpr = $connection->getCheckSql(
+ "{$specialPrice} IS NOT NULL AND ({$specialFromExpr}) AND ({$specialToExpr})",
+ $specialPrice,
+ $maxUnsignedBigint
+ );
+ $tierPrice = $this->getTotalTierPriceExpression($price);
+ $tierPriceExpr = $connection->getIfNullSql($tierPrice, $maxUnsignedBigint);
+ $finalPrice = $connection->getLeastSql([
+ $price,
+ $specialPriceExpr,
+ $tierPriceExpr,
+ ]);
+
+ $select->columns(
+ [
+ //orig_price in catalog_product_index_price_final_tmp
+ 'price' => $connection->getIfNullSql($price, 0),
+ //price in catalog_product_index_price_final_tmp
+ 'final_price' => $connection->getIfNullSql($finalPrice, 0),
+ 'min_price' => $connection->getIfNullSql($finalPrice, 0),
+ 'max_price' => $connection->getIfNullSql($finalPrice, 0),
+ 'tier_price' => $tierPrice,
+ ]
+ );
+
+ $select->where("e.type_id = ?", $productType);
+
+ if ($entityIds !== null) {
+ if (count($entityIds) > 1) {
+ $select->where(sprintf('e.entity_id BETWEEN %s AND %s', min($entityIds), max($entityIds)));
+ } else {
+ $select->where('e.entity_id = ?', $entityIds);
+ }
+ }
+
+ /**
+ * throw event for backward compatibility
+ */
+ $this->eventManager->dispatch(
+ 'prepare_catalog_product_index_select',
+ [
+ 'select' => $select,
+ 'entity_field' => new ColumnValueExpression('e.entity_id'),
+ 'website_field' => new ColumnValueExpression('pw.website_id'),
+ 'store_field' => new ColumnValueExpression('cwd.default_store_id'),
+ ]
+ );
+
+ return $select;
+ }
+
+ /**
+ * Get total tier price expression
+ *
+ * @param \Zend_Db_Expr $priceExpression
+ * @return \Zend_Db_Expr
+ */
+ private function getTotalTierPriceExpression(\Zend_Db_Expr $priceExpression)
+ {
+ $maxUnsignedBigint = '~0';
+
+ return $this->getConnection()->getCheckSql(
+ implode(
+ ' AND ',
+ [
+ 'tier_price_1.value_id is NULL',
+ 'tier_price_2.value_id is NULL',
+ 'tier_price_3.value_id is NULL',
+ 'tier_price_4.value_id is NULL'
+ ]
+ ),
+ 'NULL',
+ $this->getConnection()->getLeastSql([
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_1', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_2', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_3', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ $this->getConnection()->getIfNullSql(
+ $this->getTierPriceExpressionForTable('tier_price_4', $priceExpression),
+ $maxUnsignedBigint
+ ),
+ ])
+ );
+ }
+
+ /**
+ * Get tier price expression for table
+ *
+ * @param $tableAlias
+ * @param \Zend_Db_Expr $priceExpression
+ * @return \Zend_Db_Expr
+ */
+ private function getTierPriceExpressionForTable($tableAlias, \Zend_Db_Expr $priceExpression): \Zend_Db_Expr
+ {
+ return $this->getConnection()->getCheckSql(
+ sprintf('%s.value = 0', $tableAlias),
+ sprintf(
+ 'ROUND(%s * (1 - ROUND(%s.percentage_value * cwd.rate, 4) / 100), 4)',
+ $priceExpression,
+ $tableAlias
+ ),
+ sprintf('ROUND(%s.value * cwd.rate, 4)', $tableAlias)
+ );
+ }
+
+ /**
+ * Get connection
+ *
+ * return \Magento\Framework\DB\Adapter\AdapterInterface
+ * @throws \DomainException
+ */
+ private function getConnection(): \Magento\Framework\DB\Adapter\AdapterInterface
+ {
+ if ($this->connection === null) {
+ $this->connection = $this->resource->getConnection($this->connectionName);
+ }
+
+ return $this->connection;
+ }
+
+ /**
+ * Get table
+ *
+ * @param string $tableName
+ * @return string
+ */
+ private function getTable($tableName)
+ {
+ return $this->resource->getTableName($tableName, $this->connectionName);
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/JoinAttributeProcessor.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/JoinAttributeProcessor.php
new file mode 100644
index 0000000000000..888e68a817081
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Query/JoinAttributeProcessor.php
@@ -0,0 +1,112 @@
+eavConfig = $eavConfig;
+ $this->metadataPool = $metadataPool;
+ $this->resource = $resource;
+ $this->connectionName = $connectionName;
+ }
+
+ /**
+ * @param Select $select
+ * @param string $attributeCode
+ * @param string|null $attributeValue
+ * @return \Zend_Db_Expr
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Zend_Db_Select_Exception
+ */
+ public function process(Select $select, $attributeCode, $attributeValue = null): \Zend_Db_Expr
+ {
+ $attribute = $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode);
+ $attributeId = $attribute->getAttributeId();
+ $attributeTable = $attribute->getBackend()->getTable();
+ $connection = $this->resource->getConnection($this->connectionName);
+ $joinType = $attributeValue !== null ? 'join' : 'joinLeft';
+ $productIdField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
+
+ if ($attribute->isScopeGlobal()) {
+ $alias = 'ta_' . $attributeCode;
+ $select->{$joinType}(
+ [$alias => $attributeTable],
+ "{$alias}.{$productIdField} = e.{$productIdField} AND {$alias}.attribute_id = {$attributeId}" .
+ " AND {$alias}.store_id = 0",
+ []
+ );
+ $whereExpression = new Expression("{$alias}.value");
+ } else {
+ $dAlias = 'tad_' . $attributeCode;
+ $sAlias = 'tas_' . $attributeCode;
+
+ $select->{$joinType}(
+ [$dAlias => $attributeTable],
+ "{$dAlias}.{$productIdField} = e.{$productIdField} AND {$dAlias}.attribute_id = {$attributeId}" .
+ " AND {$dAlias}.store_id = 0",
+ []
+ );
+ $select->joinLeft(
+ [$sAlias => $attributeTable],
+ "{$sAlias}.{$productIdField} = e.{$productIdField} AND {$sAlias}.attribute_id = {$attributeId}" .
+ " AND {$sAlias}.store_id = cwd.default_store_id",
+ []
+ );
+ $whereExpression = $connection->getCheckSql(
+ $connection->getIfNullSql("{$sAlias}.value_id", -1) . ' > 0',
+ "{$sAlias}.value",
+ "{$dAlias}.value"
+ );
+ }
+
+ if ($attributeValue !== null) {
+ $select->where("{$whereExpression} = ?", $attributeValue);
+ }
+
+ return $whereExpression;
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/SimpleProductPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/SimpleProductPrice.php
new file mode 100644
index 0000000000000..5a055e5ed9603
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/SimpleProductPrice.php
@@ -0,0 +1,89 @@
+baseFinalPrice = $baseFinalPrice;
+ $this->indexTableStructureFactory = $indexTableStructureFactory;
+ $this->tableMaintainer = $tableMaintainer;
+ $this->productType = $productType;
+ $this->basePriceModifier = $basePriceModifier;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function executeByDimensions(array $dimensions, \Traversable $entityIds)
+ {
+ $this->tableMaintainer->createMainTmpTable($dimensions);
+
+ $temporaryPriceTable = $this->indexTableStructureFactory->create([
+ 'tableName' => $this->tableMaintainer->getMainTmpTable($dimensions),
+ 'entityField' => 'entity_id',
+ 'customerGroupField' => 'customer_group_id',
+ 'websiteField' => 'website_id',
+ 'taxClassField' => 'tax_class_id',
+ 'originalPriceField' => 'price',
+ 'finalPriceField' => 'final_price',
+ 'minPriceField' => 'min_price',
+ 'maxPriceField' => 'max_price',
+ 'tierPriceField' => 'tier_price',
+ ]);
+ $select = $this->baseFinalPrice->getQuery($dimensions, $this->productType, iterator_to_array($entityIds));
+ $query = $select->insertFromSelect($temporaryPriceTable->getTableName(), [], false);
+ $this->tableMaintainer->getConnection()->query($query);
+
+ $this->basePriceModifier->modifyPrice($temporaryPriceTable, iterator_to_array($entityIds));
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php
index 4ebcd1f4b9ae4..ce0a9b6e461ce 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php
@@ -256,7 +256,8 @@ protected function _saveValueTitles(AbstractModel $object)
$object->unsetData('title');
}
- if ($object->getTitle()) {
+ /*** Checking whether title is not null ***/
+ if ($object->getTitle()!= null) {
if ($existInCurrentStore) {
if ($storeId == $object->getStoreId()) {
$where = [
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
index c7829ab3a31d2..c5c656b726528 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/StatusBaseSelectProcessor.php
@@ -13,6 +13,7 @@
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Store\Api\StoreResolverInterface;
use Magento\Store\Model\Store;
+use Magento\Store\Model\StoreManagerInterface;
/**
* Class StatusBaseSelectProcessor
@@ -30,28 +31,32 @@ class StatusBaseSelectProcessor implements BaseSelectProcessorInterface
private $metadataPool;
/**
- * @var StoreResolverInterface
+ * @var StoreManagerInterface
*/
- private $storeResolver;
+ private $storeManager;
/**
* @param Config $eavConfig
* @param MetadataPool $metadataPool
* @param StoreResolverInterface $storeResolver
+ * @param StoreManagerInterface $storeManager
+ *
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function __construct(
Config $eavConfig,
MetadataPool $metadataPool,
- StoreResolverInterface $storeResolver
+ StoreResolverInterface $storeResolver,
+ StoreManagerInterface $storeManager = null
) {
$this->eavConfig = $eavConfig;
$this->metadataPool = $metadataPool;
- $this->storeResolver = $storeResolver;
+ $this->storeManager = $storeManager ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(StoreManagerInterface::class);
}
/**
- * @param Select $select
- * @return Select
+ * @inheritdoc
*/
public function process(Select $select)
{
@@ -70,7 +75,7 @@ public function process(Select $select)
['status_attr' => $statusAttribute->getBackendTable()],
"status_attr.{$linkField} = " . self::PRODUCT_TABLE_ALIAS . ".{$linkField}"
. ' AND status_attr.attribute_id = ' . (int)$statusAttribute->getAttributeId()
- . ' AND status_attr.store_id = ' . $this->storeResolver->getCurrentStoreId(),
+ . ' AND status_attr.store_id = ' . $this->storeManager->getStore()->getId(),
[]
);
diff --git a/app/code/Magento/Catalog/Observer/CategoryProductIndexer.php b/app/code/Magento/Catalog/Observer/CategoryProductIndexer.php
new file mode 100644
index 0000000000000..ca87efaa87490
--- /dev/null
+++ b/app/code/Magento/Catalog/Observer/CategoryProductIndexer.php
@@ -0,0 +1,42 @@
+processor = $processor;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function execute(Observer $observer): void
+ {
+ $productIds = $observer->getEvent()->getProductIds();
+ if (!empty($productIds) && $this->processor->isIndexerScheduled()) {
+ $this->processor->markIndexerAsInvalid();
+ }
+ }
+}
diff --git a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php
index 8cbe235e05f26..44f9193ab4012 100644
--- a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php
+++ b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php
@@ -22,7 +22,7 @@ class Topmenu
protected $catalogCategory;
/**
- * @var \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory
+ * @var \Magento\Catalog\Model\ResourceModel\Category\StateDependentCollectionFactory
*/
private $collectionFactory;
@@ -40,13 +40,13 @@ class Topmenu
* Initialize dependencies.
*
* @param \Magento\Catalog\Helper\Category $catalogCategory
- * @param \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoryCollectionFactory
+ * @param \Magento\Catalog\Model\ResourceModel\Category\StateDependentCollectionFactory $categoryCollectionFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
*/
public function __construct(
\Magento\Catalog\Helper\Category $catalogCategory,
- \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoryCollectionFactory,
+ \Magento\Catalog\Model\ResourceModel\Category\StateDependentCollectionFactory $categoryCollectionFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Catalog\Model\Layer\Resolver $layerResolver
) {
diff --git a/app/code/Magento/Catalog/Plugin/Model/Attribute/Backend/AttributeValidation.php b/app/code/Magento/Catalog/Plugin/Model/Attribute/Backend/AttributeValidation.php
index 597a1466a125e..eca4d468950e1 100644
--- a/app/code/Magento/Catalog/Plugin/Model/Attribute/Backend/AttributeValidation.php
+++ b/app/code/Magento/Catalog/Plugin/Model/Attribute/Backend/AttributeValidation.php
@@ -7,6 +7,9 @@
use Magento\Store\Model\Store;
+/**
+ * Attribute validation
+ */
class AttributeValidation
{
/**
@@ -14,6 +17,11 @@ class AttributeValidation
*/
private $storeManager;
+ /**
+ * @var array
+ */
+ private $allowedEntityTypes;
+
/**
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param array $allowedEntityTypes
@@ -27,9 +35,12 @@ public function __construct(
}
/**
+ * Around validate
+ *
* @param \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend $subject
* @param \Closure $proceed
* @param \Magento\Framework\DataObject $entity
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
* @return bool
*/
public function aroundValidate(
@@ -41,7 +52,7 @@ public function aroundValidate(
return $entity instanceof $allowedEntity;
}, $this->allowedEntityTypes)));
- if ($isAllowedType && $this->storeManager->getStore()->getId() !== Store::DEFAULT_STORE_ID) {
+ if ($isAllowedType && (int) $this->storeManager->getStore()->getId() !== Store::DEFAULT_STORE_ID) {
$attrCode = $subject->getAttribute()->getAttributeCode();
// Null is meaning "no value" which should be overridden by value from default scope
if (array_key_exists($attrCode, $entity->getData()) && $entity->getData($attrCode) === null) {
diff --git a/app/code/Magento/Catalog/Plugin/Model/ResourceModel/ReadSnapshotPlugin.php b/app/code/Magento/Catalog/Plugin/Model/ResourceModel/ReadSnapshotPlugin.php
index 4dae4ec68efa8..ff4d2f93c912a 100644
--- a/app/code/Magento/Catalog/Plugin/Model/ResourceModel/ReadSnapshotPlugin.php
+++ b/app/code/Magento/Catalog/Plugin/Model/ResourceModel/ReadSnapshotPlugin.php
@@ -58,7 +58,9 @@ public function afterExecute(ReadSnapshot $subject, array $entityData, $entityTy
$globalAttributes = [];
$attributesMap = [];
$eavEntityType = $metadata->getEavEntityType();
- $attributes = (null === $eavEntityType) ? [] : $this->config->getEntityAttributes($eavEntityType);
+ $attributes = null === $eavEntityType
+ ? []
+ : $this->config->getEntityAttributes($eavEntityType, new \Magento\Framework\DataObject($entityData));
/** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */
foreach ($attributes as $attribute) {
diff --git a/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php b/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php
index 1397ceb6bf71c..2c4e332e71237 100644
--- a/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php
+++ b/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php
@@ -29,7 +29,7 @@ public function getValue()
if ($this->value === null) {
$price = $this->product->getPrice();
$priceInCurrentCurrency = $this->priceCurrency->convertAndRound($price);
- $this->value = $priceInCurrentCurrency ? floatval($priceInCurrentCurrency) : 0;
+ $this->value = $priceInCurrentCurrency ? (float)$priceInCurrentCurrency : 0;
}
return $this->value;
}
diff --git a/app/code/Magento/Catalog/Pricing/Price/TierPrice.php b/app/code/Magento/Catalog/Pricing/Price/TierPrice.php
index 74f98c2e66a54..f250927889c29 100644
--- a/app/code/Magento/Catalog/Pricing/Price/TierPrice.php
+++ b/app/code/Magento/Catalog/Pricing/Price/TierPrice.php
@@ -80,7 +80,7 @@ public function __construct(
GroupManagementInterface $groupManagement,
CustomerGroupRetrieverInterface $customerGroupRetriever = null
) {
- $quantity = floatval($quantity) ? $quantity : 1;
+ $quantity = (float)$quantity ? $quantity : 1;
parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
$this->customerSession = $customerSession;
$this->groupManagement = $groupManagement;
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml
index 44c960dc37641..692487c1d60cd 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml
index 7c04e9bd83d56..76f65381f43fa 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCategoryActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateRootCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateRootCategoryActionGroup.xml
index e7d9a63484bc6..a99420bcf95bb 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateRootCategoryActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateRootCategoryActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
index bca6ae2b60bf3..9f8d827b20849 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
@@ -121,6 +121,7 @@
+
@@ -173,6 +174,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -184,6 +221,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -196,4 +251,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
index 3f4ee180fc65f..fd80838692065 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
index 33f4ccac2b98f..5948ca12dcf0f 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
@@ -34,4 +34,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
index c2620bc5a3672..1bd9bb4a09c86 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontCategoryPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontCategoryPageActionGroup.xml
index 4eca49dc28b57..8b657fa1b8aab 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontCategoryPageActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontCategoryPageActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontProductPageActionGroup.xml
index 59c874b8481d3..391a1a7d670de 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontProductPageActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertProductInStorefrontProductPageActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CheckItemInLayeredNavigationActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CheckItemInLayeredNavigationActionGroup.xml
index 304f38e227960..f2a7a0acffefa 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CheckItemInLayeredNavigationActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CheckItemInLayeredNavigationActionGroup.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml
index 6b47479d41cb7..7373d5baea0c5 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/MoveCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/MoveCategoryActionGroup.xml
index ae9dc0557a9bd..7bb9aa60ca628 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/MoveCategoryActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/MoveCategoryActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenEditProductOnBackendActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenEditProductOnBackendActionGroup.xml
index 07fba7cc6be06..8f89a85e14892 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenEditProductOnBackendActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenEditProductOnBackendActionGroup.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenProductFromCategoryPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenProductFromCategoryPageActionGroup.xml
index e8794ab895c6b..c460dcbfbec91 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenProductFromCategoryPageActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/OpenProductFromCategoryPageActionGroup.xml
@@ -5,7 +5,7 @@
* See COPYING.txt for license details.
-->
-
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/RestoreLayoutSettingActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/RestoreLayoutSettingActionGroup.xml
index 53acfe2b4372d..2f9d38516bd05 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/RestoreLayoutSettingActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/RestoreLayoutSettingActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchAndMultiselectActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchAndMultiselectActionGroup.xml
index 943fe803232e6..53e7ea3589d1e 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchAndMultiselectActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchAndMultiselectActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchForProductOnBackendActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchForProductOnBackendActionGroup.xml
index 5fbc9c5d7fcad..a303511ffe5bb 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchForProductOnBackendActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchForProductOnBackendActionGroup.xml
@@ -6,16 +6,22 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
-
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml
index 105a5c58788de..c7ae52d2b37c3 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml
index 4376e78242fbd..c980c43b8f3af 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCompareActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCompareActionGroup.xml
index 7af1cacfb3da8..04e15da91777c 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCompareActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCompareActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml
index eb672cd162e82..5f0d03597dab1 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml
index d46b895044531..82042975d5fb8 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontProductPageActionGroup.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CatalogPriceData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogPriceData.xml
new file mode 100644
index 0000000000000..cad8a8cd03e0d
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogPriceData.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+ scopeWebsite
+ defaultProductPrice
+
+
+ 1
+
+
+ 0
+
+
+
+ scopeGlobal
+ defaultProductPrice
+
+
+ 0
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml
index 42351741d9fa8..5c79c321c9431 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
simpleCategory
simplecategory
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml
index 8ae57f9239902..8a26b6babdbbc 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
1
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CustomAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CustomAttributeData.xml
index e93138fecfd47..389c41abf0bd1 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/CustomAttributeData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/CustomAttributeData.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
url_key
category
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml
index 2423383bc19f7..a46d40c62c76e 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml
@@ -7,9 +7,13 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
0
attribute
+
+ 0
+ attributeTwo
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ImageContentData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ImageContentData.xml
index c674a8fc144ce..1f4b1470098e2 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ImageContentData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ImageContentData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGAAYAMBIgACEQEDEQH/xACXAAEBAAMBAQEBAAAAAAAAAAAABgMEBQgCAQcQAAEDAQUFBgQDCQAAAAAAAAABAgMEBQYRFpESMTZV0QchcnOzwhMUIkEygaE1QlFSYXGCsbIBAAEFAQAAAAAAAAAAAAAAAAACAwQGBwERAAECAwMLBAMBAAAAAAAAAAEAAgMEERMhkRQxMzRBUVJTcXKxBRJhoSKBwUL/2gAMAwEAAhEDEQA/AP7+AYKysp7Po5aurlbFBEmL3u3NQ6ASaBdArcFnBN5/urzqn0d0Gf7q86p9HdCRkUzy3YFOWEXhOCpATef7q86p9HdBn+6vOqfR3QMimeW7AosIvCcFSAm8/wB1edU+jugz/dXnVPo7oGRTPLdgUWEXhOCpATef7q86p9HdBn+6vOqfR3QMimeW7AosIvCcFSA1bPtGktWiZWUM7Z6d6qjZG7lwXBf1Q2iO5paaOFCmyCDQoTd/uBLX8n3IUhN3+4EtfyfchIk9Zh9w8pyBpW9QvN4Bwbcsujis+pq2Q4Tq5HbW0u9XJj3Y4fc0ibjPgQjEY0GgJNTS4brj/FaIz3Q2FwFafNP4V3gc1aWz7FY+rjhVrsNjBrlcrsV3Iir/ABPxtqzRyM+boJKeJ7kakm2jkRV3Yom4TlbYf4xrnfFSBuqaCn7ouWwbc+4/FT90XTBz57RlbVvpqWjdUSRoiyfWjUbju71MUlqSyWdVPjpnsqIUVJI3ORFZ3fix+4OnoLSRU3V2HZnANKEjcEGOwVG74OxdUGjZM1RNQROqIlYuw3Zcr9pXpgn1f0xN4kQYgiww8bU4xwe0OG1eg+y7gCg8cvqOLEjuy7gCg8cvqOLEzT1HXIvcfKq0zpn9ShN3+4EtfyfchSE3f7gS1/J9yCJPWYfcPKTA0reoXm85l4P2HUf4/wDSHTPmSOOZiskY17F3tcmKKaXMwjGgvhj/AECMQrTFZ72ObvC5lvxq+gjeivRsUzXvVn4kb34qmpozxWc+NjVtWtqPiOREjbMj1Vf7YFHvMMdLTxP244ImP/maxEUhzMhaxC8UvABrXZuoR9pmLL+9xddfvXNrfkVtJyPqJaOpRiL8VHbKPT8+5THFVS1FnWnE+VKhsUbmsmamG3i1e78jsSwQzoiTRRyIm5HtRf8AZ9MjZGxGMY1rU/damCHTJPMQuDgAa5q31G0VpdnrnuRYO9xNaA1+/r9rUsmeGazqdscrHuZExHo1cVauH30U3THFBDBtfBijj2t+w1Ex0MhMgMcyG1r843J+GC1oDs69B9l3AFB45fUcWJHdl3AFB45fUcWJm3qOuRe4+VV5nTP6lCbv9wJa/k+5CkJu/wBwJa/k+5BEnrMPuHlJgaVvULzeADUlbUAAIQAAhAACF6D7LuAKDxy+o4sSO7LuAKDxy+o4sTMPUdci9x8qqTOmf1KE3f7gS1/J9yFITd/uBLX8n3IIk9Zh9w8pMDSt6hebwAakragABCAAEIAAQvQfZdwBQeOX1HFiR3ZdwBQeOX1HFiZh6jrkXuPlVSZ0z+pQwVlHT2hRy0lXE2WCVMHsduchnBEBINQmQaXhTeQLq8lp9XdRkC6vJafV3UpASMtmeY7Epy3i8RxU3kC6vJafV3UZAuryWn1d1KQBlszzHYlFvF4jipvIF1eS0+ruoyBdXktPq7qUgDLZnmOxKLeLxHFTeQLq8lp9XdRkC6vJafV3UpAGWzPMdiUW8XiOK1bPs6ksqiZR0MDYKdiqrY27kxXFf1U2gCO5xcauNSmySTUr/9k=
image/jpeg
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
index f67370dcff296..b367cdcab9d8b 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
attribute
textarea
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeMediaGalleryEntryData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeMediaGalleryEntryData.xml
index 60b38812e4ced..98c9a70e6aad4 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeMediaGalleryEntryData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeMediaGalleryEntryData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
image
Test Image
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml
index 15c2dc8bbebca..c575f1a5db82f 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeOptionData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
option1
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
index 68c0a54ff88fc..68f51559a9f31 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
4
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
index 0df091eb5f8ef..9ae551b69d388 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
testSku
simple
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml
index 88ff2bbace47a..6e532637fb6d3 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
Qty_1000
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
index b123800a6cc84..ea0bcafe56c48 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
10
100
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionData.xml
index 903bf03535a37..ca5024920ad40 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
OptionField
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionValueData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionValueData.xml
index 28dd255321844..d16a201cd9ecc 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionValueData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductOptionValueData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
OptionValueDropDown1
1
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml
index 4fae51de86c45..39ecc2d440fc2 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
1000
true
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml
index a703e56beda01..ce964e2d71503 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/StoreLabelData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
0
option1
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml
new file mode 100644
index 0000000000000..0aec1244d2650
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+ $676.50
+ $615.00
+
+
+ secondStore
+ second_store
+
+
+ secondStoreView
+ second_store_view
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_price-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_price-meta.xml
new file mode 100644
index 0000000000000..e16688ba0d37b
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_price-meta.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+ string
+
+
+ string
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/category-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/category-meta.xml
index 0880315db5d6b..ae491aefc10cf 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Metadata/category-meta.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/category-meta.xml
@@ -6,7 +6,7 @@
*/
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
application/json
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/custom_attribute-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/custom_attribute-meta.xml
index aed9b7a979836..a37bb36eb6597 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Metadata/custom_attribute-meta.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/custom_attribute-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
string
string
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/empty_extension_attribute-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/empty_extension_attribute-meta.xml
index d8410593cb5b4..7faac6c3b6d3d 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Metadata/empty_extension_attribute-meta.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/empty_extension_attribute-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/frontend_label-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/frontend_label-meta.xml
index d0bcbd3e5db97..063b8c2e5ac63 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Metadata/frontend_label-meta.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/frontend_label-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">
integer
string
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/product-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/product-meta.xml
index 212de2b39d363..9ece47c01fca3 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Metadata/product-meta.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/product-meta.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd">