diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml
new file mode 100644
index 0000000000000..8f9c5828e2f5e
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
index b9a23e9d08ec3..1940a0ac80c0b 100644
--- a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
+++ b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
@@ -1,7 +1,5 @@
$category, 'controller_action' => $this]
);
- } catch (\Magento\Framework\Exception\LocalizedException $e) {
- $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
+ } catch (LocalizedException $e) {
+ $this->_objectManager->get(LoggerInterface::class)->critical($e);
return false;
}
@@ -161,13 +175,12 @@ protected function _initCategory()
/**
* Category view action
*
- * @return \Magento\Framework\Controller\ResultInterface
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
+ * @return ResultInterface
+ * @throws NoSuchEntityException
*/
public function execute()
{
- if ($this->_request->getParam(\Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED)) {
+ if ($this->_request->getParam(ActionInterface::PARAM_NAME_URL_ENCODED)) {
return $this->resultRedirectFactory->create()->setUrl($this->_redirect->getRedirectUrl());
}
$category = $this->_initCategory();
@@ -188,29 +201,18 @@ public function execute()
$page->getConfig()->setPageLayout($settings->getPageLayout());
}
- $hasChildren = $category->hasChildren();
- if ($category->getIsAnchor()) {
- $type = $hasChildren ? 'layered' : 'layered_without_children';
- } else {
- $type = $hasChildren ? 'default' : 'default_without_children';
- }
+ $pageType = $this->getPageType($category);
- if (!$hasChildren) {
+ if (!$category->hasChildren()) {
// Two levels removed from parent. Need to add default page type.
- $parentType = strtok($type, '_');
- $page->addPageLayoutHandles(['type' => $parentType], null, false);
+ $parentPageType = strtok($pageType, '_');
+ $page->addPageLayoutHandles(['type' => $parentPageType], null, false);
}
- $page->addPageLayoutHandles(['type' => $type], null, false);
+ $page->addPageLayoutHandles(['type' => $pageType], null, false);
$page->addPageLayoutHandles(['id' => $category->getId()]);
// apply custom layout update once layout is loaded
- $layoutUpdates = $settings->getLayoutUpdates();
- if ($layoutUpdates && is_array($layoutUpdates)) {
- foreach ($layoutUpdates as $layoutUpdate) {
- $page->addUpdate($layoutUpdate);
- $page->addPageLayoutHandles(['layout_update' => sha1($layoutUpdate)], null, false);
- }
- }
+ $this->applyLayoutUpdates($page, $settings);
$page->getConfig()->addBodyClass('page-products')
->addBodyClass('categorypath-' . $this->categoryUrlPathGenerator->getUrlPath($category))
@@ -221,4 +223,40 @@ public function execute()
return $this->resultForwardFactory->create()->forward('noroute');
}
}
+
+ /**
+ * Get page type based on category
+ *
+ * @param Category $category
+ * @return string
+ */
+ private function getPageType(Category $category) : string
+ {
+ $hasChildren = $category->hasChildren();
+ if ($category->getIsAnchor()) {
+ return $hasChildren ? 'layered' : 'layered_without_children';
+ }
+
+ return $hasChildren ? 'default' : 'default_without_children';
+ }
+
+ /**
+ * Apply custom layout updates
+ *
+ * @param Page $page
+ * @param DataObject $settings
+ * @return void
+ */
+ private function applyLayoutUpdates(
+ Page $page,
+ DataObject $settings
+ ) {
+ $layoutUpdates = $settings->getLayoutUpdates();
+ if ($layoutUpdates && is_array($layoutUpdates)) {
+ foreach ($layoutUpdates as $layoutUpdate) {
+ $page->addUpdate($layoutUpdate);
+ $page->addPageLayoutHandles(['layout_update' => sha1($layoutUpdate)], null, false);
+ }
+ }
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
index a3d958ea537e1..e6c098ab0254e 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
@@ -115,7 +115,7 @@ public function build($storeId, $changedIds, $valueFieldSuffix)
/**
* Create empty temporary table with given columns list
*
- * @param string $tableName Table name
+ * @param string $tableName Table name
* @param array $columns array('columnName' => \Magento\Catalog\Model\ResourceModel\Eav\Attribute, ...)
* @param string $valueFieldSuffix
*
@@ -304,12 +304,16 @@ protected function _fillTemporaryTable(
/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
foreach ($columnsList as $columnName => $attribute) {
- $countTableName = 't' . $iterationNum++;
+ $countTableName = 't' . ($iterationNum++);
$joinCondition = sprintf(
- 'e.%3$s = %1$s.%3$s AND %1$s.attribute_id = %2$d AND %1$s.store_id = 0',
+ 'e.%3$s = %1$s.%3$s' .
+ ' AND %1$s.attribute_id = %2$d' .
+ ' AND (%1$s.store_id = %4$d' .
+ ' OR %1$s.store_id = 0)',
$countTableName,
$attribute->getId(),
- $metadata->getLinkField()
+ $metadata->getLinkField(),
+ $storeId
);
$select->joinLeft(
@@ -323,9 +327,10 @@ protected function _fillTemporaryTable(
$columnValueName = $attributeCode . $valueFieldSuffix;
if (isset($flatColumns[$columnValueName])) {
$valueJoinCondition = sprintf(
- 'e.%1$s = %2$s.option_id AND %2$s.store_id = 0',
+ 'e.%1$s = %2$s.option_id AND (%2$s.store_id = %3$d OR %2$s.store_id = 0)',
$attributeCode,
- $countTableName
+ $countTableName,
+ $storeId
);
$selectValue->joinLeft(
[
diff --git a/app/code/Magento/Catalog/Model/Product/Copier.php b/app/code/Magento/Catalog/Model/Product/Copier.php
index 53fa11df04b35..44ebdf0f1f283 100644
--- a/app/code/Magento/Catalog/Model/Product/Copier.php
+++ b/app/code/Magento/Catalog/Model/Product/Copier.php
@@ -1,7 +1,5 @@
setUpdatedAt(null);
$duplicate->setId(null);
$duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
-
$this->copyConstructor->build($product, $duplicate);
- $isDuplicateSaved = false;
- do {
- $urlKey = $duplicate->getUrlKey();
- $urlKey = preg_match('/(.*)-(\d+)$/', $urlKey, $matches)
- ? $matches[1] . '-' . ($matches[2] + 1)
- : $urlKey . '-1';
- $duplicate->setUrlKey($urlKey);
- $duplicate->setData('url_path', null);
- try {
- $duplicate->save();
- $isDuplicateSaved = true;
- } catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
- }
- } while (!$isDuplicateSaved);
+ $this->setDefaultUrl($product, $duplicate);
+ $this->setStoresUrl($product, $duplicate);
$this->getOptionRepository()->duplicate($product, $duplicate);
$product->getResource()->duplicate(
$product->getData($metadata->getLinkField()),
@@ -98,6 +87,81 @@ public function copy(Product $product)
return $duplicate;
}
+ /**
+ * Set default URL.
+ *
+ * @param Product $product
+ * @param Product $duplicate
+ * @return void
+ */
+ private function setDefaultUrl(Product $product, Product $duplicate) : void
+ {
+ $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
+ $resource = $product->getResource();
+ $attribute = $resource->getAttribute('url_key');
+ $productId = $product->getId();
+ $urlKey = $resource->getAttributeRawValue($productId, 'url_key', \Magento\Store\Model\Store::DEFAULT_STORE_ID);
+ do {
+ $urlKey = $this->modifyUrl($urlKey);
+ $duplicate->setUrlKey($urlKey);
+ } while (!$attribute->getEntity()->checkAttributeUniqueValue($attribute, $duplicate));
+ $duplicate->setData('url_path', null);
+ $duplicate->save();
+ }
+
+ /**
+ * Set URL for each store.
+ *
+ * @param Product $product
+ * @param Product $duplicate
+ * @return void
+ */
+ private function setStoresUrl(Product $product, Product $duplicate) : void
+ {
+ $storeIds = $duplicate->getStoreIds();
+ $productId = $product->getId();
+ $productResource = $product->getResource();
+ $defaultUrlKey = $productResource->getAttributeRawValue(
+ $productId,
+ 'url_key',
+ \Magento\Store\Model\Store::DEFAULT_STORE_ID
+ );
+ $duplicate->setData('save_rewrites_history', false);
+ foreach ($storeIds as $storeId) {
+ $isDuplicateSaved = false;
+ $duplicate->setStoreId($storeId);
+ $urlKey = $productResource->getAttributeRawValue($productId, 'url_key', $storeId);
+ if ($urlKey === $defaultUrlKey) {
+ continue;
+ }
+ do {
+ $urlKey = $this->modifyUrl($urlKey);
+ $duplicate->setUrlKey($urlKey);
+ $duplicate->setData('url_path', null);
+ try {
+ $duplicate->save();
+ $isDuplicateSaved = true;
+ // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock
+ } catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
+ }
+ } while (!$isDuplicateSaved);
+ }
+ $duplicate->setStoreId(\Magento\Store\Model\Store::DEFAULT_STORE_ID);
+ }
+
+ /**
+ * Modify URL key.
+ *
+ * @param string $urlKey
+ * @return string
+ */
+ private function modifyUrl(string $urlKey) : string
+ {
+ return preg_match('/(.*)-(\d+)$/', $urlKey, $matches)
+ ? $matches[1] . '-' . ($matches[2] + 1)
+ : $urlKey . '-1';
+ }
+
/**
* Returns product option repository.
*
diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
index 42b9639d2717b..e06e85e90a2d8 100644
--- a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
+++ b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
@@ -206,7 +206,7 @@ public function execute($product, $arguments = [])
}
/**
- * Returns media gallery atribute instance
+ * Returns media gallery attribute instance
*
* @return \Magento\Catalog\Api\Data\ProductAttributeInterface
* @since 101.0.0
@@ -230,6 +230,7 @@ public function getAttribute()
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @since 101.0.0
+ * phpcs:disable Magento2.CodeAnalysis.EmptyBlock
*/
protected function processDeletedImages($product, array &$images)
{
@@ -400,6 +401,7 @@ protected function getUniqueFileName($file, $forTmp = false)
$destinationFile = $forTmp
? $this->mediaDirectory->getAbsolutePath($this->mediaConfig->getTmpMediaPath($file))
: $this->mediaDirectory->getAbsolutePath($this->mediaConfig->getMediaPath($file));
+ // phpcs:disable Magento2.Functions.DiscouragedFunction
$destFile = dirname($file) . '/' . FileUploader::getNewFileName($destinationFile);
}
@@ -420,6 +422,7 @@ protected function copyImage($file)
$destinationFile = $this->getUniqueFileName($file);
if (!$this->mediaDirectory->isFile($this->mediaConfig->getMediaPath($file))) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
throw new \Exception();
}
@@ -437,6 +440,7 @@ protected function copyImage($file)
}
return str_replace('\\', '/', $destinationFile);
+ // phpcs:ignore Magento2.Exceptions.ThrowCatch
} catch (\Exception $e) {
$file = $this->mediaConfig->getMediaPath($file);
throw new \Magento\Framework\Exception\LocalizedException(
diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php b/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php
index 0e08b0af92862..c993e51c8bc09 100644
--- a/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php
+++ b/app/code/Magento/Catalog/Model/Product/Gallery/GalleryManagement.php
@@ -71,8 +71,10 @@ public function create($sku, ProductAttributeMediaGalleryEntryInterface $entry)
$product->setMediaGalleryEntries($existingMediaGalleryEntries);
try {
$product = $this->productRepository->save($product);
+ // phpcs:ignore Magento2.Exceptions.ThrowCatch
} catch (InputException $inputException) {
throw $inputException;
+ // phpcs:ignore Magento2.Exceptions.ThrowCatch
} catch (\Exception $e) {
throw new StateException(__("The product can't be saved."));
}
@@ -105,7 +107,10 @@ public function update($sku, ProductAttributeMediaGalleryEntryInterface $entry)
if ($existingEntry->getId() == $entry->getId()) {
$found = true;
- if ($entry->getFile()) {
+
+ $file = $entry->getContent();
+
+ if ($file && $file->getBase64EncodedData() || $entry->getFile()) {
$entry->setId(null);
}
$existingMediaGalleryEntries[$key] = $entry;
diff --git a/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php b/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php
index f6893a41113e6..dabfdb74f0118 100644
--- a/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php
+++ b/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php
@@ -17,6 +17,9 @@
*
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ *
+ * @deprecated
+ * @see \Magento\Catalog\Model\Product\Type\Price
*/
class FrontSpecialPrice extends Price
{
@@ -66,6 +69,8 @@ public function __construct(
/**
* @inheritdoc
+ *
+ * @deprecated
*/
protected function _applySpecialPrice($product, $finalPrice)
{
diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php
index 48f45d0ce9373..c87b6e9763205 100644
--- a/app/code/Magento/Catalog/Model/ProductRepository.php
+++ b/app/code/Magento/Catalog/Model/ProductRepository.php
@@ -1,18 +1,18 @@
productFactory = $productFactory;
$this->collectionFactory = $collectionFactory;
@@ -239,6 +257,8 @@ public function __construct(
$this->cacheLimit = (int)$cacheLimit;
$this->readExtensions = $readExtensions ?: \Magento\Framework\App\ObjectManager::getInstance()
->get(ReadExtensions::class);
+ $this->linkManagement = $linkManagement ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(CategoryLinkManagementInterface::class);
}
/**
@@ -381,6 +401,9 @@ private function assignProductToWebsites(\Magento\Catalog\Model\Product $product
/**
* Process new gallery media entry.
*
+ * @deprecated
+ * @see MediaGalleryProcessor::processNewMediaGalleryEntry()
+ *
* @param ProductInterface $product
* @param array $newEntry
* @return $this
@@ -392,40 +415,8 @@ protected function processNewMediaGalleryEntry(
ProductInterface $product,
array $newEntry
) {
- /** @var ImageContentInterface $contentDataObject */
- $contentDataObject = $newEntry['content'];
+ $this->getMediaGalleryProcessor()->processNewMediaGalleryEntry($product, $newEntry);
- /** @var \Magento\Catalog\Model\Product\Media\Config $mediaConfig */
- $mediaConfig = $product->getMediaConfig();
- $mediaTmpPath = $mediaConfig->getBaseTmpMediaPath();
-
- $relativeFilePath = $this->imageProcessor->processImageContent($mediaTmpPath, $contentDataObject);
- $tmpFilePath = $mediaConfig->getTmpMediaShortUrl($relativeFilePath);
-
- if (!$product->hasGalleryAttribute()) {
- throw new StateException(
- __("The product that was requested doesn't exist. Verify the product and try again.")
- );
- }
-
- $imageFileUri = $this->getMediaGalleryProcessor()->addImage(
- $product,
- $tmpFilePath,
- isset($newEntry['types']) ? $newEntry['types'] : [],
- true,
- isset($newEntry['disabled']) ? $newEntry['disabled'] : true
- );
- // Update additional fields that are still empty after addImage call
- $this->getMediaGalleryProcessor()->updateImage(
- $product,
- $imageFileUri,
- [
- 'label' => $newEntry['label'],
- 'position' => $newEntry['position'],
- 'disabled' => $newEntry['disabled'],
- 'media_type' => $newEntry['media_type'],
- ]
- );
return $this;
}
@@ -500,68 +491,13 @@ private function processLinks(ProductInterface $product, $newLinks)
* @return $this
* @throws InputException
* @throws StateException
+ * @throws LocalizedException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function processMediaGallery(ProductInterface $product, $mediaGalleryEntries)
{
- $existingMediaGallery = $product->getMediaGallery('images');
- $newEntries = [];
- $entriesById = [];
- if (!empty($existingMediaGallery)) {
- foreach ($mediaGalleryEntries as $entry) {
- if (isset($entry['value_id'])) {
- $entriesById[$entry['value_id']] = $entry;
- } else {
- $newEntries[] = $entry;
- }
- }
- foreach ($existingMediaGallery as $key => &$existingEntry) {
- if (isset($entriesById[$existingEntry['value_id']])) {
- $updatedEntry = $entriesById[$existingEntry['value_id']];
- if ($updatedEntry['file'] === null) {
- unset($updatedEntry['file']);
- }
- $existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry);
- } else {
- //set the removed flag
- $existingEntry['removed'] = true;
- }
- }
- $product->setData('media_gallery', ["images" => $existingMediaGallery]);
- } else {
- $newEntries = $mediaGalleryEntries;
- }
-
- $images = (array)$product->getMediaGallery('images');
- $images = $this->determineImageRoles($product, $images);
-
- $this->getMediaGalleryProcessor()->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
-
- foreach ($images as $image) {
- if (!isset($image['removed']) && !empty($image['types'])) {
- $this->getMediaGalleryProcessor()->setMediaAttribute($product, $image['types'], $image['file']);
- }
- }
+ $this->getMediaGalleryProcessor()->processMediaGallery($product, $mediaGalleryEntries);
- foreach ($newEntries as $newEntry) {
- if (!isset($newEntry['content'])) {
- throw new InputException(__('The image content is invalid. Verify the content and try again.'));
- }
- /** @var ImageContentInterface $contentDataObject */
- $contentDataObject = $this->contentFactory->create()
- ->setName($newEntry['content']['data'][ImageContentInterface::NAME])
- ->setBase64EncodedData($newEntry['content']['data'][ImageContentInterface::BASE64_ENCODED_DATA])
- ->setType($newEntry['content']['data'][ImageContentInterface::TYPE]);
- $newEntry['content'] = $contentDataObject;
- $this->processNewMediaGalleryEntry($product, $newEntry);
-
- $finalGallery = $product->getData('media_gallery');
- $newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById));
- $newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]);
- $entriesById[$newEntryId] = $newEntry;
- $finalGallery['images'][$newEntryId] = $newEntry;
- $product->setData('media_gallery', $finalGallery);
- }
return $this;
}
@@ -572,6 +508,7 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
*/
public function save(ProductInterface $product, $saveOptions = false)
{
+ $assignToCategories = false;
$tierPrices = $product->getData('tier_price');
try {
@@ -589,6 +526,7 @@ public function save(ProductInterface $product, $saveOptions = false)
$extensionAttributes = $product->getExtensionAttributes();
if (empty($extensionAttributes->__toArray())) {
$product->setExtensionAttributes($existingProduct->getExtensionAttributes());
+ $assignToCategories = true;
}
} catch (NoSuchEntityException $e) {
$existingProduct = null;
@@ -626,6 +564,12 @@ public function save(ProductInterface $product, $saveOptions = false)
}
$this->saveProduct($product);
+ if ($assignToCategories === true && $product->getCategoryIds()) {
+ $this->linkManagement->assignProductToCategories(
+ $product->getSku(),
+ $product->getCategoryIds()
+ );
+ }
$this->removeProductFromLocalCache($product->getSku());
unset($this->instancesById[$product->getId()]);
@@ -763,44 +707,19 @@ public function cleanCache()
$this->instancesById = null;
}
- /**
- * 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
+ * @return MediaGalleryProcessor
*/
private function getMediaGalleryProcessor()
{
- if (null === $this->mediaGalleryProcessor) {
- $this->mediaGalleryProcessor = \Magento\Framework\App\ObjectManager::getInstance()
- ->get(\Magento\Catalog\Model\Product\Gallery\Processor::class);
+ if (null === $this->mediaProcessor) {
+ $this->mediaProcessor = \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(MediaGalleryProcessor::class);
}
- return $this->mediaGalleryProcessor;
+
+ return $this->mediaProcessor;
}
/**
@@ -912,6 +831,7 @@ private function saveProduct($product): void
throw new CouldNotSaveException(__($e->getMessage()));
} catch (LocalizedException $e) {
throw $e;
+ // phpcs:disable Magento2.Exceptions.ThrowCatch
} catch (\Exception $e) {
throw new CouldNotSaveException(
__('The product was unable to be saved. Please try again.'),
diff --git a/app/code/Magento/Catalog/Model/ProductRepository/MediaGalleryProcessor.php b/app/code/Magento/Catalog/Model/ProductRepository/MediaGalleryProcessor.php
new file mode 100644
index 0000000000000..70311954f63e9
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ProductRepository/MediaGalleryProcessor.php
@@ -0,0 +1,239 @@
+processor = $processor;
+ $this->contentFactory = $contentFactory;
+ $this->imageProcessor = $imageProcessor;
+ }
+
+ /**
+ * Process Media gallery data before save product.
+ *
+ * Compare Media Gallery Entries Data with existing Media Gallery
+ * * If Media entry has not value_id set it as new
+ * * If Existing entry 'value_id' absent in Media Gallery set 'removed' flag
+ * * Merge Existing and new media gallery
+ *
+ * @param ProductInterface $product contains only existing media gallery items
+ * @param array $mediaGalleryEntries array which contains all media gallery items
+ * @return void
+ * @throws InputException
+ * @throws StateException
+ * @throws LocalizedException
+ */
+ public function processMediaGallery(ProductInterface $product, array $mediaGalleryEntries) :void
+ {
+ $existingMediaGallery = $product->getMediaGallery('images');
+ $newEntries = [];
+ $entriesById = [];
+ if (!empty($existingMediaGallery)) {
+ foreach ($mediaGalleryEntries as $entry) {
+ if (isset($entry['value_id'])) {
+ $entriesById[$entry['value_id']] = $entry;
+ } else {
+ $newEntries[] = $entry;
+ }
+ }
+ foreach ($existingMediaGallery as $key => &$existingEntry) {
+ if (isset($entriesById[$existingEntry['value_id']])) {
+ $updatedEntry = $entriesById[$existingEntry['value_id']];
+ if ($updatedEntry['file'] === null) {
+ unset($updatedEntry['file']);
+ }
+ $existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry);
+ } else {
+ //set the removed flag
+ $existingEntry['removed'] = true;
+ }
+ }
+ $product->setData('media_gallery', ["images" => $existingMediaGallery]);
+ } else {
+ $newEntries = $mediaGalleryEntries;
+ }
+
+ $images = (array)$product->getMediaGallery('images');
+ $images = $this->determineImageRoles($product, $images);
+
+ $this->processor->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
+
+ $this->processMediaAttributes($product, $images);
+ $this->processEntries($product, $newEntries, $entriesById);
+ }
+
+ /**
+ * Process new gallery media entry.
+ *
+ * @param ProductInterface $product
+ * @param array $newEntry
+ * @return void
+ * @throws InputException
+ * @throws StateException
+ * @throws LocalizedException
+ */
+ public function processNewMediaGalleryEntry(
+ ProductInterface $product,
+ array $newEntry
+ ) :void {
+ /** @var ImageContentInterface $contentDataObject */
+ $contentDataObject = $newEntry['content'];
+
+ /** @var Config $mediaConfig */
+ $mediaConfig = $product->getMediaConfig();
+ $mediaTmpPath = $mediaConfig->getBaseTmpMediaPath();
+
+ $relativeFilePath = $this->imageProcessor->processImageContent($mediaTmpPath, $contentDataObject);
+ $tmpFilePath = $mediaConfig->getTmpMediaShortUrl($relativeFilePath);
+
+ if (!$product->hasGalleryAttribute()) {
+ throw new StateException(
+ __("The product that was requested doesn't exist. Verify the product and try again.")
+ );
+ }
+
+ $imageFileUri = $this->processor->addImage(
+ $product,
+ $tmpFilePath,
+ isset($newEntry['types']) ? $newEntry['types'] : [],
+ true,
+ isset($newEntry['disabled']) ? $newEntry['disabled'] : true
+ );
+ // Update additional fields that are still empty after addImage call
+ $this->processor->updateImage(
+ $product,
+ $imageFileUri,
+ [
+ 'label' => $newEntry['label'],
+ 'position' => $newEntry['position'],
+ 'disabled' => $newEntry['disabled'],
+ 'media_type' => $newEntry['media_type'],
+ ]
+ );
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Convert entries into product media gallery data and set to product.
+ *
+ * @param ProductInterface $product
+ * @param array $newEntries
+ * @param array $entriesById
+ * @throws InputException
+ * @throws LocalizedException
+ * @throws StateException
+ */
+ private function processEntries(ProductInterface $product, array $newEntries, array $entriesById): void
+ {
+ foreach ($newEntries as $newEntry) {
+ if (!isset($newEntry['content'])) {
+ throw new InputException(__('The image content is invalid. Verify the content and try again.'));
+ }
+ /** @var ImageContentInterface $contentDataObject */
+ $contentDataObject = $this->contentFactory->create()
+ ->setName($newEntry['content']['data'][ImageContentInterface::NAME])
+ ->setBase64EncodedData($newEntry['content']['data'][ImageContentInterface::BASE64_ENCODED_DATA])
+ ->setType($newEntry['content']['data'][ImageContentInterface::TYPE]);
+ $newEntry['content'] = $contentDataObject;
+ $this->processNewMediaGalleryEntry($product, $newEntry);
+
+ $finalGallery = $product->getData('media_gallery');
+ $newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById));
+ $newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]);
+ $entriesById[$newEntryId] = $newEntry;
+ $finalGallery['images'][$newEntryId] = $newEntry;
+ $product->setData('media_gallery', $finalGallery);
+ }
+ }
+
+ /**
+ * Set media attribute values.
+ *
+ * @param ProductInterface $product
+ * @param array $images
+ */
+ private function processMediaAttributes(ProductInterface $product, array $images): void
+ {
+ foreach ($images as $image) {
+ if (!isset($image['removed']) && !empty($image['types'])) {
+ $this->processor->setMediaAttribute($product, $image['types'], $image['file']);
+ }
+ }
+ }
+}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php
index b5668a12f94a5..657daca13055e 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php
@@ -7,7 +7,6 @@
use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator;
use Magento\Framework\App\Config\ScopeConfigInterface;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
use Magento\Store\Model\ScopeInterface;
/**
@@ -83,8 +82,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
- *
- * @param ResourceModelPoolInterface|null $resourceModelPool
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -99,8 +96,7 @@ public function __construct(
\Magento\Framework\Validator\UniversalFactory $universalFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
- \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null,
- ResourceModelPoolInterface $resourceModelPool = null
+ \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig = null
) {
parent::__construct(
$entityFactory,
@@ -113,8 +109,7 @@ public function __construct(
$resourceHelper,
$universalFactory,
$storeManager,
- $connection,
- $resourceModelPool
+ $connection
);
$this->scopeConfig = $scopeConfig ?:
\Magento\Framework\App\ObjectManager::getInstance()->get(ScopeConfigInterface::class);
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php b/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php
index 2e40d13f1ccac..3a0d47fe573fb 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Collection/AbstractCollection.php
@@ -5,8 +5,6 @@
*/
namespace Magento\Catalog\Model\ResourceModel\Collection;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
-
/**
* Catalog EAV collection resource abstract model
*
@@ -45,8 +43,6 @@ class AbstractCollection extends \Magento\Eav\Model\Entity\Collection\AbstractCo
* @param \Magento\Framework\Validator\UniversalFactory $universalFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
- *
- * @param ResourceModelPoolInterface|null $resourceModelPool
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -60,8 +56,7 @@ public function __construct(
\Magento\Eav\Model\ResourceModel\Helper $resourceHelper,
\Magento\Framework\Validator\UniversalFactory $universalFactory,
\Magento\Store\Model\StoreManagerInterface $storeManager,
- \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
- ResourceModelPoolInterface $resourceModelPool = null
+ \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
) {
$this->_storeManager = $storeManager;
parent::__construct(
@@ -74,8 +69,7 @@ public function __construct(
$eavEntityFactory,
$resourceHelper,
$universalFactory,
- $connection,
- $resourceModelPool
+ $connection
);
}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php
index 23f612582f42e..d56cc40ad0fc2 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php
@@ -845,9 +845,14 @@ public function afterDelete()
/**
* @inheritdoc
* @since 100.0.9
+ *
+ * @SuppressWarnings(PHPMD.SerializationAware)
+ * @deprecated Do not use PHP serialization.
*/
public function __sleep()
{
+ trigger_error('Using PHP serialization is deprecated', E_USER_DEPRECATED);
+
$this->unsetData('entity_type');
return array_diff(
parent::__sleep(),
@@ -858,9 +863,14 @@ public function __sleep()
/**
* @inheritdoc
* @since 100.0.9
+ *
+ * @SuppressWarnings(PHPMD.SerializationAware)
+ * @deprecated Do not use PHP serialization.
*/
public function __wakeup()
{
+ trigger_error('Using PHP serialization is deprecated', E_USER_DEPRECATED);
+
parent::__wakeup();
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_indexerEavProcessor = $objectManager->get(\Magento\Catalog\Model\Indexer\Product\Flat\Processor::class);
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
index 136c7e800bf08..0cdf8b39f7d52 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
@@ -7,6 +7,8 @@
namespace Magento\Catalog\Model\ResourceModel\Product;
use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
+use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver;
use Magento\Catalog\Model\Product\Attribute\Source\Status as ProductStatus;
use Magento\Catalog\Model\Product\Gallery\ReadHandler as GalleryReadHandler;
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
@@ -16,12 +18,10 @@
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;
use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
+use Magento\Store\Model\Indexer\WebsiteDimensionProvider;
+use Magento\Store\Model\Store;
/**
* Product collection
@@ -32,6 +32,7 @@
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
* @SuppressWarnings(PHPMD.NumberOfChildren)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
* @since 100.0.2
*/
class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\AbstractCollection
@@ -324,7 +325,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
* @param TableMaintainer|null $tableMaintainer
* @param PriceTableResolver|null $priceTableResolver
* @param DimensionFactory|null $dimensionFactory
- * @param ResourceModelPoolInterface|null $resourceModelPool
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
@@ -353,8 +353,7 @@ public function __construct(
MetadataPool $metadataPool = null,
TableMaintainer $tableMaintainer = null,
PriceTableResolver $priceTableResolver = null,
- DimensionFactory $dimensionFactory = null,
- ResourceModelPoolInterface $resourceModelPool = null
+ DimensionFactory $dimensionFactory = null
) {
$this->moduleManager = $moduleManager;
$this->_catalogProductFlatState = $catalogProductFlatState;
@@ -382,8 +381,7 @@ public function __construct(
$resourceHelper,
$universalFactory,
$storeManager,
- $connection,
- $resourceModelPool
+ $connection
);
$this->tableMaintainer = $tableMaintainer ?: ObjectManager::getInstance()->get(TableMaintainer::class);
$this->priceTableResolver = $priceTableResolver ?: ObjectManager::getInstance()->get(PriceTableResolver::class);
@@ -445,7 +443,7 @@ protected function _preparePriceExpressionParameters($select)
*/
public function getPriceExpression($select)
{
- //@todo: Add caching of price expresion
+ //@todo: Add caching of price expression
$this->_preparePriceExpressionParameters($select);
return $this->_priceExpression;
}
@@ -1979,6 +1977,7 @@ protected function _productLimitationPrice($joinLeft = false)
}
// Set additional field filters
foreach ($this->_priceDataFieldFilters as $filterData) {
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
$select->where(call_user_func_array('sprintf', $filterData));
}
} else {
@@ -2284,6 +2283,7 @@ private function getBackend()
public function addPriceDataFieldFilter($comparisonFormat, $fields)
{
if (!preg_match('/^%s( (<|>|=|<=|>=|<>) %s)*$/', $comparisonFormat)) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
throw new \Exception('Invalid comparison format.');
}
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Compare/Item/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Compare/Item/Collection.php
index a45e2060d7c20..aa6fb8c1f8827 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Compare/Item/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Compare/Item/Collection.php
@@ -5,13 +5,6 @@
*/
namespace Magento\Catalog\Model\ResourceModel\Product\Compare\Item;
-use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
-use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver;
-use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
-use Magento\Framework\EntityManager\MetadataPool;
-use Magento\Framework\Indexer\DimensionFactory;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
-
/**
* Catalog Product Compare Items Resource Collection
*
@@ -19,6 +12,7 @@
* @author Magento Core Team
* @SuppressWarnings(PHPMD.LongVariable)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
* @since 100.0.2
*/
class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
@@ -82,12 +76,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
* @param \Magento\Catalog\Model\ResourceModel\Product\Compare\Item $catalogProductCompareItem
* @param \Magento\Catalog\Helper\Product\Compare $catalogProductCompare
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
- * @param ProductLimitationFactory|null $productLimitationFactory
- * @param MetadataPool|null $metadataPool
- * @param TableMaintainer|null $tableMaintainer
- * @param PriceTableResolver|null $priceTableResolver
- * @param DimensionFactory|null $dimensionFactory
- * @param ResourceModelPoolInterface|null $resourceModelPool
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -112,13 +100,7 @@ public function __construct(
\Magento\Customer\Api\GroupManagementInterface $groupManagement,
\Magento\Catalog\Model\ResourceModel\Product\Compare\Item $catalogProductCompareItem,
\Magento\Catalog\Helper\Product\Compare $catalogProductCompare,
- \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
- ProductLimitationFactory $productLimitationFactory = null,
- MetadataPool $metadataPool = null,
- TableMaintainer $tableMaintainer = null,
- PriceTableResolver $priceTableResolver = null,
- DimensionFactory $dimensionFactory = null,
- ResourceModelPoolInterface $resourceModelPool = null
+ \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
) {
$this->_catalogProductCompareItem = $catalogProductCompareItem;
$this->_catalogProductCompare = $catalogProductCompare;
@@ -142,13 +124,7 @@ public function __construct(
$customerSession,
$dateTime,
$groupManagement,
- $connection,
- $productLimitationFactory,
- $metadataPool,
- $tableMaintainer,
- $priceTableResolver,
- $dimensionFactory,
- $resourceModelPool
+ $connection
);
}
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 318c9bd132ccd..494dbac02d792 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php
@@ -17,11 +17,12 @@
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
+use Magento\Catalog\Helper\Data;
/**
* Catalog product custom option resource model
*
- * @author Magento Core Team
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Value extends AbstractDb
{
@@ -51,6 +52,11 @@ class Value extends AbstractDb
*/
private $localeFormat;
+ /**
+ * @var Data
+ */
+ private $dataHelper;
+
/**
* Class constructor
*
@@ -59,17 +65,21 @@ class Value extends AbstractDb
* @param StoreManagerInterface $storeManager
* @param ScopeConfigInterface $config
* @param string $connectionName
+ * @param Data $dataHelper
*/
public function __construct(
Context $context,
CurrencyFactory $currencyFactory,
StoreManagerInterface $storeManager,
ScopeConfigInterface $config,
- $connectionName = null
+ $connectionName = null,
+ Data $dataHelper = null
) {
$this->_currencyFactory = $currencyFactory;
$this->_storeManager = $storeManager;
$this->_config = $config;
+ $this->dataHelper = $dataHelper ?: ObjectManager::getInstance()
+ ->get(Data::class);
parent::__construct($context, $connectionName);
}
@@ -131,7 +141,7 @@ protected function _saveValuePrices(AbstractModel $object)
$optionTypeId = $this->getConnection()->fetchOne($select);
if ($optionTypeId) {
- if ($object->getStoreId() == '0') {
+ if ($object->getStoreId() == '0' || $this->dataHelper->isPriceGlobal()) {
$bind = ['price' => $price, 'price_type' => $priceType];
$where = [
'option_type_id = ?' => $optionTypeId,
diff --git a/app/code/Magento/Catalog/Setup/CategorySetup.php b/app/code/Magento/Catalog/Setup/CategorySetup.php
index 271387932829b..f8542454bef92 100644
--- a/app/code/Magento/Catalog/Setup/CategorySetup.php
+++ b/app/code/Magento/Catalog/Setup/CategorySetup.php
@@ -10,7 +10,6 @@
use Magento\Catalog\Block\Adminhtml\Category\Helper\Pricestep;
use Magento\Catalog\Block\Adminhtml\Category\Helper\Sortby\Available;
use Magento\Catalog\Block\Adminhtml\Category\Helper\Sortby\DefaultSortby;
-use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\BaseImage;
use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Category as CategoryFormHelper;
use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight as WeightFormHelper;
use Magento\Catalog\Model\Attribute\Backend\Customlayoutupdate;
@@ -54,6 +53,8 @@
use Magento\Theme\Model\Theme\Source\Theme;
/**
+ * Setup category with default entities.
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class CategorySetup extends EavSetup
@@ -593,7 +594,6 @@ public function getDefaultEntities()
'label' => 'Base Image',
'input' => 'media_image',
'frontend' => ImageFrontendModel::class,
- 'input_renderer' => BaseImage::class,
'required' => false,
'sort_order' => 0,
'global' => ScopedAttributeInterface::SCOPE_STORE,
@@ -626,7 +626,6 @@ public function getDefaultEntities()
'type' => 'varchar',
'label' => 'Media Gallery',
'input' => 'gallery',
- 'backend' => Media::class,
'required' => false,
'sort_order' => 4,
'group' => 'Images',
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml
new file mode 100644
index 0000000000000..dd66919640a73
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminOpenNewProductFormPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminOpenNewProductFormPageActionGroup.xml
new file mode 100644
index 0000000000000..fe859fab52667
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminOpenNewProductFormPageActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
index da570f9ed99b0..3c44a8f1898ad 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
@@ -19,6 +19,14 @@
+
+
+
+
+
+
+
+
@@ -96,6 +104,9 @@
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
index 46329dde278bc..86158aba68f82 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
@@ -65,6 +65,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
index 2914ecc470220..019d103a31cf2 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
@@ -45,6 +45,9 @@
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
index cbdabe6a2d218..ad32b8edbd243 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
@@ -289,4 +289,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductInWidgetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductInWidgetActionGroup.xml
new file mode 100644
index 0000000000000..c25b73bab21ae
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductInWidgetActionGroup.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontClickAddToCartOnProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontClickAddToCartOnProductPageActionGroup.xml
new file mode 100644
index 0000000000000..fb2065d228d5a
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontClickAddToCartOnProductPageActionGroup.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..24e1fe9cf5ecd
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+ Catalog
+ Catalog
+ magento-catalog-catalog
+
+
+ Default Category (ID: 2)
+ Categories
+ magento-catalog-catalog-categories
+
+
+ Products
+ Products
+ magento-catalog-catalog-products
+
+
+ Attribute Sets
+ Attribute Set
+ magento-catalog-catalog-attributes-sets
+
+
+ Product Attributes
+ Product
+ magento-catalog-catalog-attributes-attributes
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/AttributeSetData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/AttributeSetData.xml
new file mode 100644
index 0000000000000..6e1b25fb9cdc4
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/AttributeSetData.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ 4
+ Default
+ 0
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CatalogRecentlyProductsConfigData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogRecentlyProductsConfigData.xml
new file mode 100644
index 0000000000000..d1e469deaebba
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogRecentlyProductsConfigData.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+ EnableCatalogRecentlyProductsSynchronize
+
+
+
+ 1
+
+
+
+ DefaultCatalogRecentlyProductsSynchronize
+
+
+
+ 0
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
index 134abcaa50354..817dd637f81dd 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
@@ -73,6 +73,20 @@
false
ProductAttributeFrontendLabel
+
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+
attribute
select
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
index 713c453bb7ad4..6d4314a6d865f 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
@@ -20,4 +20,10 @@
7
1
+
+
+ 0
+ 0
+ 0
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
index ba4a623e35def..b8d6ec8e63e71 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
@@ -305,6 +305,15 @@
magento-again
jpg
+
+ magento-adobe
+ 1.00
+ Upload File
+ Yes
+ adobe-base.jpg
+ adobe-base
+ jpg
+
霁产品
simple
@@ -940,6 +949,19 @@
13
0
+
+ AAA Product
+
+
+ BBB Product
+
+
+ Product "!@#$%^&*()+:;\|}{][?=~`
+ |}{][?=~`
+
+
+ ProductWith128Chars 1234567891123456789112345678911234567891123456789112345678911234567891123456789112345678 endnums
+
sku_simple_product_
simple
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
index ea0bcafe56c48..71c8af318e9b4 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
@@ -12,4 +12,7 @@
10
100
+
+ 1
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml
index 83f0a56c21545..18564ff101fd9 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml
@@ -12,4 +12,24 @@
Catalog Product Link
Product Link Block Template
+
+ Recently Compared Products
+ Magento Luma
+ Recently Compared Products
+
+ - All Store Views
+
+ All Pages
+ Sidebar Additional
+
+
+ Recently Viewed Products
+ Magento Luma
+ Recently Viewed Products
+
+ - All Store Views
+
+ All Pages
+ Sidebar Additional
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_recently_products-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_recently_products-meta.xml
new file mode 100644
index 0000000000000..0fe4f154d5ef5
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_recently_products-meta.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml
index e23a503266e33..dd5d5aef08a7c 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml
@@ -10,5 +10,6 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCatalogProductWidgetSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCatalogProductWidgetSection.xml
new file mode 100644
index 0000000000000..3261db1f63f24
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCatalogProductWidgetSection.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml
index 697648cedb7ba..3ef78a3fe8f41 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml
@@ -14,6 +14,7 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml
index e159a4ce5c0b6..a2a349ed67611 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml
@@ -17,8 +17,23 @@
-
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml
index da282d06145aa..f515171e835db 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml
@@ -203,7 +203,9 @@
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontWidgetsSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontWidgetsSection.xml
new file mode 100644
index 0000000000000..87aab45bd8cb7
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontWidgetsSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml
new file mode 100644
index 0000000000000..4f66395bd0fbf
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddDefaultImageSimpleProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddDefaultImageSimpleProductTest.xml
index 88a39a9087bb3..117f094ee0607 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddDefaultImageSimpleProductTest.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddDefaultImageSimpleProductTest.xml
@@ -43,7 +43,9 @@
-
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogCategoriesNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogCategoriesNavigateMenuTest.xml
new file mode 100644
index 0000000000000..a51df86d0327a
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogCategoriesNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogProductsNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogProductsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..1d9400bf81e4d
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogProductsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberAfterSaveAndCloseActionTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberAfterSaveAndCloseActionTest.xml
new file mode 100644
index 0000000000000..b24ed7f9c9a81
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberAfterSaveAndCloseActionTest.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresAttributeSetNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresAttributeSetNavigateMenuTest.xml
new file mode 100644
index 0000000000000..ed29c281b804c
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresAttributeSetNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresProductNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresProductNavigateMenuTest.xml
new file mode 100644
index 0000000000000..28a33c4f20c01
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresProductNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml
index df4803bcd7906..fb95fc3f57bca 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml
@@ -52,10 +52,6 @@
-
-
-
-
@@ -67,6 +63,14 @@
+
+
+
+
+
+
+
+
@@ -78,8 +82,9 @@
-
-
+
+
+
@@ -101,15 +106,12 @@
-
-
-
-
-
+
+
+
-
@@ -129,11 +131,9 @@
-
-
-
-
-
+
+
+
@@ -176,24 +176,29 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
@@ -205,14 +210,12 @@
-
-
-
-
-
-
-
+
+
+
+
+
@@ -250,13 +253,22 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -296,8 +308,7 @@
-
-
+
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php
index d93520297e485..60c6f2f1bd821 100644
--- a/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php
@@ -124,7 +124,7 @@ protected function setUp()
->disableOriginalConstructor()->getMock();
$this->pageConfig->expects($this->any())->method('addBodyClass')->will($this->returnSelf());
- $this->page = $this->getMockBuilder(\Magento\Framework\View\Page::class)
+ $this->page = $this->getMockBuilder(\Magento\Framework\View\Result\Page::class)
->setMethods(['getConfig', 'initLayout', 'addPageLayoutHandles', 'getLayout', 'addUpdate'])
->disableOriginalConstructor()->getMock();
$this->page->expects($this->any())->method('getConfig')->will($this->returnValue($this->pageConfig));
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php
index e9eee5c766883..80b6db2a516bd 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php
@@ -6,10 +6,12 @@
namespace Magento\Catalog\Test\Unit\Model\Product;
use Magento\Catalog\Api\Data\ProductInterface;
-use \Magento\Catalog\Model\Product\Copier;
use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Copier;
/**
+ * Test for Magento\Catalog\Model\Product\Copier class.
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class CopierTest extends \PHPUnit\Framework\TestCase
@@ -76,6 +78,9 @@ protected function setUp()
]);
}
+ /**
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
public function testCopy()
{
$stockItem = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockItemInterface::class)
@@ -103,8 +108,44 @@ public function testCopy()
['linkField', null, '1'],
]);
- $resourceMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class);
- $this->productMock->expects($this->once())->method('getResource')->will($this->returnValue($resourceMock));
+ $entityMock = $this->getMockForAbstractClass(
+ \Magento\Eav\Model\Entity\AbstractEntity::class,
+ [],
+ '',
+ false,
+ true,
+ true,
+ ['checkAttributeUniqueValue']
+ );
+ $entityMock->expects($this->any())
+ ->method('checkAttributeUniqueValue')
+ ->willReturn(true);
+
+ $attributeMock = $this->getMockForAbstractClass(
+ \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
+ [],
+ '',
+ false,
+ true,
+ true,
+ ['getEntity']
+ );
+ $attributeMock->expects($this->any())
+ ->method('getEntity')
+ ->willReturn($entityMock);
+
+ $resourceMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getAttributeRawValue', 'duplicate', 'getAttribute'])
+ ->getMock();
+ $resourceMock->expects($this->any())
+ ->method('getAttributeRawValue')
+ ->willReturn('urk-key-1');
+ $resourceMock->expects($this->any())
+ ->method('getAttribute')
+ ->willReturn($attributeMock);
+
+ $this->productMock->expects($this->any())->method('getResource')->will($this->returnValue($resourceMock));
$duplicateMock = $this->createPartialMock(
Product::class,
@@ -119,11 +160,11 @@ public function testCopy()
'setCreatedAt',
'setUpdatedAt',
'setId',
- 'setStoreId',
'getEntityId',
'save',
'setUrlKey',
- 'getUrlKey',
+ 'setStoreId',
+ 'getStoreIds',
]
);
$this->productFactoryMock->expects($this->once())->method('create')->will($this->returnValue($duplicateMock));
@@ -138,19 +179,13 @@ public function testCopy()
)->with(
\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED
);
+ $duplicateMock->expects($this->atLeastOnce())->method('setStoreId');
$duplicateMock->expects($this->once())->method('setCreatedAt')->with(null);
$duplicateMock->expects($this->once())->method('setUpdatedAt')->with(null);
$duplicateMock->expects($this->once())->method('setId')->with(null);
- $duplicateMock->expects(
- $this->once()
- )->method(
- 'setStoreId'
- )->with(
- \Magento\Store\Model\Store::DEFAULT_STORE_ID
- );
+ $duplicateMock->expects($this->atLeastOnce())->method('getStoreIds')->willReturn([]);
$duplicateMock->expects($this->atLeastOnce())->method('setData')->willReturn($duplicateMock);
$this->copyConstructorMock->expects($this->once())->method('build')->with($this->productMock, $duplicateMock);
- $duplicateMock->expects($this->once())->method('getUrlKey')->willReturn('urk-key-1');
$duplicateMock->expects($this->once())->method('setUrlKey')->with('urk-key-2')->willReturn($duplicateMock);
$duplicateMock->expects($this->once())->method('save');
@@ -158,7 +193,8 @@ public function testCopy()
$duplicateMock->expects($this->any())->method('getData')->willReturnMap([
['linkField', null, '2'],
- ]); $this->optionRepositoryMock->expects($this->once())
+ ]);
+ $this->optionRepositoryMock->expects($this->once())
->method('duplicate')
->with($this->productMock, $duplicateMock);
$resourceMock->expects($this->once())->method('duplicate')->with(1, 2);
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
index c729a0c58e1ec..cb92cc6c2d523 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
@@ -1,6 +1,5 @@
productFactory = $this->createPartialMock(
- \Magento\Catalog\Model\ProductFactory::class,
+ ProductFactory::class,
['create', 'setData']
);
$this->product = $this->createPartialMock(
- \Magento\Catalog\Model\Product::class,
+ Product::class,
[
'getId',
'getSku',
@@ -200,12 +210,13 @@ protected function setUp()
'setData',
'getStoreId',
'getMediaGalleryEntries',
- 'getExtensionAttributes'
+ 'getExtensionAttributes',
+ 'getCategoryIds'
]
);
$this->initializedProduct = $this->createPartialMock(
- \Magento\Catalog\Model\Product::class,
+ Product::class,
[
'getWebsiteIds',
'setProductOptions',
@@ -220,7 +231,8 @@ protected function setUp()
'validate',
'save',
'getMediaGalleryEntries',
- 'getExtensionAttributes'
+ 'getExtensionAttributes',
+ 'getCategoryIds'
]
);
$this->initializedProduct->expects($this->any())
@@ -232,7 +244,7 @@ protected function setUp()
$this->searchCriteriaBuilder = $this->createMock(SearchCriteriaBuilder::class);
$this->metadataService = $this->createMock(ProductAttributeRepositoryInterface::class);
$this->searchResultsFactory = $this->createPartialMock(
- \Magento\Catalog\Api\Data\ProductSearchResultsInterfaceFactory::class,
+ ProductSearchResultsInterfaceFactory::class,
['create']
);
$this->resourceModel = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class);
@@ -269,15 +281,21 @@ protected function setUp()
$this->initializedProduct
->method('getExtensionAttributes')
->willReturn($this->productExtension);
+ $this->product
+ ->method('getCategoryIds')
+ ->willReturn([1, 2, 3, 4]);
+ $this->initializedProduct
+ ->method('getCategoryIds')
+ ->willReturn([1, 2, 3, 4]);
$storeMock = $this->getMockBuilder(StoreInterface::class)
->disableOriginalConstructor()
->setMethods([])
->getMockForAbstractClass();
$storeMock->expects($this->any())->method('getWebsiteId')->willReturn('1');
- $storeMock->expects($this->any())->method('getCode')->willReturn(\Magento\Store\Model\Store::ADMIN_CODE);
+ $storeMock->expects($this->any())->method('getCode')->willReturn(Store::ADMIN_CODE);
$this->storeManager->expects($this->any())->method('getStore')->willReturn($storeMock);
- $this->mediaGalleryProcessor = $this->createMock(\Magento\Catalog\Model\Product\Gallery\Processor::class);
+ $this->processor = $this->createMock(Processor::class);
$this->collectionProcessor = $this->getMockBuilder(CollectionProcessorInterface::class)
->getMock();
@@ -293,6 +311,14 @@ function ($value) {
)
);
+ $mediaProcessor = $this->objectManager->getObject(
+ ProductRepository\MediaGalleryProcessor::class,
+ [
+ 'processor' => $this->processor,
+ 'contentFactory' => $this->contentFactory,
+ 'imageProcessor' => $this->imageProcessor,
+ ]
+ );
$this->model = $this->objectManager->getObject(
ProductRepository::class,
[
@@ -307,17 +333,16 @@ function ($value) {
'extensibleDataObjectConverter' => $this->extensibleDataObjectConverter,
'contentValidator' => $this->contentValidator,
'fileSystem' => $this->fileSystem,
- 'contentFactory' => $this->contentFactory,
'mimeTypeExtensionMap' => $this->mimeTypeExtensionMap,
'linkTypeProvider' => $this->linkTypeProvider,
- 'imageProcessor' => $this->imageProcessor,
'storeManager' => $this->storeManager,
- 'mediaGalleryProcessor' => $this->mediaGalleryProcessor,
+ 'mediaGalleryProcessor' => $this->processor,
'collectionProcessor' => $this->collectionProcessor,
'serializer' => $this->serializerMock,
'cacheLimit' => $this->cacheLimit
]
);
+ $this->objectManager->setBackwardCompatibleProperty($this->model, 'mediaProcessor', $mediaProcessor);
}
/**
@@ -500,7 +525,7 @@ private function getProductMocksForReducedCache($productsCount)
$productMocks = [];
for ($i = 1; $i <= $productsCount; $i++) {
- $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+ $productMock = $this->getMockBuilder(Product::class)
->disableOriginalConstructor()
->setMethods([
'getId',
@@ -753,8 +778,8 @@ public function testDeleteById()
public function testGetList()
{
- $searchCriteriaMock = $this->createMock(\Magento\Framework\Api\SearchCriteriaInterface::class);
- $collectionMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product\Collection::class);
+ $searchCriteriaMock = $this->createMock(SearchCriteriaInterface::class);
+ $collectionMock = $this->createMock(Collection::class);
$this->collectionFactory->expects($this->once())->method('create')->willReturn($collectionMock);
$this->product->method('getSku')->willReturn('simple');
$collectionMock->expects($this->once())->method('addAttributeToSelect')->with('*');
@@ -769,7 +794,7 @@ public function testGetList()
$collectionMock->expects($this->once())->method('addCategoryIds');
$collectionMock->expects($this->atLeastOnce())->method('getItems')->willReturn([$this->product]);
$collectionMock->expects($this->once())->method('getSize')->willReturn(128);
- $searchResultsMock = $this->createMock(\Magento\Catalog\Api\Data\ProductSearchResultsInterface::class);
+ $searchResultsMock = $this->createMock(ProductSearchResultsInterface::class);
$searchResultsMock->expects($this->once())->method('setSearchCriteria')->with($searchCriteriaMock);
$searchResultsMock->expects($this->once())->method('setItems')->with([$this->product]);
$this->searchResultsFactory->expects($this->once())->method('create')->willReturn($searchResultsMock);
@@ -903,8 +928,8 @@ public function saveExistingWithOptionsDataProvider()
],
];
- /** @var \Magento\Catalog\Model\Product\Option|\PHPUnit_Framework_MockObject_MockObject $existingOption1 */
- $existingOption1 = $this->getMockBuilder(\Magento\Catalog\Model\Product\Option::class)
+ /** @var Option|MockObject $existingOption1 */
+ $existingOption1 = $this->getMockBuilder(Option::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
@@ -914,8 +939,8 @@ public function saveExistingWithOptionsDataProvider()
"type" => "drop_down",
]
);
- /** @var \Magento\Catalog\Model\Product\Option\Value $existingOptionValue1 */
- $existingOptionValue1 = $this->getMockBuilder(\Magento\Catalog\Model\Product\Option\Value::class)
+ /** @var Value $existingOptionValue1 */
+ $existingOptionValue1 = $this->getMockBuilder(Value::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
@@ -926,7 +951,7 @@ public function saveExistingWithOptionsDataProvider()
"price" => 5,
]
);
- $existingOptionValue2 = $this->getMockBuilder(\Magento\Catalog\Model\Product\Option\Value::class)
+ $existingOptionValue2 = $this->getMockBuilder(Value::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
@@ -943,7 +968,7 @@ public function saveExistingWithOptionsDataProvider()
"9" => $existingOptionValue2,
]
);
- $existingOption2 = $this->getMockBuilder(\Magento\Catalog\Model\Product\Option::class)
+ $existingOption2 = $this->getMockBuilder(Option::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
@@ -1008,8 +1033,8 @@ public function saveExistingWithOptionsDataProvider()
* @param array $existingLinks
* @param array $expectedData
* @dataProvider saveWithLinksDataProvider
- * @throws \Magento\Framework\Exception\CouldNotSaveException
- * @throws \Magento\Framework\Exception\InputException
+ * @throws CouldNotSaveException
+ * @throws InputException
*/
public function testSaveWithLinks(array $newLinks, array $existingLinks, array $expectedData)
{
@@ -1037,7 +1062,7 @@ public function testSaveWithLinks(array $newLinks, array $existingLinks, array $
->expects($this->any())->method('getProductsIdsBySkus')
->willReturn([$newLinks['linked_product_sku'] => $newLinks['linked_product_sku']]);
- $inputLink = $this->objectManager->getObject(\Magento\Catalog\Model\ProductLink\Link::class);
+ $inputLink = $this->objectManager->getObject(Link::class);
$inputLink->setProductSku($newLinks['product_sku']);
$inputLink->setLinkType($newLinks['link_type']);
$inputLink->setLinkedProductSku($newLinks['linked_product_sku']);
@@ -1081,7 +1106,7 @@ public function testSaveWithLinks(array $newLinks, array $existingLinks, array $
$outputLinks = [];
if (!empty($expectedData)) {
foreach ($expectedData as $link) {
- $outputLink = $this->objectManager->getObject(\Magento\Catalog\Model\ProductLink\Link::class);
+ $outputLink = $this->objectManager->getObject(Link::class);
$outputLink->setProductSku($link['product_sku']);
$outputLink->setLinkType($link['link_type']);
$outputLink->setLinkedProductSku($link['linked_product_sku']);
@@ -1235,10 +1260,10 @@ public function testSaveExistingWithNewMediaGalleryEntries()
$mediaTmpPath = '/tmp';
$absolutePath = '/a/b/filename.jpg';
- $this->mediaGalleryProcessor->expects($this->once())->method('clearMediaAttribute')
+ $this->processor->expects($this->once())->method('clearMediaAttribute')
->with($this->initializedProduct, ['image', 'small_image']);
- $mediaConfigMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Media\Config::class)
+ $mediaConfigMock = $this->getMockBuilder(Config::class)
->disableOriginalConstructor()
->getMock();
$mediaConfigMock->expects($this->once())
@@ -1250,7 +1275,7 @@ public function testSaveExistingWithNewMediaGalleryEntries()
->willReturn($mediaConfigMock);
//verify new entries
- $contentDataObject = $this->getMockBuilder(\Magento\Framework\Api\ImageContent::class)
+ $contentDataObject = $this->getMockBuilder(ImageContent::class)
->disableOriginalConstructor()
->setMethods(null)
->getMock();
@@ -1263,10 +1288,10 @@ public function testSaveExistingWithNewMediaGalleryEntries()
->willReturn($absolutePath);
$imageFileUri = "imageFileUri";
- $this->mediaGalleryProcessor->expects($this->once())->method('addImage')
+ $this->processor->expects($this->once())->method('addImage')
->with($this->initializedProduct, $mediaTmpPath . $absolutePath, ['image', 'small_image'], true, false)
->willReturn($imageFileUri);
- $this->mediaGalleryProcessor->expects($this->once())->method('updateImage')
+ $this->processor->expects($this->once())->method('updateImage')
->with(
$this->initializedProduct,
$imageFileUri,
@@ -1386,9 +1411,9 @@ public function testSaveExistingWithMediaGalleryEntries()
->method('getMediaAttributes')
->willReturn(["image" => "filename1", "small_image" => "filename2"]);
- $this->mediaGalleryProcessor->expects($this->once())->method('clearMediaAttribute')
+ $this->processor->expects($this->once())->method('clearMediaAttribute')
->with($this->initializedProduct, ['image', 'small_image']);
- $this->mediaGalleryProcessor->expects($this->once())
+ $this->processor->expects($this->once())
->method('setMediaAttribute')
->with($this->initializedProduct, ['image', 'small_image'], 'filename1');
$this->initializedProduct->expects($this->atLeastOnce())
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
index 5da5625189ee3..0316b2e374d2f 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
@@ -5,33 +5,13 @@
*/
namespace Magento\Catalog\Test\Unit\Model\ResourceModel\Product;
-use Magento\Catalog\Model\Indexer;
-use Magento\Catalog\Model\Product as ProductModel;
-use Magento\Catalog\Model\ResourceModel\Product as ProductResource;
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
use Magento\Framework\DB\Select;
-use Magento\Eav\Model\Entity\AbstractEntity;
-use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
-use Magento\Eav\Model\EntityFactory;
-use Magento\Framework\App\Config\ScopeConfigInterface;
-use Magento\Framework\App\ResourceConnection;
-use Magento\Framework\Data\Collection;
-use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
-use Magento\Framework\DB;
-use Magento\Framework\EntityManager\EntityMetadataInterface;
-use Magento\Framework\EntityManager\MetadataPool;
-use Magento\Framework\Event;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
-use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
-use Magento\Store\Api\Data\StoreInterface;
-use Magento\Store\Model\StoreManagerInterface;
-use PHPUnit\Framework\TestCase;
-use Psr\Log\LoggerInterface;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class CollectionTest extends TestCase
+class CollectionTest extends \PHPUnit\Framework\TestCase
{
/**
* @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
@@ -44,12 +24,12 @@ class CollectionTest extends TestCase
protected $selectMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject|DB\Adapter\AdapterInterface
+ * @var \PHPUnit_Framework_MockObject_MockObject
*/
protected $connectionMock;
/**
- * @var ProductResource\Collection
+ * @var \Magento\Catalog\Model\ResourceModel\Product\Collection
*/
protected $collection;
@@ -90,50 +70,121 @@ protected function setUp()
{
$this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
$this->entityFactory = $this->createMock(\Magento\Framework\Data\Collection\EntityFactory::class);
- $this->selectMock = $this->createMock(DB\Select::class);
- $this->connectionMock = $this->createMock(DB\Adapter\AdapterInterface::class);
- $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock);
- $this->entityMock = $this->createMock(AbstractEntity::class);
+ $logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $fetchStrategy = $this->getMockBuilder(\Magento\Framework\Data\Collection\Db\FetchStrategyInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $eventManager = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $eavConfig = $this->getMockBuilder(\Magento\Eav\Model\Config::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $resource = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $eavEntityFactory = $this->getMockBuilder(\Magento\Eav\Model\EntityFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $resourceHelper = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Helper::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $universalFactory = $this->getMockBuilder(\Magento\Framework\Validator\UniversalFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getStore', 'getId', 'getWebsiteId'])
+ ->getMockForAbstractClass();
+ $moduleManager = $this->getMockBuilder(\Magento\Framework\Module\Manager::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $catalogProductFlatState = $this->getMockBuilder(\Magento\Catalog\Model\Indexer\Product\Flat\State::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $productOptionFactory = $this->getMockBuilder(\Magento\Catalog\Model\Product\OptionFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $catalogUrl = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Url::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $localeDate = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $customerSession = $this->getMockBuilder(\Magento\Customer\Model\Session::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $dateTime = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $groupManagement = $this->getMockBuilder(\Magento\Customer\Api\GroupManagementInterface::class)
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class)
+ ->setMethods(['getId'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $this->selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->entityMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->galleryResourceMock = $this->getMockBuilder(
+ \Magento\Catalog\Model\ResourceModel\Product\Gallery::class
+ )->disableOriginalConstructor()->getMock();
+ $this->metadataPoolMock = $this->getMockBuilder(
+ \Magento\Framework\EntityManager\MetadataPool::class
+ )->disableOriginalConstructor()->getMock();
+ $this->galleryReadHandlerMock = $this->getMockBuilder(
+ \Magento\Catalog\Model\Product\Gallery\ReadHandler::class
+ )->disableOriginalConstructor()->getMock();
+ $this->storeManager->expects($this->any())->method('getId')->willReturn(1);
+ $this->storeManager->expects($this->any())->method('getStore')->willReturnSelf();
+ $universalFactory->expects($this->exactly(1))->method('create')->willReturnOnConsecutiveCalls(
+ $this->entityMock
+ );
$this->entityMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock);
$this->entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn([]);
- $this->entityMock->method('getTable')->willReturnArgument(0);
- $this->galleryResourceMock = $this->createMock(ProductResource\Gallery::class);
- $this->metadataPoolMock = $this->createMock(MetadataPool::class);
- $this->galleryReadHandlerMock = $this->createMock(ProductModel\Gallery\ReadHandler::class);
+ $this->entityMock->expects($this->any())->method('getTable')->willReturnArgument(0);
+ $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock);
- $storeStub = $this->createMock(StoreInterface::class);
- $storeStub->method('getId')->willReturn(1);
- $storeStub->method('getWebsiteId')->willReturn(1);
- $this->storeManager = $this->createMock(StoreManagerInterface::class);
- $this->storeManager->method('getStore')->willReturn($storeStub);
- $resourceModelPool = $this->createMock(ResourceModelPoolInterface::class);
- $resourceModelPool->expects($this->exactly(1))->method('get')->willReturn($this->entityMock);
+ $productLimitationMock = $this->createMock(
+ \Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class
+ );
+ $productLimitationFactoryMock = $this->getMockBuilder(
+ ProductLimitationFactory::class
+ )->disableOriginalConstructor()->setMethods(['create'])->getMock();
- $productLimitationFactoryMock = $this->createPartialMock(ProductLimitationFactory::class, ['create']);
$productLimitationFactoryMock->method('create')
- ->willReturn($this->createMock(ProductResource\Collection\ProductLimitation::class));
+ ->willReturn($productLimitationMock);
$this->collection = $this->objectManager->getObject(
- ProductResource\Collection::class,
+ \Magento\Catalog\Model\ResourceModel\Product\Collection::class,
[
'entityFactory' => $this->entityFactory,
- 'logger' => $this->createMock(LoggerInterface::class),
- 'fetchStrategy' => $this->createMock(FetchStrategyInterface::class),
- 'eventManager' => $this->createMock(Event\ManagerInterface::class),
- 'eavConfig' => $this->createMock(\Magento\Eav\Model\Config::class),
- 'resource' => $this->createMock(ResourceConnection::class),
- 'eavEntityFactory' => $this->createMock(EntityFactory::class),
- 'resourceHelper' => $this->createMock(\Magento\Catalog\Model\ResourceModel\Helper::class),
- 'resourceModelPool' => $resourceModelPool,
+ 'logger' => $logger,
+ 'fetchStrategy' => $fetchStrategy,
+ 'eventManager' => $eventManager,
+ 'eavConfig' => $eavConfig,
+ 'resource' => $resource,
+ 'eavEntityFactory' => $eavEntityFactory,
+ 'resourceHelper' => $resourceHelper,
+ 'universalFactory' => $universalFactory,
'storeManager' => $this->storeManager,
- 'moduleManager' => $this->createMock(\Magento\Framework\Module\Manager::class),
- 'catalogProductFlatState' => $this->createMock(Indexer\Product\Flat\State::class),
- 'scopeConfig' => $this->createMock(ScopeConfigInterface::class),
- 'productOptionFactory' => $this->createMock(ProductModel\OptionFactory::class),
- 'catalogUrl' => $this->createMock(\Magento\Catalog\Model\ResourceModel\Url::class),
- 'localeDate' => $this->createMock(TimezoneInterface::class),
- 'customerSession' => $this->createMock(\Magento\Customer\Model\Session::class),
- 'dateTime' => $this->createMock(\Magento\Framework\Stdlib\DateTime::class),
- 'groupManagement' => $this->createMock(\Magento\Customer\Api\GroupManagementInterface::class),
+ 'moduleManager' => $moduleManager,
+ 'catalogProductFlatState' => $catalogProductFlatState,
+ 'scopeConfig' => $scopeConfig,
+ 'productOptionFactory' => $productOptionFactory,
+ 'catalogUrl' => $catalogUrl,
+ 'localeDate' => $localeDate,
+ 'customerSession' => $customerSession,
+ 'dateTime' => $dateTime,
+ 'groupManagement' => $groupManagement,
'connection' => $this->connectionMock,
'productLimitationFactory' => $productLimitationFactoryMock,
'metadataPool' => $this->metadataPoolMock,
@@ -158,8 +209,9 @@ public function testAddProductCategoriesFilter()
$condition = ['in' => [1, 2]];
$values = [1, 2];
$conditionType = 'nin';
- $preparedSql = 'category_id IN(1,2)';
- $tableName = 'catalog_category_product';
+ $preparedSql = "category_id IN(1,2)";
+ $tableName = "catalog_category_product";
+ $this->connectionMock->expects($this->any())->method('getId')->willReturn(1);
$this->connectionMock->expects($this->exactly(2))->method('prepareSqlCondition')->withConsecutive(
['cat.category_id', $condition],
['e.entity_id', [$conditionType => $this->selectMock]]
@@ -184,14 +236,19 @@ public function testAddMediaGalleryData()
$rowId = 4;
$linkField = 'row_id';
$mediaGalleriesMock = [[$linkField => $rowId]];
- /** @var ProductModel|\PHPUnit_Framework_MockObject_MockObject $itemMock */
- $itemMock = $this->getMockBuilder(ProductModel::class)
+ $itemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
->disableOriginalConstructor()
->setMethods(['getOrigData'])
->getMock();
- $attributeMock = $this->createMock(AbstractAttribute::class);
- $selectMock = $this->createMock(DB\Select::class);
- $metadataMock = $this->createMock(EntityMetadataInterface::class);
+ $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $metadataMock = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->collection->addItem($itemMock);
$this->galleryResourceMock->expects($this->once())->method('createBatchBaseSelect')->willReturn($selectMock);
$attributeMock->expects($this->once())->method('getAttributeId')->willReturn($attributeId);
@@ -221,15 +278,25 @@ public function testAddMediaGalleryData()
public function testAddTierPriceDataByGroupId()
{
$customerGroupId = 2;
- /** @var ProductModel|\PHPUnit_Framework_MockObject_MockObject $itemMock */
- $itemMock = $this->createMock(ProductModel::class);
- $attributeMock = $this->getMockBuilder(AbstractAttribute::class)
+ $itemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getData'])
+ ->getMock();
+ $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
->disableOriginalConstructor()
->setMethods(['isScopeGlobal', 'getBackend'])
->getMock();
- $backend = $this->createMock(ProductModel\Attribute\Backend\Tierprice::class);
- $resource = $this->createMock(ProductResource\Attribute\Backend\GroupPrice\AbstractGroupPrice::class);
- $select = $this->createMock(DB\Select::class);
+ $backend = $this->getMockBuilder(\Magento\Catalog\Model\Product\Attribute\Backend\Tierprice::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $resource = $this->getMockBuilder(
+ \Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice::class
+ )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $select = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->connectionMock->expects($this->once())->method('getAutoIncrementField')->willReturn('entity_id');
$this->collection->addItem($itemMock);
$itemMock->expects($this->atLeastOnce())->method('getData')->with('entity_id')->willReturn(1);
@@ -239,6 +306,7 @@ public function testAddTierPriceDataByGroupId()
->willReturn($attributeMock);
$attributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn($backend);
$attributeMock->expects($this->once())->method('isScopeGlobal')->willReturn(false);
+ $this->storeManager->expects($this->once())->method('getWebsiteId')->willReturn(1);
$backend->expects($this->once())->method('getResource')->willReturn($resource);
$resource->expects($this->once())->method('getSelect')->willReturn($select);
$select->expects($this->once())->method('columns')->with(['product_id' => 'entity_id'])->willReturnSelf();
@@ -265,22 +333,25 @@ public function testAddTierPriceDataByGroupId()
*/
public function testAddTierPriceData()
{
- /** @var ProductModel|\PHPUnit_Framework_MockObject_MockObject $itemMock */
- $itemMock = $this->getMockBuilder(ProductModel::class)
+ $itemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
->disableOriginalConstructor()
->setMethods(['getData'])
->getMock();
- $attributeMock = $this->getMockBuilder(AbstractAttribute::class)
+ $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
->disableOriginalConstructor()
->setMethods(['isScopeGlobal', 'getBackend'])
->getMock();
- $backend = $this->createMock(ProductModel\Attribute\Backend\Tierprice::class);
+ $backend = $this->getMockBuilder(\Magento\Catalog\Model\Product\Attribute\Backend\Tierprice::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$resource = $this->getMockBuilder(
- ProductResource\Attribute\Backend\GroupPrice\AbstractGroupPrice::class
+ \Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice::class
)
->disableOriginalConstructor()
->getMock();
- $select = $this->createMock(DB\Select::class);
+ $select = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$this->connectionMock->expects($this->once())->method('getAutoIncrementField')->willReturn('entity_id');
$this->collection->addItem($itemMock);
$itemMock->expects($this->atLeastOnce())->method('getData')->with('entity_id')->willReturn(1);
@@ -290,6 +361,7 @@ public function testAddTierPriceData()
->willReturn($attributeMock);
$attributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn($backend);
$attributeMock->expects($this->once())->method('isScopeGlobal')->willReturn(false);
+ $this->storeManager->expects($this->once())->method('getWebsiteId')->willReturn(1);
$backend->expects($this->once())->method('getResource')->willReturn($resource);
$resource->expects($this->once())->method('getSelect')->willReturn($select);
$select->expects($this->once())->method('columns')->with(['product_id' => 'entity_id'])->willReturnSelf();
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php
index 80180d2033ce5..596148b627506 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php
@@ -7,8 +7,6 @@
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation;
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
-use Magento\Framework\Data\Collection\Db\FetchStrategyInterface;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -28,7 +26,7 @@ class CollectionTest extends \PHPUnit\Framework\TestCase
/** @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject */
protected $loggerMock;
- /** @var FetchStrategyInterface|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var \Magento\Framework\Data\Collection\Db\FetchStrategyInterface|\PHPUnit_Framework_MockObject_MockObject */
protected $fetchStrategyMock;
/** @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
@@ -46,8 +44,8 @@ class CollectionTest extends \PHPUnit\Framework\TestCase
/** @var \Magento\Catalog\Model\ResourceModel\Helper|\PHPUnit_Framework_MockObject_MockObject */
protected $helperMock;
- /** @var ResourceModelPoolInterface|\PHPUnit_Framework_MockObject_MockObject */
- protected $resourceModelPoolMock;
+ /** @var \Magento\Framework\Validator\UniversalFactory|\PHPUnit_Framework_MockObject_MockObject */
+ protected $universalFactoryMock;
/** @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
protected $storeManagerMock;
@@ -81,23 +79,29 @@ protected function setUp()
$this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
$this->entityFactoryMock = $this->createMock(\Magento\Framework\Data\Collection\EntityFactory::class);
$this->loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class);
- $this->fetchStrategyMock = $this->createMock(FetchStrategyInterface::class);
+ $this->fetchStrategyMock = $this->createMock(
+ \Magento\Framework\Data\Collection\Db\FetchStrategyInterface::class
+ );
$this->managerInterfaceMock = $this->createMock(\Magento\Framework\Event\ManagerInterface::class);
$this->configMock = $this->createMock(\Magento\Eav\Model\Config::class);
$this->resourceMock = $this->createMock(\Magento\Framework\App\ResourceConnection::class);
$this->entityFactoryMock2 = $this->createMock(\Magento\Eav\Model\EntityFactory::class);
$this->helperMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Helper::class);
$entity = $this->createMock(\Magento\Eav\Model\Entity\AbstractEntity::class);
- $select = $this->createMock(\Magento\Framework\DB\Select::class);
- $connection = $this->createMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class);
+ $select = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\Pdo\Mysql::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$connection->expects($this->any())
->method('select')
->willReturn($select);
$entity->expects($this->any())->method('getConnection')->will($this->returnValue($connection));
$entity->expects($this->any())->method('getDefaultAttributes')->will($this->returnValue([]));
- $this->resourceModelPoolMock = $this->createMock(ResourceModelPoolInterface::class);
- $this->resourceModelPoolMock->expects($this->any())->method('get')->will($this->returnValue($entity));
- $this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class);
+ $this->universalFactoryMock = $this->createMock(\Magento\Framework\Validator\UniversalFactory::class);
+ $this->universalFactoryMock->expects($this->any())->method('create')->will($this->returnValue($entity));
+ $this->storeManagerMock = $this->getMockForAbstractClass(\Magento\Store\Model\StoreManagerInterface::class);
$this->storeManagerMock
->expects($this->any())
->method('getStore')
@@ -114,7 +118,9 @@ function ($store) {
$this->timezoneInterfaceMock = $this->createMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class);
$this->sessionMock = $this->createMock(\Magento\Customer\Model\Session::class);
$this->dateTimeMock = $this->createMock(\Magento\Framework\Stdlib\DateTime::class);
- $productLimitationFactoryMock = $this->createPartialMock(ProductLimitationFactory::class, ['create']);
+ $productLimitationFactoryMock = $this->getMockBuilder(
+ ProductLimitationFactory::class
+ )->disableOriginalConstructor()->setMethods(['create'])->getMock();
$productLimitationFactoryMock->method('create')
->willReturn($this->createMock(ProductLimitation::class));
@@ -130,7 +136,7 @@ function ($store) {
'resource' => $this->resourceMock,
'eavEntityFactory' => $this->entityFactoryMock2,
'resourceHelper' => $this->helperMock,
- 'resourceModelPool' => $this->resourceModelPoolMock,
+ 'universalFactory' => $this->universalFactoryMock,
'storeManager' => $this->storeManagerMock,
'catalogData' => $this->catalogHelperMock,
'catalogProductFlatState' => $this->stateMock,
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
index cd6565f32ed18..a2d81854607a0 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
@@ -154,38 +154,4 @@ public function modifyMetaLockedDataProvider()
{
return [[true], [false]];
}
-
- public function testModifyMetaWithCaching()
- {
- $this->arrayManagerMock->expects($this->exactly(2))
- ->method('findPath')
- ->willReturn(true);
- $cacheManager = $this->getMockBuilder(CacheInterface::class)
- ->getMockForAbstractClass();
- $cacheManager->expects($this->once())
- ->method('load')
- ->with(Categories::CATEGORY_TREE_ID . '_');
- $cacheManager->expects($this->once())
- ->method('save');
-
- $modifier = $this->createModel();
- $cacheContextProperty = new \ReflectionProperty(
- Categories::class,
- 'cacheManager'
- );
- $cacheContextProperty->setAccessible(true);
- $cacheContextProperty->setValue($modifier, $cacheManager);
-
- $groupCode = 'test_group_code';
- $meta = [
- $groupCode => [
- 'children' => [
- 'category_ids' => [
- 'sortOrder' => 10,
- ],
- ],
- ],
- ];
- $modifier->modifyMeta($meta);
- }
}
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
index 681435851fbde..800ead0e4030c 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Ui\DataProvider\Product\Form\Modifier;
use Magento\Catalog\Model\Locator\LocatorInterface;
@@ -11,6 +13,7 @@
use Magento\Framework\App\CacheInterface;
use Magento\Framework\DB\Helper as DbHelper;
use Magento\Catalog\Model\Category as CategoryModel;
+use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\UrlInterface;
use Magento\Framework\Stdlib\ArrayManager;
@@ -202,6 +205,7 @@ protected function createNewCategoryModal(array $meta)
*
* @param array $meta
* @return array
+ * @throws LocalizedException
* @since 101.0.0
*/
protected function customizeCategoriesField(array $meta)
@@ -306,20 +310,64 @@ protected function customizeCategoriesField(array $meta)
*
* @param string|null $filter
* @return array
+ * @throws LocalizedException
* @since 101.0.0
*/
protected function getCategoriesTree($filter = null)
{
- $categoryTree = $this->getCacheManager()->load(self::CATEGORY_TREE_ID . '_' . $filter);
- if ($categoryTree) {
- return $this->serializer->unserialize($categoryTree);
+ $storeId = (int) $this->locator->getStore()->getId();
+
+ $cachedCategoriesTree = $this->getCacheManager()
+ ->load($this->getCategoriesTreeCacheId($storeId, (string) $filter));
+ if (!empty($cachedCategoriesTree)) {
+ return $this->serializer->unserialize($cachedCategoriesTree);
}
- $storeId = $this->locator->getStore()->getId();
+ $categoriesTree = $this->retrieveCategoriesTree(
+ $storeId,
+ $this->retrieveShownCategoriesIds($storeId, (string) $filter)
+ );
+
+ $this->getCacheManager()->save(
+ $this->serializer->serialize($categoriesTree),
+ $this->getCategoriesTreeCacheId($storeId, (string) $filter),
+ [
+ \Magento\Catalog\Model\Category::CACHE_TAG,
+ \Magento\Framework\App\Cache\Type\Block::CACHE_TAG
+ ]
+ );
+
+ return $categoriesTree;
+ }
+
+ /**
+ * Get cache id for categories tree.
+ *
+ * @param int $storeId
+ * @param string $filter
+ * @return string
+ */
+ private function getCategoriesTreeCacheId(int $storeId, string $filter = '') : string
+ {
+ return self::CATEGORY_TREE_ID
+ . '_' . (string) $storeId
+ . '_' . $filter;
+ }
+
+ /**
+ * Retrieve filtered list of categories id.
+ *
+ * @param int $storeId
+ * @param string $filter
+ * @return array
+ * @throws LocalizedException
+ */
+ private function retrieveShownCategoriesIds(int $storeId, string $filter = '') : array
+ {
/* @var $matchingNamesCollection \Magento\Catalog\Model\ResourceModel\Category\Collection */
$matchingNamesCollection = $this->categoryCollectionFactory->create();
- if ($filter !== null) {
+ if (!empty($filter)) {
$matchingNamesCollection->addAttributeToFilter(
'name',
['like' => $this->dbHelper->addLikeEscape($filter, ['position' => 'any'])]
@@ -339,6 +387,19 @@ protected function getCategoriesTree($filter = null)
}
}
+ return $shownCategoriesIds;
+ }
+
+ /**
+ * Retrieve tree of categories with attributes.
+ *
+ * @param int $storeId
+ * @param array $shownCategoriesIds
+ * @return array|null
+ * @throws LocalizedException
+ */
+ private function retrieveCategoriesTree(int $storeId, array $shownCategoriesIds) : ?array
+ {
/* @var $collection \Magento\Catalog\Model\ResourceModel\Category\Collection */
$collection = $this->categoryCollectionFactory->create();
@@ -365,15 +426,6 @@ protected function getCategoriesTree($filter = null)
$categoryById[$category->getParentId()]['optgroup'][] = &$categoryById[$category->getId()];
}
- $this->getCacheManager()->save(
- $this->serializer->serialize($categoryById[CategoryModel::TREE_ROOT_ID]['optgroup']),
- self::CATEGORY_TREE_ID . '_' . $filter,
- [
- \Magento\Catalog\Model\Category::CACHE_TAG,
- \Magento\Framework\App\Cache\Type\Block::CACHE_TAG
- ]
- );
-
return $categoryById[CategoryModel::TREE_ROOT_ID]['optgroup'];
}
}
diff --git a/app/code/Magento/Catalog/ViewModel/Product/Checker/AddToCompareAvailability.php b/app/code/Magento/Catalog/ViewModel/Product/Checker/AddToCompareAvailability.php
new file mode 100644
index 0000000000000..27829155af292
--- /dev/null
+++ b/app/code/Magento/Catalog/ViewModel/Product/Checker/AddToCompareAvailability.php
@@ -0,0 +1,58 @@
+stockConfiguration = $stockConfiguration;
+ }
+
+ /**
+ * Is product available for comparison.
+ *
+ * @param ProductInterface $product
+ * @return bool
+ */
+ public function isAvailableForCompare(ProductInterface $product): bool
+ {
+ return $this->isInStock($product) || $this->stockConfiguration->isShowOutOfStock();
+ }
+
+ /**
+ * Get is in stock status.
+ *
+ * @param ProductInterface $product
+ * @return bool
+ */
+ private function isInStock(ProductInterface $product): bool
+ {
+ $quantityAndStockStatus = $product->getQuantityAndStockStatus();
+ if (!$quantityAndStockStatus) {
+ return $product->isSalable();
+ }
+
+ return isset($quantityAndStockStatus['is_in_stock']) && $quantityAndStockStatus['is_in_stock'];
+ }
+}
diff --git a/app/code/Magento/Catalog/etc/frontend/di.xml b/app/code/Magento/Catalog/etc/frontend/di.xml
index 793a2291f599c..ee9c5b29da894 100644
--- a/app/code/Magento/Catalog/etc/frontend/di.xml
+++ b/app/code/Magento/Catalog/etc/frontend/di.xml
@@ -120,5 +120,4 @@
-
diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml
index 44884897461a8..4e7396608826b 100644
--- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml
+++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml
@@ -11,7 +11,7 @@
setGrid
- Magento\Eav\Model\ResourceModel\Entity\Attribute\Grid\Collection
+ Magento\Eav\Model\ResourceModel\Entity\Attribute\Grid\Collection
set_name
ASC
1
diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
index 41a2a6142d506..13e2d998f6cdd 100644
--- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
+++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
@@ -91,7 +91,11 @@
+ template="Magento_Catalog::product/view/addto/compare.phtml" >
+
+ Magento\Catalog\ViewModel\Product\Checker\AddToCompareAvailability
+
+
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml
index f434402346087..ecc9700802d27 100644
--- a/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml
+++ b/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml
@@ -169,7 +169,7 @@ switch ($type = $block->getType()) {
= /* @escapeNotVerified */ __('Check items to add to the cart or') ?>
-
+
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml
index adf0f44d0c831..194a472d81d58 100644
--- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml
+++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml
@@ -9,6 +9,10 @@
/** @var $block \Magento\Catalog\Block\Product\View\Addto\Compare */
?>
+getData('addToCompareViewModel'); ?>
+isAvailableForCompare($block->getProduct())): ?>
= /* @escapeNotVerified */ __('Add to Compare') ?>
+
+
diff --git a/app/code/Magento/Catalog/view/frontend/web/js/related-products.js b/app/code/Magento/Catalog/view/frontend/web/js/related-products.js
index 0c37f9ff4f007..66df48c28bfab 100644
--- a/app/code/Magento/Catalog/view/frontend/web/js/related-products.js
+++ b/app/code/Magento/Catalog/view/frontend/web/js/related-products.js
@@ -17,7 +17,7 @@ define([
relatedProductsField: '#related-products-field', // Hidden input field that stores related products.
selectAllMessage: $.mage.__('select all'),
unselectAllMessage: $.mage.__('unselect all'),
- selectAllLink: '[role="select-all"]',
+ selectAllLink: '[role="button"]',
elementsSelector: '.item.product'
},
diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoriesIdentity.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoriesIdentity.php
new file mode 100644
index 0000000000000..aba2d7b198dbd
--- /dev/null
+++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoriesIdentity.php
@@ -0,0 +1,33 @@
+_resourceHelper->getNextAutoincrement($mainTable);
// pre-load 'position' attributes ID for each link type once
- foreach ($this->_linkNameToId as $linkName => $linkId) {
+ foreach ($this->_linkNameToId as $linkId) {
$select = $this->_connection->select()->from(
$resource->getTable('catalog_product_link_attribute'),
['id' => 'product_link_attribute_id']
@@ -1374,6 +1375,7 @@ protected function _saveLinks()
}
return $this;
}
+ // phpcs:enable
/**
* Save product attributes.
@@ -1608,6 +1610,7 @@ public function getImagesFromRow(array $rowData)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
* @throws LocalizedException
+ * phpcs:disable Generic.Metrics.NestingLevel
*/
protected function _saveProducts()
{
@@ -1798,7 +1801,13 @@ protected function _saveProducts()
$uploadedImages[$columnImage] = $uploadedFile;
} else {
unset($rowData[$column]);
- $this->skipRow($rowNum, ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE);
+ $this->addRowError(
+ ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE,
+ $rowNum,
+ null,
+ null,
+ ProcessingError::ERROR_LEVEL_NOT_CRITICAL
+ );
}
} else {
$uploadedFile = $uploadedImages[$columnImage];
@@ -1974,6 +1983,7 @@ protected function _saveProducts()
return $this;
}
+ // phpcs:enable
/**
* Prepare array with image states (visible or hidden from product page)
diff --git a/app/code/Magento/CatalogInventory/Test/Mftf/ActionGroup/DisplayOutOfStockProductActionGroup.xml b/app/code/Magento/CatalogInventory/Test/Mftf/ActionGroup/DisplayOutOfStockProductActionGroup.xml
index c7c9126f46803..2850b8d069201 100644
--- a/app/code/Magento/CatalogInventory/Test/Mftf/ActionGroup/DisplayOutOfStockProductActionGroup.xml
+++ b/app/code/Magento/CatalogInventory/Test/Mftf/ActionGroup/DisplayOutOfStockProductActionGroup.xml
@@ -21,6 +21,7 @@
+
diff --git a/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/AdminOpenNewCatalogPriceRuleFormPageActionGroup.xml b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/AdminOpenNewCatalogPriceRuleFormPageActionGroup.xml
new file mode 100644
index 0000000000000..072e8b24b0336
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/AdminOpenNewCatalogPriceRuleFormPageActionGroup.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/AssertCustomerGroupNotOnCatalogPriceRuleFormActionGroup.xml b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/AssertCustomerGroupNotOnCatalogPriceRuleFormActionGroup.xml
new file mode 100644
index 0000000000000..93a2a8a610951
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Mftf/ActionGroup/AssertCustomerGroupNotOnCatalogPriceRuleFormActionGroup.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+ customerGroups
+ {{customerGroup.code}}
+
+
+
diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/CatalogRule/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..eb9cac1401c36
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Marketing
+ Marketing
+ magento-backend-marketing
+
+
+ Catalog Price Rule
+ Catalog Price Rule
+ magento-catalogrule-promo-catalog
+
+
diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Page/CatalogRuleNewPage.xml b/app/code/Magento/CatalogRule/Test/Mftf/Page/CatalogRuleNewPage.xml
new file mode 100644
index 0000000000000..ad3e40b37c5b0
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Mftf/Page/CatalogRuleNewPage.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminMarketingCatalogPriceRuleNavigateMenuTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminMarketingCatalogPriceRuleNavigateMenuTest.xml
new file mode 100644
index 0000000000000..0fe35419aaf3e
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminMarketingCatalogPriceRuleNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/DeleteCustomerGroupTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/DeleteCustomerGroupTest.xml
new file mode 100644
index 0000000000000..75223fcfc4c4b
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/DeleteCustomerGroupTest.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogRule/etc/mview.xml b/app/code/Magento/CatalogRule/etc/mview.xml
index 35efe33461afc..9e5a1c866a842 100644
--- a/app/code/Magento/CatalogRule/etc/mview.xml
+++ b/app/code/Magento/CatalogRule/etc/mview.xml
@@ -16,7 +16,6 @@
-
diff --git a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml
index 99d64ed7a635f..f38f6e0fcd850 100644
--- a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml
+++ b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml
@@ -11,7 +11,7 @@
promo_catalog_grid
- Magento\CatalogRule\Model\ResourceModel\Grid\Collection
+ Magento\CatalogRule\Model\ResourceModel\Grid\Collection
name
ASC
1
diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
index 2ffa63098cdee..c758e773f43c1 100644
--- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Filter/Preprocessor.php
@@ -8,7 +8,9 @@
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
+use Magento\CatalogSearch\Model\Search\FilterMapper\VisibilityFilter;
use Magento\CatalogSearch\Model\Search\TableMapper;
+use Magento\Customer\Model\Session;
use Magento\Eav\Model\Config;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ObjectManager;
@@ -20,10 +22,11 @@
use Magento\Framework\Search\Adapter\Mysql\Filter\PreprocessorInterface;
use Magento\Framework\Search\Request\FilterInterface;
use Magento\Store\Model\Store;
-use Magento\Customer\Model\Session;
-use Magento\CatalogSearch\Model\Search\FilterMapper\VisibilityFilter;
/**
+ * ElasticSearch search filter pre-processor.
+ *
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @deprecated
* @see \Magento\ElasticSearch
@@ -128,7 +131,7 @@ public function __construct(
}
/**
- * {@inheritdoc}
+ * @inheritdoc
*/
public function process(FilterInterface $filter, $isNegation, $query)
{
@@ -136,10 +139,13 @@ public function process(FilterInterface $filter, $isNegation, $query)
}
/**
+ * Process query with field.
+ *
* @param FilterInterface $filter
* @param bool $isNegation
* @param string $query
* @return string
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
private function processQueryWithField(FilterInterface $filter, $isNegation, $query)
{
@@ -170,7 +176,7 @@ private function processQueryWithField(FilterInterface $filter, $isNegation, $qu
} elseif ($filter->getField() === VisibilityFilter::VISIBILITY_FILTER_FIELD) {
return '';
} elseif ($filter->getType() === FilterInterface::TYPE_TERM &&
- in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true)
+ in_array($attribute->getFrontendInput(), ['select', 'multiselect', 'boolean'], true)
) {
$resultQuery = $this->processTermSelect($filter, $isNegation);
} elseif ($filter->getType() === FilterInterface::TYPE_RANGE &&
@@ -204,19 +210,23 @@ private function processQueryWithField(FilterInterface $filter, $isNegation, $qu
->where('main_table.store_id = ?', Store::DEFAULT_STORE_ID)
->having($query);
- $resultQuery = 'search_index.entity_id IN (
- select entity_id from ' . $this->conditionManager->wrapBrackets($select) . ' as filter
- )';
+ $resultQuery = 'search_index.entity_id IN ('
+ . 'select entity_id from '
+ . $this->conditionManager->wrapBrackets($select)
+ . ' as filter)';
}
return $resultQuery;
}
/**
+ * Process range numeric.
+ *
* @param FilterInterface $filter
* @param string $query
* @param Attribute $attribute
* @return string
+ * @throws \Exception
*/
private function processRangeNumeric(FilterInterface $filter, $query, $attribute)
{
@@ -238,14 +248,17 @@ private function processRangeNumeric(FilterInterface $filter, $query, $attribute
->where('main_table.store_id = ?', $currentStoreId)
->having($query);
- $resultQuery = 'search_index.entity_id IN (
- select entity_id from ' . $this->conditionManager->wrapBrackets($select) . ' as filter
- )';
+ $resultQuery = 'search_index.entity_id IN ('
+ . 'select entity_id from '
+ . $this->conditionManager->wrapBrackets($select)
+ . ' as filter)';
return $resultQuery;
}
/**
+ * Process term select.
+ *
* @param FilterInterface $filter
* @param bool $isNegation
* @return string
diff --git a/app/code/Magento/CatalogSearch/Model/Layer/Filter/Decimal.php b/app/code/Magento/CatalogSearch/Model/Layer/Filter/Decimal.php
index e61a886a41d6f..e9fb1070fedd5 100644
--- a/app/code/Magento/CatalogSearch/Model/Layer/Filter/Decimal.php
+++ b/app/code/Magento/CatalogSearch/Model/Layer/Filter/Decimal.php
@@ -111,12 +111,9 @@ protected function _getItemsData()
$from = '';
}
if ($to == '*') {
- $to = '';
+ $to = null;
}
- $label = $this->renderRangeLabel(
- empty($from) ? 0 : $from,
- empty($to) ? 0 : $to
- );
+ $label = $this->renderRangeLabel(empty($from) ? 0 : $from, $to);
$value = $from . '-' . $to;
$data[] = [
@@ -141,7 +138,7 @@ protected function _getItemsData()
protected function renderRangeLabel($fromPrice, $toPrice)
{
$formattedFromPrice = $this->priceCurrency->format($fromPrice);
- if ($toPrice === '') {
+ if ($toPrice === null) {
return __('%1 and above', $formattedFromPrice);
} else {
if ($fromPrice != $toPrice) {
diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php
index e3f61af771f8c..7791dc761ae39 100644
--- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php
+++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Advanced/Collection.php
@@ -6,8 +6,6 @@
namespace Magento\CatalogSearch\Model\ResourceModel\Advanced;
-use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
-use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver;
use Magento\Catalog\Model\Product;
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverInterface;
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplierInterface;
@@ -21,8 +19,6 @@
use Magento\Framework\Api\Search\SearchResultFactory;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\LocalizedException;
-use Magento\Framework\Indexer\DimensionFactory;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
use Magento\Framework\Search\Request\EmptyRequestDataException;
use Magento\Framework\Search\Request\NonExistingRequestNameException;
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
@@ -139,10 +135,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
* @param SearchResultFactory|null $searchResultFactory
* @param ProductLimitationFactory|null $productLimitationFactory
* @param MetadataPool|null $metadataPool
- * @param TableMaintainer|null $tableMaintainer
- * @param PriceTableResolver|null $priceTableResolver
- * @param DimensionFactory|null $dimensionFactory
- * @param ResourceModelPoolInterface|null $resourceModelPool
* @param string $searchRequestName
* @param SearchCriteriaResolverFactory|null $searchCriteriaResolverFactory
* @param SearchResultApplierFactory|null $searchResultApplierFactory
@@ -177,10 +169,6 @@ public function __construct(
SearchResultFactory $searchResultFactory = null,
ProductLimitationFactory $productLimitationFactory = null,
MetadataPool $metadataPool = null,
- TableMaintainer $tableMaintainer = null,
- PriceTableResolver $priceTableResolver = null,
- DimensionFactory $dimensionFactory = null,
- ResourceModelPoolInterface $resourceModelPool = null,
$searchRequestName = 'advanced_search_container',
SearchCriteriaResolverFactory $searchCriteriaResolverFactory = null,
SearchResultApplierFactory $searchResultApplierFactory = null,
@@ -225,11 +213,7 @@ public function __construct(
$groupManagement,
$connection,
$productLimitationFactory,
- $metadataPool,
- $tableMaintainer,
- $priceTableResolver,
- $dimensionFactory,
- $resourceModelPool
+ $metadataPool
);
}
diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php
index 2c36b150fed07..59f6cd1c6e7eb 100644
--- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php
+++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Fulltext/Collection.php
@@ -6,8 +6,6 @@
namespace Magento\CatalogSearch\Model\ResourceModel\Fulltext;
-use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
-use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver;
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolverInterface;
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\TotalRecordsResolverFactory;
use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection\SearchCriteriaResolverInterface;
@@ -21,8 +19,6 @@
use Magento\CatalogSearch\Model\Search\RequestGenerator;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\StateException;
-use Magento\Framework\Indexer\DimensionFactory;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
use Magento\Framework\Search\Response\QueryResponse;
use Magento\Framework\Search\Request\EmptyRequestDataException;
use Magento\Framework\Search\Request\NonExistingRequestNameException;
@@ -41,6 +37,7 @@
* @since 100.0.2
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyFields)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
{
@@ -167,10 +164,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
* @param SearchResultFactory|null $searchResultFactory
* @param ProductLimitationFactory|null $productLimitationFactory
* @param MetadataPool|null $metadataPool
- * @param TableMaintainer|null $tableMaintainer
- * @param PriceTableResolver|null $priceTableResolver
- * @param DimensionFactory|null $dimensionFactory
- * @param ResourceModelPoolInterface|null $resourceModelPool
* @param \Magento\Search\Api\SearchInterface|null $search
* @param \Magento\Framework\Api\Search\SearchCriteriaBuilder|null $searchCriteriaBuilder
* @param \Magento\Framework\Api\FilterBuilder|null $filterBuilder
@@ -210,10 +203,6 @@ public function __construct(
SearchResultFactory $searchResultFactory = null,
ProductLimitationFactory $productLimitationFactory = null,
MetadataPool $metadataPool = null,
- TableMaintainer $tableMaintainer = null,
- PriceTableResolver $priceTableResolver = null,
- DimensionFactory $dimensionFactory = null,
- ResourceModelPoolInterface $resourceModelPool = null,
\Magento\Search\Api\SearchInterface $search = null,
\Magento\Framework\Api\Search\SearchCriteriaBuilder $searchCriteriaBuilder = null,
\Magento\Framework\Api\FilterBuilder $filterBuilder = null,
@@ -249,11 +238,7 @@ public function __construct(
$groupManagement,
$connection,
$productLimitationFactory,
- $metadataPool,
- $tableMaintainer,
- $priceTableResolver,
- $dimensionFactory,
- $resourceModelPool
+ $metadataPool
);
$this->requestBuilder = $requestBuilder;
$this->searchEngine = $searchEngine;
diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Search/Collection.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Search/Collection.php
index fd948616c005b..e625ccbe51fe3 100644
--- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Search/Collection.php
+++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Search/Collection.php
@@ -6,17 +6,11 @@
namespace Magento\CatalogSearch\Model\ResourceModel\Search;
-use Magento\Catalog\Model\Indexer\Category\Product\TableMaintainer;
-use Magento\Catalog\Model\Indexer\Product\Price\PriceTableResolver;
-use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory;
-use Magento\Framework\EntityManager\MetadataPool;
-use Magento\Framework\Indexer\DimensionFactory;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
-
/**
* Search collection
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
* @api
* @since 100.0.2
*/
@@ -67,12 +61,6 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
* @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
* @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
- * @param ProductLimitationFactory|null $productLimitationFactory
- * @param MetadataPool|null $metadataPool
- * @param TableMaintainer|null $tableMaintainer
- * @param PriceTableResolver|null $priceTableResolver
- * @param DimensionFactory|null $dimensionFactory
- * @param ResourceModelPoolInterface|null $resourceModelPool
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -96,13 +84,7 @@ public function __construct(
\Magento\Framework\Stdlib\DateTime $dateTime,
\Magento\Customer\Api\GroupManagementInterface $groupManagement,
\Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $attributeCollectionFactory,
- \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
- ProductLimitationFactory $productLimitationFactory = null,
- MetadataPool $metadataPool = null,
- TableMaintainer $tableMaintainer = null,
- PriceTableResolver $priceTableResolver = null,
- DimensionFactory $dimensionFactory = null,
- ResourceModelPoolInterface $resourceModelPool = null
+ \Magento\Framework\DB\Adapter\AdapterInterface $connection = null
) {
$this->_attributeCollectionFactory = $attributeCollectionFactory;
parent::__construct(
@@ -125,13 +107,7 @@ public function __construct(
$customerSession,
$dateTime,
$groupManagement,
- $connection,
- $productLimitationFactory,
- $metadataPool,
- $tableMaintainer,
- $priceTableResolver,
- $dimensionFactory,
- $resourceModelPool
+ $connection
);
}
@@ -293,6 +269,7 @@ protected function _getSearchEntityIdsSql($query, $searchOnlyInCurrentStore = tr
$sql = $this->_getSearchInOptionSql($query);
if ($sql) {
+ // phpcs:ignore Magento2.SQL.RawQuery
$selects[] = "SELECT * FROM ({$sql}) AS inoptionsql"; // inherent unions may be inside
}
diff --git a/app/code/Magento/CatalogSearch/Model/Search/CustomAttributeFilterCheck.php b/app/code/Magento/CatalogSearch/Model/Search/CustomAttributeFilterCheck.php
index bcd4080b30b14..657c8540d7c68 100644
--- a/app/code/Magento/CatalogSearch/Model/Search/CustomAttributeFilterCheck.php
+++ b/app/code/Magento/CatalogSearch/Model/Search/CustomAttributeFilterCheck.php
@@ -44,7 +44,7 @@ public function isCustom(FilterInterface $filter)
return $attribute
&& $filter->getType() === FilterInterface::TYPE_TERM
- && in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true);
+ && in_array($attribute->getFrontendInput(), ['select', 'multiselect', 'boolean'], true);
}
/**
diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml b/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml
index 4b52b2c669edf..067d76821d687 100644
--- a/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml
+++ b/app/code/Magento/CatalogSearch/Test/Mftf/ActionGroup/StorefrontCatalogSearchActionGroup.xml
@@ -20,6 +20,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..df1c3db6e5661
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Search Terms
+ Search Terms
+ magento-search-search-terms
+
+
+ Search Terms Report
+ Search Terms
+ magento-search-report-search-term
+
+
diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/AdminMarketingSearchTermsNavigateMenuTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/AdminMarketingSearchTermsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..bc255020d98b3
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/AdminMarketingSearchTermsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/AdminReportsSearchTermsNavigateMenuTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/AdminReportsSearchTermsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..85cf0e3ba90ed
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/AdminReportsSearchTermsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest.xml b/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest.xml
new file mode 100644
index 0000000000000..19db201e91f40
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Mftf/Test/SearchEntityResultsTest.xml
@@ -0,0 +1,629 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $attributeSet.attribute_set_id$
+
+
+
+
+
+
+
+ $attributeSet.attribute_set_id$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php
index fe29fa1ece011..683070c286239 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Advanced/CollectionTest.php
@@ -67,7 +67,7 @@ protected function setUp()
$this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
$this->eavConfig = $this->createMock(\Magento\Eav\Model\Config::class);
$storeManager = $this->getStoreManager();
- $resourceModelPool = $this->getResourceModelPool();
+ $universalFactory = $this->getUniversalFactory();
$this->criteriaBuilder = $this->getCriteriaBuilder();
$this->filterBuilder = $this->createMock(\Magento\Framework\Api\FilterBuilder::class);
$this->temporaryStorageFactory = $this->createMock(
@@ -126,7 +126,7 @@ protected function setUp()
[
'eavConfig' => $this->eavConfig,
'storeManager' => $storeManager,
- 'resourceModelPool' => $resourceModelPool,
+ 'universalFactory' => $universalFactory,
'searchCriteriaBuilder' => $this->criteriaBuilder,
'filterBuilder' => $this->filterBuilder,
'temporaryStorageFactory' => $this->temporaryStorageFactory,
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/BaseCollection.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/BaseCollection.php
index 5a5106593af8b..9ea103e23d2a7 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/BaseCollection.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/BaseCollection.php
@@ -5,8 +5,6 @@
*/
namespace Magento\CatalogSearch\Test\Unit\Model\ResourceModel;
-use Magento\Framework\Model\ResourceModel\ResourceModelPoolInterface;
-
/**
* Base class for Collection tests.
*
@@ -44,17 +42,19 @@ protected function getStoreManager()
}
/**
- * Get mock for ResourceModelPool so Collection can be used.
+ * Get mock for UniversalFactory so Collection can be used.
*
- * @return \PHPUnit_Framework_MockObject_MockObject|ResourceModelPoolInterface
+ * @return \PHPUnit_Framework_MockObject_MockObject
*/
- protected function getResourceModelPool()
+ protected function getUniversalFactory()
{
$connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\Pdo\Mysql::class)
->disableOriginalConstructor()
->setMethods(['select'])
->getMockForAbstractClass();
- $select = $this->createMock(\Magento\Framework\DB\Select::class);
+ $select = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$connection->expects($this->any())->method('select')->willReturn($select);
$entity = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class)
@@ -74,14 +74,14 @@ protected function getResourceModelPool()
->method('getEntityTable')
->willReturn('table');
- $resourceModelPool = $this->getMockBuilder(ResourceModelPoolInterface::class)
- ->setMethods(['get'])
+ $universalFactory = $this->getMockBuilder(\Magento\Framework\Validator\UniversalFactory::class)
+ ->setMethods(['create'])
->disableOriginalConstructor()
->getMock();
- $resourceModelPool->expects($this->once())
- ->method('get')
+ $universalFactory->expects($this->once())
+ ->method('create')
->willReturn($entity);
- return $resourceModelPool;
+ return $universalFactory;
}
}
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php
index f1c2161a052e0..9170b81dc3182 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/ResourceModel/Fulltext/CollectionTest.php
@@ -49,7 +49,7 @@ class CollectionTest extends BaseCollection
/**
* @var MockObject
*/
- private $resourceModelPool;
+ private $universalFactory;
/**
* @var MockObject
@@ -78,7 +78,7 @@ protected function setUp()
{
$this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
$this->storeManager = $this->getStoreManager();
- $this->resourceModelPool = $this->getResourceModelPool();
+ $this->universalFactory = $this->getUniversalFactory();
$this->scopeConfig = $this->getScopeConfig();
$this->criteriaBuilder = $this->getCriteriaBuilder();
$this->filterBuilder = $this->getFilterBuilder();
@@ -143,7 +143,7 @@ protected function setUp()
\Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection::class,
[
'storeManager' => $this->storeManager,
- 'resourceModelPool' => $this->resourceModelPool,
+ 'universalFactory' => $this->universalFactory,
'scopeConfig' => $this->scopeConfig,
'temporaryStorageFactory' => $temporaryStorageFactory,
'productLimitationFactory' => $productLimitationFactoryMock,
diff --git a/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php b/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php
index 3f6f638db5b82..557f143352446 100644
--- a/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php
+++ b/app/code/Magento/Checkout/Block/Checkout/LayoutProcessor.php
@@ -122,6 +122,7 @@ private function convertElementsToSelect($elements, $attributesToConvert)
if (!in_array($code, $codes)) {
continue;
}
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
$options = call_user_func($attributesToConvert[$code]);
if (!is_array($options)) {
continue;
@@ -287,8 +288,14 @@ private function getBillingAddressComponent($paymentCode, $elements)
'provider' => 'checkoutProvider',
'deps' => 'checkoutProvider',
'dataScopePrefix' => 'billingAddress' . $paymentCode,
+ 'billingAddressListProvider' => '${$.name}.billingAddressList',
'sortOrder' => 1,
'children' => [
+ 'billingAddressList' => [
+ 'component' => 'Magento_Checkout/js/view/billing-address/list',
+ 'displayArea' => 'billing-address-list',
+ 'template' => 'Magento_Checkout/billing-address/list'
+ ],
'form-fields' => [
'component' => 'uiComponent',
'displayArea' => 'additional-fieldsets',
diff --git a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php
index f30bd73deeae2..470d4a3aca561 100644
--- a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php
+++ b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php
@@ -10,6 +10,7 @@
use Magento\Checkout\Model\Session as CheckoutSession;
use Magento\Customer\Api\AddressMetadataInterface;
use Magento\Customer\Api\CustomerRepositoryInterface as CustomerRepository;
+use Magento\Customer\Model\Address\CustomerAddressDataProvider;
use Magento\Customer\Model\Context as CustomerContext;
use Magento\Customer\Model\Session as CustomerSession;
use Magento\Customer\Model\Url as CustomerUrlManager;
@@ -34,6 +35,7 @@
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyFields)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class DefaultConfigProvider implements ConfigProviderInterface
{
@@ -177,6 +179,11 @@ class DefaultConfigProvider implements ConfigProviderInterface
*/
private $addressMetadata;
+ /**
+ * @var CustomerAddressDataProvider
+ */
+ private $customerAddressData;
+
/**
* @param CheckoutHelper $checkoutHelper
* @param Session $checkoutSession
@@ -206,6 +213,7 @@ class DefaultConfigProvider implements ConfigProviderInterface
* @param UrlInterface $urlBuilder
* @param AddressMetadataInterface $addressMetadata
* @param AttributeOptionManagementInterface $attributeOptionManager
+ * @param CustomerAddressDataProvider|null $customerAddressData
* @codeCoverageIgnore
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
@@ -237,7 +245,8 @@ public function __construct(
\Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement,
UrlInterface $urlBuilder,
AddressMetadataInterface $addressMetadata = null,
- AttributeOptionManagementInterface $attributeOptionManager = null
+ AttributeOptionManagementInterface $attributeOptionManager = null,
+ CustomerAddressDataProvider $customerAddressData = null
) {
$this->checkoutHelper = $checkoutHelper;
$this->checkoutSession = $checkoutSession;
@@ -268,6 +277,8 @@ public function __construct(
$this->addressMetadata = $addressMetadata ?: ObjectManager::getInstance()->get(AddressMetadataInterface::class);
$this->attributeOptionManager = $attributeOptionManager ??
ObjectManager::getInstance()->get(AttributeOptionManagementInterface::class);
+ $this->customerAddressData = $customerAddressData ?:
+ ObjectManager::getInstance()->get(CustomerAddressDataProvider::class);
}
/**
@@ -359,57 +370,18 @@ private function isAutocompleteEnabled()
*
* @return array
*/
- private function getCustomerData()
+ private function getCustomerData(): array
{
$customerData = [];
if ($this->isCustomerLoggedIn()) {
+ /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */
$customer = $this->customerRepository->getById($this->customerSession->getCustomerId());
$customerData = $customer->__toArray();
- foreach ($customer->getAddresses() as $key => $address) {
- $customerData['addresses'][$key]['inline'] = $this->getCustomerAddressInline($address);
- if ($address->getCustomAttributes()) {
- $customerData['addresses'][$key]['custom_attributes'] = $this->filterNotVisibleAttributes(
- $customerData['addresses'][$key]['custom_attributes']
- );
- }
- }
+ $customerData['addresses'] = $this->customerAddressData->getAddressDataByCustomer($customer);
}
return $customerData;
}
- /**
- * Filter not visible on storefront custom attributes.
- *
- * @param array $attributes
- * @return array
- */
- private function filterNotVisibleAttributes(array $attributes)
- {
- $attributesMetadata = $this->addressMetadata->getAllAttributesMetadata();
- foreach ($attributesMetadata as $attributeMetadata) {
- if (!$attributeMetadata->isVisible()) {
- unset($attributes[$attributeMetadata->getAttributeCode()]);
- }
- }
-
- return $this->setLabelsToAttributes($attributes);
- }
-
- /**
- * Set additional customer address data
- *
- * @param \Magento\Customer\Api\Data\AddressInterface $address
- * @return string
- */
- private function getCustomerAddressInline($address)
- {
- $builtOutputAddressData = $this->addressMapper->toFlatArray($address);
- return $this->addressConfig
- ->getFormatByCode(\Magento\Customer\Model\Address\Config::DEFAULT_ADDRESS_FORMAT)
- ->getRenderer()
- ->renderArray($builtOutputAddressData);
- }
-
/**
* Retrieve quote data
*
@@ -726,61 +698,6 @@ private function getPaymentMethods()
return $paymentMethods;
}
- /**
- * Set Labels to custom Attributes
- *
- * @param array $customAttributes
- * @return array $customAttributes
- * @throws \Magento\Framework\Exception\InputException
- * @throws \Magento\Framework\Exception\StateException
- */
- private function setLabelsToAttributes(array $customAttributes) : array
- {
- if (!empty($customAttributes)) {
- foreach ($customAttributes as $customAttributeCode => $customAttribute) {
- $attributeOptionLabels = $this->getAttributeLabels($customAttribute, $customAttributeCode);
- if (!empty($attributeOptionLabels)) {
- $customAttributes[$customAttributeCode]['label'] = implode(', ', $attributeOptionLabels);
- }
- }
- }
-
- return $customAttributes;
- }
-
- /**
- * Get Labels by CustomAttribute and CustomAttributeCode
- *
- * @param array $customAttribute
- * @param string|integer $customAttributeCode
- * @return array $attributeOptionLabels
- * @throws \Magento\Framework\Exception\InputException
- * @throws \Magento\Framework\Exception\StateException
- */
- private function getAttributeLabels(array $customAttribute, string $customAttributeCode) : array
- {
- $attributeOptionLabels = [];
-
- if (!empty($customAttribute['value'])) {
- $customAttributeValues = explode(',', $customAttribute['value']);
- $attributeOptions = $this->attributeOptionManager->getItems(
- \Magento\Customer\Model\Indexer\Address\AttributeProvider::ENTITY,
- $customAttributeCode
- );
-
- if (!empty($attributeOptions)) {
- foreach ($attributeOptions as $attributeOption) {
- $attributeOptionValue = $attributeOption->getValue();
- if (in_array($attributeOptionValue, $customAttributeValues)) {
- $attributeOptionLabels[] = $attributeOption->getLabel() ?? $attributeOptionValue;
- }
- }
- }
- }
-
- return $attributeOptionLabels;
- }
-
/**
* Get notification messages for the quote items
*
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailNoteMessageOnCheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailNoteMessageOnCheckoutActionGroup.xml
new file mode 100644
index 0000000000000..c4fc753e73713
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailNoteMessageOnCheckoutActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailTooltipContentOnCheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailTooltipContentOnCheckoutActionGroup.xml
new file mode 100644
index 0000000000000..f9c6771262ccc
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailTooltipContentOnCheckoutActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailValidationMessageOnCheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailValidationMessageOnCheckoutActionGroup.xml
new file mode 100644
index 0000000000000..14b96ed46ce6b
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertStorefrontEmailValidationMessageOnCheckoutActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml
index b67b7451d5968..2e4b742ece8ec 100644
--- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml
@@ -110,7 +110,7 @@
-
+
@@ -241,6 +241,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -257,13 +272,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/FillNewShippingAddressModalActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/FillNewShippingAddressModalActionGroup.xml
new file mode 100644
index 0000000000000..7035855cc0ed3
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/FillNewShippingAddressModalActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCartEstimateShippingAndTaxActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCartEstimateShippingAndTaxActionGroup.xml
new file mode 100644
index 0000000000000..0d6f34098c048
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCartEstimateShippingAndTaxActionGroup.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCartShippingMethodSelectedActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCartShippingMethodSelectedActionGroup.xml
new file mode 100644
index 0000000000000..4061f97821cd0
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCartShippingMethodSelectedActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutEstimateShippingInformationActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutEstimateShippingInformationActionGroup.xml
new file mode 100644
index 0000000000000..82d7e12105b8c
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutEstimateShippingInformationActionGroup.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutShippingMethodSelectedActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutShippingMethodSelectedActionGroup.xml
new file mode 100644
index 0000000000000..33f2852f1f0ad
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertCheckoutShippingMethodSelectedActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertGuestShippingInfoActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertGuestShippingInfoActionGroup.xml
new file mode 100644
index 0000000000000..02c362bf34058
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertGuestShippingInfoActionGroup.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertShippingMethodPresentInCartActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertShippingMethodPresentInCartActionGroup.xml
new file mode 100644
index 0000000000000..3d8530ae83704
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontAssertShippingMethodPresentInCartActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontCartEstimateShippingAndTaxActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontCartEstimateShippingAndTaxActionGroup.xml
new file mode 100644
index 0000000000000..4176859f99f70
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontCartEstimateShippingAndTaxActionGroup.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontFillEmailFieldOnCheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontFillEmailFieldOnCheckoutActionGroup.xml
new file mode 100644
index 0000000000000..fcac780a36776
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontFillEmailFieldOnCheckoutActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontFillGuestShippingInfoActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontFillGuestShippingInfoActionGroup.xml
new file mode 100644
index 0000000000000..e7669d62c79a0
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontFillGuestShippingInfoActionGroup.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontOpenCheckoutPageActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontOpenCheckoutPageActionGroup.xml
new file mode 100644
index 0000000000000..b18d476c02c65
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/StorefrontOpenCheckoutPageActionGroup.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Data/EstimateAndTaxData.xml b/app/code/Magento/Checkout/Test/Mftf/Data/EstimateAndTaxData.xml
new file mode 100644
index 0000000000000..36dea5a521a04
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Data/EstimateAndTaxData.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ United States
+ California
+ 90240
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml
index 8d14a9a561900..3100fae3b119b 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutCartSummarySection.xml
@@ -20,9 +20,12 @@
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml
index 0206c18b819c2..cbe71e9cffa60 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentSection.xml
@@ -54,5 +54,6 @@
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentWithDisplayBillingAddressOnPaymentPageSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentWithDisplayBillingAddressOnPaymentPageSection.xml
new file mode 100644
index 0000000000000..42decd8d43220
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutPaymentWithDisplayBillingAddressOnPaymentPageSection.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml
index 6838824400b96..b19e365f2e32c 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingGuestInfoSection.xml
@@ -9,13 +9,17 @@
-
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml
index ab4b59fd67d03..77d903eab3934 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingMethodsSection.xml
@@ -17,5 +17,6 @@
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml
index d825e10395145..9676f16f3a5c6 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/CheckoutShippingSection.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutCheckoutCustomerLoginSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutCheckoutCustomerLoginSection.xml
new file mode 100644
index 0000000000000..9772fa1993acb
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutCheckoutCustomerLoginSection.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml
index 55c4385706ba9..9d9a96d2ea5e6 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutPaymentMethodSection.xml
@@ -12,5 +12,6 @@
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/DefaultBillingAddressShouldBeCheckedOnPaymentPageTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/DefaultBillingAddressShouldBeCheckedOnPaymentPageTest.xml
new file mode 100644
index 0000000000000..166f5022d5aeb
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/DefaultBillingAddressShouldBeCheckedOnPaymentPageTest.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml
index e7c2ad3dd28a4..fadc9ec50ad8d 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest.xml
@@ -186,20 +186,20 @@
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
+
@@ -216,16 +216,18 @@
-
-
+
+
+
-
-
-
+
+
+
+
@@ -253,16 +255,18 @@
-
-
-
-
-
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml
index 8537e10ce5a03..651c5bd8d4375 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerPlaceOrderWithNewAddressesThatWasEditedTest.xml
@@ -71,6 +71,7 @@
+
@@ -89,7 +90,7 @@
-
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontPersistentDataForGuestCustomerWithPhysicalQuoteTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontPersistentDataForGuestCustomerWithPhysicalQuoteTest.xml
new file mode 100644
index 0000000000000..20ff67a076e1e
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontPersistentDataForGuestCustomerWithPhysicalQuoteTest.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontValidateEmailOnCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontValidateEmailOnCheckoutTest.xml
new file mode 100644
index 0000000000000..1b27e1d53adad
--- /dev/null
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontValidateEmailOnCheckoutTest.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml
index 64b70e80bd84f..a305413bcf1f3 100644
--- a/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml
+++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml
@@ -105,7 +105,7 @@
- opc-new-shipping-address
-
-
-
- Save Address
+ - Ship here
- action primary action-save-address
-
diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml
index 454031279d882..d15794fb761bb 100644
--- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml
+++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml
@@ -84,20 +84,20 @@ $canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinima
|
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js b/app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js
index 7db0dc5ce7473..c601bb8acf125 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/action/create-billing-address.js
@@ -12,6 +12,17 @@ define([
'use strict';
return function (addressData) {
- return addressConverter.formAddressDataToQuoteAddress(addressData);
+ var address = addressConverter.formAddressDataToQuoteAddress(addressData);
+
+ /**
+ * Returns new customer billing address type.
+ *
+ * @returns {String}
+ */
+ address.getType = function () {
+ return 'new-customer-billing-address';
+ };
+
+ return address;
};
});
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js
index 9cc60a3645d58..bc0ab59b622a2 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/model/checkout-data-resolver.js
@@ -216,11 +216,11 @@ define([
newCustomerBillingAddressData = checkoutData.getNewCustomerBillingAddress();
if (selectedBillingAddress) {
- if (selectedBillingAddress == 'new-customer-address' && newCustomerBillingAddressData) { //eslint-disable-line
+ if (selectedBillingAddress === 'new-customer-billing-address' && newCustomerBillingAddressData) {
selectBillingAddress(createBillingAddress(newCustomerBillingAddressData));
} else {
addressList.some(function (address) {
- if (selectedBillingAddress == address.getKey()) { //eslint-disable-line eqeqeq
+ if (selectedBillingAddress === address.getKey()) {
selectBillingAddress(address);
}
});
@@ -243,7 +243,7 @@ define([
return;
}
- if (quote.isVirtual()) {
+ if (quote.isVirtual() || !quote.billingAddress()) {
isBillingAddressInitialized = addressList.some(function (addrs) {
if (addrs.isDefaultBilling()) {
selectBillingAddress(addrs);
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js b/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js
index d68b0682eb511..a552aa01da061 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address.js
@@ -40,30 +40,23 @@ function (
'use strict';
var lastSelectedBillingAddress = null,
- newAddressOption = {
- /**
- * Get new address label
- * @returns {String}
- */
- getAddressInline: function () {
- return $t('New Address');
- },
- customerAddressId: null
- },
countryData = customerData.get('directory-data'),
addressOptions = addressList().filter(function (address) {
- return address.getType() == 'customer-address'; //eslint-disable-line eqeqeq
+ return address.getType() === 'customer-address';
});
- addressOptions.push(newAddressOption);
-
return Component.extend({
defaults: {
- template: 'Magento_Checkout/billing-address'
+ template: 'Magento_Checkout/billing-address',
+ actionsTemplate: 'Magento_Checkout/billing-address/actions',
+ formTemplate: 'Magento_Checkout/billing-address/form',
+ detailsTemplate: 'Magento_Checkout/billing-address/details',
+ links: {
+ isAddressFormVisible: '${$.billingAddressListProvider}:isNewAddressSelected'
+ }
},
currentBillingAddress: quote.billingAddress,
- addressOptions: addressOptions,
- customerHasAddresses: addressOptions.length > 1,
+ customerHasAddresses: addressOptions.length > 0,
/**
* Init component
@@ -84,7 +77,7 @@ function (
.observe({
selectedAddress: null,
isAddressDetailsVisible: quote.billingAddress() != null,
- isAddressFormVisible: !customer.isLoggedIn() || addressOptions.length === 1,
+ isAddressFormVisible: !customer.isLoggedIn() || !addressOptions.length,
isAddressSameAsShipping: false,
saveInAddressBook: 1
});
@@ -147,7 +140,7 @@ function (
updateAddress: function () {
var addressData, newBillingAddress;
- if (this.selectedAddress() && this.selectedAddress() != newAddressOption) { //eslint-disable-line eqeqeq
+ if (this.selectedAddress() && !this.isAddressFormVisible()) {
selectBillingAddress(this.selectedAddress());
checkoutData.setSelectedBillingAddress(this.selectedAddress().getKey());
} else {
@@ -218,13 +211,6 @@ function (
}
},
- /**
- * @param {Object} address
- */
- onAddressChange: function (address) {
- this.isAddressFormVisible(address == newAddressOption); //eslint-disable-line eqeqeq
- },
-
/**
* @param {Number} countryId
* @return {*}
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address/list.js b/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address/list.js
new file mode 100644
index 0000000000000..ca3a267c01671
--- /dev/null
+++ b/app/code/Magento/Checkout/view/frontend/web/js/view/billing-address/list.js
@@ -0,0 +1,77 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+ 'uiComponent',
+ 'Magento_Customer/js/model/address-list',
+ 'mage/translate',
+ 'Magento_Customer/js/model/customer'
+], function (Component, addressList, $t, customer) {
+ 'use strict';
+
+ var newAddressOption = {
+ /**
+ * Get new address label
+ * @returns {String}
+ */
+ getAddressInline: function () {
+ return $t('New Address');
+ },
+ customerAddressId: null
+ },
+ addressOptions = addressList().filter(function (address) {
+ return address.getType() === 'customer-address';
+ });
+
+ return Component.extend({
+ defaults: {
+ template: 'Magento_Checkout/billing-address',
+ selectedAddress: null,
+ isNewAddressSelected: false,
+ addressOptions: addressOptions,
+ exports: {
+ selectedAddress: '${ $.parentName }:selectedAddress'
+ }
+ },
+
+ /**
+ * @returns {Object} Chainable.
+ */
+ initConfig: function () {
+ this._super();
+ this.addressOptions.push(newAddressOption);
+
+ return this;
+ },
+
+ /**
+ * @return {exports.initObservable}
+ */
+ initObservable: function () {
+ this._super()
+ .observe('selectedAddress isNewAddressSelected')
+ .observe({
+ isNewAddressSelected: !customer.isLoggedIn() || !addressOptions.length
+ });
+
+ return this;
+ },
+
+ /**
+ * @param {Object} address
+ * @return {*}
+ */
+ addressOptionsText: function (address) {
+ return address.getAddressInline();
+ },
+
+ /**
+ * @param {Object} address
+ */
+ onAddressChange: function (address) {
+ this.isNewAddressSelected(address === newAddressOption);
+ }
+ });
+});
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js b/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js
index c17e5e40d5c98..e8994c61b7221 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/view/payment.js
@@ -66,9 +66,21 @@ define([
navigate: function () {
var self = this;
- getPaymentInformation().done(function () {
- self.isVisible(true);
- });
+ if (!self.hasShippingMethod()) {
+ this.isVisible(false);
+ stepNavigator.setHash('shipping');
+ } else {
+ getPaymentInformation().done(function () {
+ self.isVisible(true);
+ });
+ }
+ },
+
+ /**
+ * @return {Boolean}
+ */
+ hasShippingMethod: function () {
+ return window.checkoutConfig.selectedShippingMethod !== null;
},
/**
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/authentication.html b/app/code/Magento/Checkout/view/frontend/web/template/authentication.html
index 406a7d899b67a..5b8dde81dd93e 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/authentication.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/authentication.html
@@ -31,15 +31,15 @@