diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
index 63a9842808a71..366202df27ee7 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php
@@ -17,6 +17,11 @@ abstract class Category extends \Magento\Backend\App\Action
*/
const ADMIN_RESOURCE = 'Magento_Catalog::categories';
+ /**
+ * @var \Magento\Framework\Stdlib\DateTime\Filter\DateTime
+ */
+ private $dateTimeFilter;
+
/**
* Initialize requested category and put it into registry.
* Root category can be returned, if inappropriate store/category is specified
@@ -107,4 +112,41 @@ protected function ajaxRequestResponse($category, $resultPage)
$resultJson->setData($eventResponse->getData());
return $resultJson;
}
+
+ /**
+ * @return \Magento\Framework\Stdlib\DateTime\Filter\DateTime
+ *
+ * @deprecated
+ */
+ private function getDateTimeFilter()
+ {
+ if ($this->dateTimeFilter === null) {
+ $this->dateTimeFilter = \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(\Magento\Framework\Stdlib\DateTime\Filter\DateTime::class);
+ }
+ return $this->dateTimeFilter;
+ }
+
+ /**
+ * Datetime data preprocessing
+ *
+ * @param \Magento\Catalog\Model\Category $category
+ * @param array $postData
+ *
+ * @return array
+ */
+ protected function dateTimePreprocessing($category, $postData)
+ {
+ $dateFieldFilters = [];
+ $attributes = $category->getAttributes();
+ foreach ($attributes as $attrKey => $attribute) {
+ if ($attribute->getBackend()->getType() == 'datetime') {
+ if (array_key_exists($attrKey, $postData) && $postData[$attrKey] != '') {
+ $dateFieldFilters[$attrKey] = $this->getDateTimeFilter();
+ }
+ }
+ }
+ $inputFilter = new \Zend_Filter_Input($dateFieldFilters, [], $postData);
+ return $inputFilter->getUnescaped();
+ }
}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
index 17ed8b762c1e4..c66fe32bcce2d 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php
@@ -50,6 +50,15 @@ public function execute()
return $resultRedirect->setPath('catalog/*/', ['_current' => true, 'id' => null]);
}
+ /**
+ * Check if there are data in session (if there was an exception on saving category)
+ */
+ $categoryData = $this->_getSession()->getCategoryData(true);
+ if (is_array($categoryData)) {
+ unset($categoryData['image']);
+ $category->addData($categoryData);
+ }
+
$resultPageFactory = $this->_objectManager->get('Magento\Framework\View\Result\PageFactory');
/** @var \Magento\Backend\Model\View\Result\Page $resultPage */
$resultPage = $resultPageFactory->create();
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
index 3f81b2bbd0ea1..1f5a68969037a 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Edit.php
@@ -80,16 +80,16 @@ public function execute()
}
/**
- * Check if we have data in session (if during category save was exception)
+ * Check if there are data in session (if there was an exception on saving category)
*/
- $data = $this->_getSession()->getCategoryData(true);
- if (isset($data['general'])) {
- if (isset($data['general']['image']['delete'])) {
- $data['general']['image'] = null;
+ $categoryData = $this->_getSession()->getCategoryData(true);
+ if (is_array($categoryData)) {
+ if (isset($categoryData['image']['delete'])) {
+ $categoryData['image'] = null;
} else {
- unset($data['general']['image']);
+ unset($categoryData['image']);
}
- $category->addData($data['general']);
+ $category->addData($categoryData);
}
/** @var \Magento\Backend\Model\View\Result\Page $resultPage */
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
index 852c465b1482a..d3878e6eba120 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
@@ -9,7 +9,7 @@
/**
* Class Save
- *
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Save extends \Magento\Catalog\Controller\Adminhtml\Category
@@ -34,15 +34,13 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
* @var array
*/
protected $stringToBoolInputs = [
- 'general' => [
- 'custom_use_parent_settings',
- 'custom_apply_to_products',
- 'is_active',
- 'include_in_menu',
- 'is_anchor',
- 'use_default' => ['url_key'],
- 'use_config' => ['available_sort_by', 'filter_price_range', 'default_sort_by']
- ]
+ 'custom_use_parent_settings',
+ 'custom_apply_to_products',
+ 'is_active',
+ 'include_in_menu',
+ 'is_anchor',
+ 'use_default' => ['url_key'],
+ 'use_config' => ['available_sort_by', 'filter_price_range', 'default_sort_by']
];
/**
@@ -110,15 +108,18 @@ public function execute()
}
$data['general'] = $this->getRequest()->getPostValue();
- $isNewCategory = !isset($data['general']['entity_id']);
- $data = $this->stringToBoolConverting($data);
- $data = $this->imagePreprocessing($data);
- $storeId = isset($data['general']['store_id']) ? $data['general']['store_id'] : null;
+ $categoryPostData = $data['general'];
+
+ $isNewCategory = !isset($categoryPostData['entity_id']);
+ $categoryPostData = $this->stringToBoolConverting($categoryPostData);
+ $categoryPostData = $this->imagePreprocessing($categoryPostData);
+ $categoryPostData = $this->dateTimePreprocessing($category, $categoryPostData);
+ $storeId = isset($categoryPostData['store_id']) ? $categoryPostData['store_id'] : null;
$store = $this->storeManager->getStore($storeId);
$this->storeManager->setCurrentStore($store->getCode());
- $parentId = isset($data['general']['parent']) ? $data['general']['parent'] : null;
- if ($data['general']) {
- $category->addData($this->_filterCategoryPostData($data['general']));
+ $parentId = isset($categoryPostData['parent']) ? $categoryPostData['parent'] : null;
+ if ($categoryPostData) {
+ $category->addData($this->_filterCategoryPostData($categoryPostData));
if ($isNewCategory) {
$parentCategory = $this->getParentCategory($parentId, $storeId);
$category->setPath($parentCategory->getPath());
@@ -128,10 +129,10 @@ public function execute()
/**
* Process "Use Config Settings" checkboxes
*/
- $generalPost = $data['general'];
+
$useConfig = [];
- if (isset($generalPost['use_config']) && !empty($generalPost['use_config'])) {
- foreach ($generalPost['use_config'] as $attributeCode => $attributeValue) {
+ if (isset($categoryPostData['use_config']) && !empty($categoryPostData['use_config'])) {
+ foreach ($categoryPostData['use_config'] as $attributeCode => $attributeValue) {
if ($attributeValue) {
$useConfig[] = $attributeCode;
$category->setData($attributeCode, null);
@@ -141,11 +142,11 @@ public function execute()
$category->setAttributeSetId($category->getDefaultAttributeSetId());
- if (isset($data['general']['category_products'])
- && is_string($data['general']['category_products'])
+ if (isset($categoryPostData['category_products'])
+ && is_string($categoryPostData['category_products'])
&& !$category->getProductsReadonly()
) {
- $products = json_decode($data['general']['category_products'], true);
+ $products = json_decode($categoryPostData['category_products'], true);
$category->setPostedProducts($products);
}
$this->_eventManager->dispatch(
@@ -156,8 +157,8 @@ public function execute()
/**
* Check "Use Default Value" checkboxes values
*/
- if (isset($generalPost['use_default']) && !empty($generalPost['use_default'])) {
- foreach ($generalPost['use_default'] as $attributeCode => $attributeValue) {
+ if (isset($categoryPostData['use_default']) && !empty($categoryPostData['use_default'])) {
+ foreach ($categoryPostData['use_default'] as $attributeCode => $attributeValue) {
if ($attributeValue) {
$category->setData($attributeCode, null);
}
@@ -197,15 +198,15 @@ public function execute()
} catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
$this->messageManager->addError($e->getMessage());
$this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
- $this->_getSession()->setCategoryData($data);
+ $this->_getSession()->setCategoryData($categoryPostData);
} catch (\Magento\Framework\Exception\LocalizedException $e) {
$this->messageManager->addError($e->getMessage());
$this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
- $this->_getSession()->setCategoryData($data);
+ $this->_getSession()->setCategoryData($categoryPostData);
} catch (\Exception $e) {
$this->messageManager->addError(__('Something went wrong while saving the category.'));
$this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
- $this->_getSession()->setCategoryData($data);
+ $this->_getSession()->setCategoryData($categoryPostData);
}
}
@@ -248,9 +249,9 @@ public function execute()
*/
public function imagePreprocessing($data)
{
- if (empty($data['general']['image'])) {
- unset($data['general']['image']);
- $data['general']['image']['delete'] = true;
+ if (empty($data['image'])) {
+ unset($data['image']);
+ $data['image']['delete'] = true;
}
return $data;
}
diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
index f2e2ea6c78816..6c114089789c6 100644
--- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
+++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
@@ -111,6 +111,9 @@ public function afterSave($object)
} catch (\Exception $e) {
$this->_logger->critical($e);
}
+ } elseif (isset($value[0]['name'])) {
+ $object->setData($this->getAttribute()->getName(), $value[0]['name']);
+ $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName());
}
return $this;
}
diff --git a/app/code/Magento/Catalog/Model/Category/DataProvider.php b/app/code/Magento/Catalog/Model/Category/DataProvider.php
index e1d1ee848f288..8626d183e2fac 100644
--- a/app/code/Magento/Catalog/Model/Category/DataProvider.php
+++ b/app/code/Magento/Catalog/Model/Category/DataProvider.php
@@ -201,9 +201,7 @@ public function getData()
return $this->loadedData;
}
$category = $this->getCurrentCategory();
- if (!$category->getId()) {
- return [];
- } else {
+ if ($category) {
$categoryData = $category->getData();
$categoryData = $this->addUseDefaultSettings($category, $categoryData);
$categoryData = $this->addUseConfigSettings($categoryData);
diff --git a/app/code/Magento/Catalog/Model/Product/Option.php b/app/code/Magento/Catalog/Model/Product/Option.php
index 86ed6714529d8..2c9e09f8aff30 100644
--- a/app/code/Magento/Catalog/Model/Product/Option.php
+++ b/app/code/Magento/Catalog/Model/Product/Option.php
@@ -63,6 +63,11 @@ class Option extends AbstractExtensibleModel implements ProductCustomOptionInter
*/
protected $optionRepository;
+ /**
+ * Option type percent
+ */
+ protected static $typePercent = 'percent';
+
/**#@+
* Constants
*/
@@ -424,7 +429,7 @@ public function afterSave()
*/
public function getPrice($flag = false)
{
- if ($flag && $this->getPriceType() == 'percent') {
+ if ($flag && $this->getPriceType() == self::$typePercent) {
$basePrice = $this->getProduct()->getPriceInfo()->getPrice(BasePrice::PRICE_CODE)->getValue();
$price = $basePrice * ($this->_getData(self::KEY_PRICE) / 100);
return $price;
@@ -827,6 +832,21 @@ public function getExtensionAttributes()
return $this->_getExtensionAttributes();
}
+ /**
+ * Return regular price.
+ *
+ * @return float|int
+ */
+ public function getRegularPrice()
+ {
+ if ($this->getPriceType() == self::$typePercent) {
+ $basePrice = $this->getProduct()->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue();
+ $price = $basePrice * ($this->_getData(self::KEY_PRICE) / 100);
+ return $price;
+ }
+ return $this->_getData(self::KEY_PRICE);
+ }
+
/**
* @param Product $product
* @return \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
diff --git a/app/code/Magento/Catalog/Setup/UpgradeData.php b/app/code/Magento/Catalog/Setup/UpgradeData.php
index 542fea6770fab..ab32e8c5a6c7d 100644
--- a/app/code/Magento/Catalog/Setup/UpgradeData.php
+++ b/app/code/Magento/Catalog/Setup/UpgradeData.php
@@ -338,7 +338,20 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface
]
);
}
+
+ if (version_compare($context->getVersion(), '2.0.7') < 0) {
+ /** @var EavSetup $eavSetupF */
+ $eavSetup= $this->eavSetupFactory->create(['setup' => $setup]);
+ $eavSetup->updateAttribute(
+ ProductAttributeInterface::ENTITY_TYPE_CODE,
+ 'meta_description',
+ [
+ 'note' => 'Maximum 255 chars. Meta Description should optimally be between 150-160 characters'
+ ]
+ );
+ }
+
$setup->endSetup();
}
}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php
index 8b938938c20e1..ea01f87a1ad6c 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/OptionTest.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Catalog\Test\Unit\Model\Product;
+use \Magento\Catalog\Model\Product\Option;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
class OptionTest extends \PHPUnit_Framework_TestCase
@@ -33,4 +34,29 @@ public function testGetProductSku()
$this->productMock->expects($this->once())->method('getSku')->willReturn($productSku);
$this->assertEquals($productSku, $this->model->getProductSku());
}
+
+ public function testGetRegularPrice()
+ {
+ $priceInfoMock = $this->getMockForAbstractClass(
+ 'Magento\Framework\Pricing\PriceInfoInterface',
+ [],
+ '',
+ false,
+ false,
+ true,
+ ['getAmount', 'getPrice']
+ );
+ $priceInfoMock->expects($this->once())->method('getPrice')->willReturnSelf();
+ $amountMock = $this->getMockForAbstractClass('Magento\Framework\Pricing\Amount\AmountInterface');
+ $priceInfoMock->expects($this->once())->method('getAmount')->willReturn($amountMock);
+
+ $this->productMock->expects($this->once())->method('getPriceInfo')->willReturn($priceInfoMock);
+
+ $amountMock->expects($this->once())->method('getValue')->willReturn(50);
+ $this->model->setPrice(50);
+ $this->model->setPriceType(\Magento\Catalog\Model\Product\Option\Value::TYPE_PERCENT);
+ $this->assertEquals(25, $this->model->getRegularPrice());
+ $this->model->setPriceType(null);
+ $this->assertEquals(50, $this->model->getRegularPrice());
+ }
}
diff --git a/app/code/Magento/Catalog/etc/module.xml b/app/code/Magento/Catalog/etc/module.xml
index ac6a681cd5ebd..87e82543fc65b 100644
--- a/app/code/Magento/Catalog/etc/module.xml
+++ b/app/code/Magento/Catalog/etc/module.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php b/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php
index d2aac2a8369e9..87340140ada3f 100644
--- a/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php
+++ b/app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php
@@ -724,7 +724,7 @@ protected function critical($e)
private function roundTime($timeStamp)
{
if (is_numeric($timeStamp) && $timeStamp != 0) {
- $timeStamp = $this->dateTime->timestamp($this->dateTime->date('Y-m-d 00:00:00'));
+ $timeStamp = $this->dateTime->timestamp($this->dateTime->date('Y-m-d 00:00:00', $timeStamp));
}
return $timeStamp;
diff --git a/app/code/Magento/Eav/Setup/EavSetup.php b/app/code/Magento/Eav/Setup/EavSetup.php
index b585435dee2c5..a53ed60774749 100644
--- a/app/code/Magento/Eav/Setup/EavSetup.php
+++ b/app/code/Magento/Eav/Setup/EavSetup.php
@@ -909,7 +909,7 @@ public function addAttributeOption($option)
*
* @param int|string $entityTypeId
* @param int|string $id
- * @param string $field
+ * @param string|array $field
* @param mixed $value
* @param int $sortOrder
* @return $this
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
index 0be86320e6ca7..6dc61d9110a5f 100644
--- a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
+++ b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
@@ -16,6 +16,16 @@
*/
class IndexerReindexCommand extends AbstractIndexerManageCommand
{
+ /**
+ * @var array
+ */
+ private $sharedIndexesComplete = [];
+
+ /**
+ * @var \Magento\Framework\Indexer\ConfigInterface
+ */
+ private $config;
+
/**
* {@inheritdoc}
*/
@@ -34,21 +44,19 @@ protected function configure()
protected function execute(InputInterface $input, OutputInterface $output)
{
$indexers = $this->getIndexers($input);
- $config = $this->getConfig();
- $sharedIndexesComplete = [];
foreach ($indexers as $indexer) {
try {
+ $this->validateIndexerStatus($indexer);
$startTime = microtime(true);
- $indexerConfig = $config->getIndexer($indexer->getId());
+ $indexerConfig = $this->getConfig()->getIndexer($indexer->getId());
+ $sharedIndex = $indexerConfig['shared_index'];
// Skip indexers having shared index that was already complete
- if (!in_array($indexerConfig['shared_index'], $sharedIndexesComplete)) {
+ if (!in_array($sharedIndex, $this->sharedIndexesComplete)) {
$indexer->reindexAll();
- } else {
- $indexer->getState()->setStatus(StateInterface::STATUS_VALID)->save();
- }
- if ($indexerConfig['shared_index']) {
- $sharedIndexesComplete[] = $indexerConfig['shared_index'];
+ if ($sharedIndex) {
+ $this->validateSharedIndex($sharedIndex);
+ }
}
$resultTime = microtime(true) - $startTime;
$output->writeln(
@@ -63,6 +71,72 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
}
+ /**
+ * Validate that indexer is not locked
+ *
+ * @param \Magento\Framework\Indexer\IndexerInterface $indexer
+ * @return void
+ * @throws LocalizedException
+ */
+ private function validateIndexerStatus(\Magento\Framework\Indexer\IndexerInterface $indexer)
+ {
+ if ($indexer->getStatus() == \Magento\Framework\Indexer\StateInterface::STATUS_WORKING) {
+ throw new LocalizedException(
+ __(
+ '%1 index is locked by another reindex process. Skipping.',
+ $indexer->getTitle()
+ )
+ );
+ }
+ }
+
+ /**
+ * Get indexer ids that have common shared index
+ *
+ * @param string $sharedIndex
+ * @return array
+ */
+ private function getIndexerIdsBySharedIndex($sharedIndex)
+ {
+ $indexers = $this->getConfig()->getIndexers();
+ $result = [];
+ foreach ($indexers as $indexerConfig) {
+ if ($indexerConfig['shared_index'] == $sharedIndex) {
+ $result[] = $indexerConfig['indexer_id'];
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Validate indexers by shared index ID
+ *
+ * @param string $sharedIndex
+ * @return $this
+ */
+ private function validateSharedIndex($sharedIndex)
+ {
+ if (empty($sharedIndex)) {
+ throw new \InvalidArgumentException('sharedIndex must be a valid shared index identifier');
+ }
+ $indexerIds = $this->getIndexerIdsBySharedIndex($sharedIndex);
+ if (empty($indexerIds)) {
+ return $this;
+ }
+ $indexerFactory = $this->getObjectManager()->create('Magento\Indexer\Model\IndexerFactory');
+ foreach ($indexerIds as $indexerId) {
+ /** @var \Magento\Indexer\Model\Indexer $indexer */
+ $indexer = $indexerFactory->create();
+ $indexer->load($indexerId);
+ /** @var \Magento\Indexer\Model\Indexer\State $state */
+ $state = $indexer->getState();
+ $state->setStatus(\Magento\Framework\Indexer\StateInterface::STATUS_VALID);
+ $state->save();
+ }
+ $this->sharedIndexesComplete[] = $sharedIndex;
+ return $this;
+ }
+
/**
* Get config
*
@@ -71,6 +145,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
*/
private function getConfig()
{
- return $this->getObjectManager()->get(ConfigInterface::class);
+ if (!$this->config) {
+ $this->config = $this->getObjectManager()->get(ConfigInterface::class);
+ }
+ return $this->config;
}
}
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerResetStateCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerResetStateCommand.php
new file mode 100644
index 0000000000000..3b1e952d1e619
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/IndexerResetStateCommand.php
@@ -0,0 +1,51 @@
+setName('indexer:reset')
+ ->setDescription('Resets indexer status to invalid')
+ ->setDefinition($this->getInputList());
+
+ parent::configure();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $indexers = $this->getIndexers($input);
+ foreach ($indexers as $indexer) {
+ try {
+ $indexer->getState()
+ ->setStatus(\Magento\Framework\Indexer\StateInterface::STATUS_INVALID)
+ ->save();
+ $output->writeln($indexer->getTitle() . ' indexer has been invalidated.');
+ } catch (LocalizedException $e) {
+ $output->writeln($e->getMessage());
+ } catch (\Exception $e) {
+ $output->writeln($indexer->getTitle() . ' indexer process unknown error:');
+ $output->writeln($e->getMessage());
+ }
+ }
+ }
+}
diff --git a/app/code/Magento/Indexer/README.md b/app/code/Magento/Indexer/README.md
index fe6d85ba0fcab..b0a88d12ad0ed 100644
--- a/app/code/Magento/Indexer/README.md
+++ b/app/code/Magento/Indexer/README.md
@@ -1,4 +1,12 @@
+## Overview
Magento_Indexer module is a base of Magento Indexing functionality.
-It allows to read indexers configuration, represent indexers in admin, control their mode, regenerate indexers by schedule.
+It allows:
+ - read indexers configuration,
+ - represent indexers in admin,
+ - regenerate indexes by cron schedule,
+ - regenerate indexes from console,
+ - view and reset indexer state from console,
+ - view and set indexer mode from console
+
There are 2 modes of the Indexers: "Update on save" and "Update by schedule".
-Manual re-index can be performed via console by running index.php script.
+Manual full reindex can be performed via console by running `php -f bin/magento indexer:reindex` console command.
\ No newline at end of file
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
index f6e8b6622e4a9..40923b6418ce4 100644
--- a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
@@ -86,36 +86,60 @@ public function testExecuteWithIndex()
['id_indexer3', ['title' => 'Title_indexer3', 'shared_index' => 'with_indexer_3']]
]
));
+ $this->configMock->expects($this->any())
+ ->method('getIndexers')
+ ->will($this->returnValue(
+ [
+ 'id_indexerOne' => [
+ 'indexer_id' => 'id_indexerOne',
+ 'title' => 'Title_indexerOne',
+ 'shared_index' => null
+ ],
+ 'id_indexerTwo' => [
+ 'indexer_id' => 'id_indexerTwo',
+ 'title' => 'Title_indexerTwo',
+ 'shared_index' => 'with_indexer_3'
+ ],
+ 'id_indexer3' => [
+ 'indexer_id' => 'id_indexer3',
+ 'title' => 'Title_indexer3',
+ 'shared_index' => 'with_indexer_3'
+ ]
+ ]
+ ));
$this->configureAdminArea();
$indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
$indexerOne->expects($this->once())->method('reindexAll');
$indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
$indexerOne->expects($this->any())->method('getId')->willReturn('id_indexerOne');
- $indexerOne->expects($this->once())->method('load')->with('id_indexerOne')->willReturn($indexerOne);
+ $indexerOne->expects($this->any())->method('load')->with('id_indexerOne')->willReturn($indexerOne);
$indexerTwo = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
$indexerTwo->expects($this->once())->method('reindexAll');
$indexerTwo->expects($this->once())->method('getTitle')->willReturn('Title_indexerTwo');
$indexerTwo->expects($this->any())->method('getId')->willReturn('id_indexerTwo');
- $indexerTwo->expects($this->once())->method('load')->with('id_indexerTwo')->willReturn($indexerTwo);
+ $indexerTwo->expects($this->any())->method('load')->with('id_indexerTwo')->willReturn($indexerTwo);
$indexer3 = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
$indexer3->expects($this->never())->method('reindexAll');
$indexer3->expects($this->once())->method('getTitle')->willReturn('Title_indexer3');
$indexer3->expects($this->any())->method('getId')->willReturn('id_indexer3');
- $indexer3->expects($this->once())->method('load')->with('id_indexer3')->willReturn($indexer3);
+ $indexer3->expects($this->any())->method('load')->with('id_indexer3')->willReturn($indexer3);
$stateMock = $this->getMock(\Magento\Indexer\Model\Indexer\State::class, [], [], '', false);
- $stateMock->expects($this->once())->method('setStatus')->will($this->returnSelf());
- $stateMock->expects($this->once())->method('save');
+ $stateMock->expects($this->exactly(2))->method('setStatus')->will($this->returnSelf());
+ $stateMock->expects($this->exactly(2))->method('save');
$indexer3->expects($this->once())->method('getState')->willReturn($stateMock);
+ $indexerTwo->expects($this->once())->method('getState')->willReturn($stateMock);
$this->collectionFactory->expects($this->never())->method('create');
$this->indexerFactory->expects($this->at(0))->method('create')->willReturn($indexerOne);
$this->indexerFactory->expects($this->at(1))->method('create')->willReturn($indexerTwo);
$this->indexerFactory->expects($this->at(2))->method('create')->willReturn($indexer3);
+ $this->indexerFactory->expects($this->at(3))->method('create')->willReturn($indexerTwo);
+ $this->indexerFactory->expects($this->at(4))->method('create')->willReturn($indexer3);
$this->command = new IndexerReindexCommand($this->objectManagerFactory);
$commandTester = new CommandTester($this->command);
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerResetStateCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerResetStateCommandTest.php
new file mode 100644
index 0000000000000..5dac864ab277b
--- /dev/null
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerResetStateCommandTest.php
@@ -0,0 +1,64 @@
+stateMock->expects($this->once())->method('setAreaCode')->with(FrontNameResolver::AREA_CODE);
+ }
+
+ public function testExecute()
+ {
+ $this->configureAdminArea();
+ $collection = $this->getMock('Magento\Indexer\Model\Indexer\Collection', [], [], '', false);
+ $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+
+ $indexerOne->expects($this->once())
+ ->method('getTitle')
+ ->willReturn('Title_indexerOne');
+
+ $collection->expects($this->once())
+ ->method('getItems')
+ ->willReturn([$indexerOne]);
+
+ $stateMock = $this->getMock(\Magento\Indexer\Model\Indexer\State::class, [], [], '', false);
+ $stateMock->expects($this->exactly(1))
+ ->method('setStatus')
+ ->with(\Magento\Framework\Indexer\StateInterface::STATUS_INVALID)
+ ->will($this->returnSelf());
+
+ $stateMock->expects($this->exactly(1))
+ ->method('save');
+
+ $indexerOne->expects($this->once())
+ ->method('getState')
+ ->willReturn($stateMock);
+
+ $this->collectionFactory->expects($this->once())
+ ->method('create')
+ ->will($this->returnValue($collection));
+
+ $this->command = new IndexerResetStateCommand($this->objectManagerFactory);
+ $commandTester = new CommandTester($this->command);
+ $commandTester->execute([]);
+ $actualValue = $commandTester->getDisplay();
+ $this->assertSame(sprintf('Title_indexerOne indexer has been invalidated.') . PHP_EOL, $actualValue);
+ }
+}
diff --git a/app/code/Magento/Indexer/etc/di.xml b/app/code/Magento/Indexer/etc/di.xml
index 019dad475a553..b29cc6ca71d1a 100644
--- a/app/code/Magento/Indexer/etc/di.xml
+++ b/app/code/Magento/Indexer/etc/di.xml
@@ -51,6 +51,7 @@
- Magento\Indexer\Console\Command\IndexerSetModeCommand
- Magento\Indexer\Console\Command\IndexerShowModeCommand
- Magento\Indexer\Console\Command\IndexerStatusCommand
+ - Magento\Indexer\Console\Command\IndexerResetStateCommand
diff --git a/app/code/Magento/Reports/Model/ResourceModel/Review/Product/Collection.php b/app/code/Magento/Reports/Model/ResourceModel/Review/Product/Collection.php
index ccfbc983aab67..dae41f6d59a4f 100644
--- a/app/code/Magento/Reports/Model/ResourceModel/Review/Product/Collection.php
+++ b/app/code/Magento/Reports/Model/ResourceModel/Review/Product/Collection.php
@@ -47,7 +47,7 @@ protected function _joinReview()
'e.entity_id = r.entity_pk_value',
[
'review_cnt' => new \Zend_Db_Expr(sprintf('(%s)', $subSelect)),
- 'last_created' => 'MAX(r.created_at)'
+ 'created_at' => 'MAX(r.created_at)'
]
)->group(
'e.entity_id'
@@ -83,7 +83,7 @@ protected function _joinReview()
*/
public function addAttributeToSort($attribute, $dir = self::SORT_ORDER_ASC)
{
- if (in_array($attribute, ['review_cnt', 'last_created', 'avg_rating', 'avg_rating_approved'])) {
+ if (in_array($attribute, ['review_cnt', 'created_at', 'avg_rating', 'avg_rating_approved'])) {
$this->getSelect()->order($attribute . ' ' . $dir);
return $this;
}
diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml
index 094740686678f..c795a9e29223c 100644
--- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml
+++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml
@@ -86,12 +86,12 @@
col-avg-rating
-
+
Last Review
datetime
- last_created
- last_created
+ created_at
+ created_at
col-date
col-date
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml
index 03c5cd3c02995..593ab70e100ff 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml
@@ -110,6 +110,10 @@
checkbox
input[name='custom_use_parent_settings']
+
+ select
+ select[name='custom_design']
+
select
select[name='page_layout']
@@ -137,10 +141,6 @@
text
input[name='custom_design_to']
-
- select
- select[name='custom_design']
-
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php
index db0cab463a417..0f7c04da94bdf 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php
@@ -62,6 +62,10 @@ public function getProductItem(FixtureInterface $product)
*/
public function getProducts()
{
+ if (!$this->_rootElement->isVisible($this->productItem)) {
+ return [];
+ }
+
$elements = $this->_rootElement->getElements($this->productItem, Locator::SELECTOR_CSS);
$result = [];
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Related.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Related.php
index f1b1e029f62d4..c81cab9de5297 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Related.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Related.php
@@ -38,6 +38,10 @@ public function getProductItem(FixtureInterface $product)
*/
public function getProducts()
{
+ if (!$this->_rootElement->isVisible($this->productItem)) {
+ return [];
+ }
+
$elements = $this->_rootElement->getElements($this->productItem, Locator::SELECTOR_CSS);
$result = [];
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php
index b5102db734e42..c1ed4c8bbd182 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php
@@ -45,6 +45,10 @@ public function processAssert(
$this->openCategory($category);
$breadcrumbs = $this->getBreadcrumbs($category);
+ \PHPUnit_Framework_Assert::assertNotEmpty(
+ $breadcrumbs,
+ 'No breadcrumbs on category \''. $category->getName() . '\' page.'
+ );
$pageBreadcrumbs = $catalogCategoryView->getBreadcrumbs()->getText();
\PHPUnit_Framework_Assert::assertEquals(
$breadcrumbs,
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php
index 936d00040de48..25166e66073f4 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php
@@ -40,7 +40,7 @@ public function processAssert(
foreach ($products as $productFixture) {
\PHPUnit_Framework_Assert::assertTrue(
$categoryView->getListProductBlock()->getProductItem($productFixture)->isVisible(),
- "Products '{$productFixture->getName()}' not found."
+ "Products '{$productFixture->getName()}' not found in category '{$category->getName()}'."
);
}
}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php
index 7cad535e5e02c..b053218966634 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php
@@ -51,7 +51,8 @@ public function processAssert(
$checkoutCart->open();
foreach ($promotedProducts as $promotedProduct) {
if (!$checkoutCart->getCrosssellBlock()->getProductItem($promotedProduct)->isVisible()) {
- $errors[] = 'Product \'' . $promotedProduct->getName() . '\' is absent in cross-sell section.';
+ $errors[] = 'Product \'' . $promotedProduct->getName()
+ . '\' is absent in cross-sell section of a product \'' . $product->getName() . '\'.';
}
}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php
index bc1a6cfbc35f4..cb3db6bd63488 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php
@@ -46,7 +46,8 @@ public function processAssert(
foreach ($promotedProducts as $promotedProduct) {
\PHPUnit_Framework_Assert::assertTrue(
$catalogProductView->getRelatedProductBlock()->getProductItem($promotedProduct)->isVisible(),
- 'Product \'' . $promotedProduct->getName() . '\' is absent in related products.'
+ 'Product \'' . $promotedProduct->getName()
+ . '\' is absent in related products \'' . $product->getName() . '\'.'
);
}
}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php
index e85edcdbd081b..f35a3004fda6d 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php
@@ -46,7 +46,8 @@ public function processAssert(
foreach ($promotedProducts as $promotedProduct) {
\PHPUnit_Framework_Assert::assertTrue(
$catalogProductView->getUpsellBlock()->getProductItem($promotedProduct)->isVisible(),
- 'Product \'' . $promotedProduct->getName() . '\' is absent in up-sells products.'
+ 'Product \'' . $promotedProduct->getName()
+ . '\' is absent in up-sells products of a product \'' . $product->getName() . '\'.'
);
}
}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml
index eb4967eec2616..b9ba495535e82 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml
@@ -46,11 +46,11 @@
+
-
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
index 6ca96f063ea9b..b79d1b61709dd 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
@@ -227,7 +227,7 @@
product_100_dollar%isolation%
product_100_dollar%isolation%
- - 666.0000
+ - 777.0000
- In Stock
This item has weight
@@ -252,7 +252,7 @@
product_40_dollar%isolation%
simple
- - 666
+ - 777
- In Stock
This item has weight
@@ -277,7 +277,7 @@
- default
- - 666
+ - 777
- In Stock
This item has weight
@@ -300,7 +300,7 @@
simple_product_with_category_%isolation%
Simple product with category %isolation%
- - 666
+ - 777
- In Stock
This item has weight
@@ -349,7 +349,7 @@
- default
- - 666
+ - 777
- In Stock
Simple Product %isolation%
@@ -487,7 +487,7 @@
- None
- - 666
+ - 777
- In Stock
This item has weight
@@ -511,7 +511,7 @@
- None
- - 666
+ - 777
- In Stock
This item has weight
@@ -535,7 +535,7 @@
- None
- - 666
+ - 777
- In Stock
This item has weight
@@ -559,7 +559,7 @@
- taxable_goods
- - 666
+ - 777
- In Stock
This item has weight
@@ -973,7 +973,7 @@
simple_product_with_category_%isolation%
Simple product with category %isolation%
- - 666
+ - 777
- In Stock
This item has weight
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml
index 164053ada9525..3fb2ff43914fa 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml
@@ -23,7 +23,7 @@
Virtual product %isolation%
sku_virtual_product_%isolation%
- - 666
+ - 777
- In Stock
This item has no weight
@@ -112,7 +112,7 @@
Virtual product %isolation%
sku_virtual_product_%isolation%
- - 666
+ - 777
- In Stock
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml
index e69adac6123d9..7e6f913dda6e7 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml
@@ -36,11 +36,11 @@
custom meta keywords %isolation%
Custom meta description %isolation%
2 columns with right bar
- LAYOUT UPDATE XML
- Yes
- 01/10/2014
- 12/31/2024
+ <referenceContainer name="catalog.leftnav" remove="true"/>
Magento Luma
+ Yes
+ Jan 10, 2014
+ Dec 31, 2024
@@ -79,11 +79,11 @@
Custom meta description %isolation%
catalogProductSimple::default,catalogProductSimple::default
2 columns with right bar
- LAYOUT UPDATE XML
- Yes
- 01/10/2014
- 12/31/2024
+ <referenceContainer name="content.aside" remove="true"/>
Magento Luma
+ Yes
+ Jan 1, 2014
+ Dec 31, 2024