diff --git a/.htaccess.sample b/.htaccess.sample
index 8e6e702ced716..3c412725f2134 100644
--- a/.htaccess.sample
+++ b/.htaccess.sample
@@ -111,7 +111,8 @@
############################################
## enable rewrites
- Options +FollowSymLinks
+ # The following line has better security but add some performance overhead - see https://httpd.apache.org/docs/2.4/en/misc/perf-tuning.html
+ Options -FollowSymLinks +SymLinksIfOwnerMatch
RewriteEngine on
############################################
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
index e05681212e84f..0a736890e8fe8 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
@@ -5,19 +5,18 @@
*/
namespace Magento\CatalogImportExport\Model\Import;
+use Magento\Catalog\Model\Config as CatalogConfig;
use Magento\Catalog\Model\Product\Visibility;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as ValidatorInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
-use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Filesystem;
use Magento\Framework\Model\ResourceModel\Db\ObjectRelationProcessor;
use Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface;
use Magento\Framework\Stdlib\DateTime;
-use Magento\Framework\Filesystem;
use Magento\ImportExport\Model\Import;
use Magento\ImportExport\Model\Import\Entity\AbstractEntity;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
-use Magento\Catalog\Model\Config as CatalogConfig;
/**
* Import entity product model
@@ -1298,20 +1297,15 @@ protected function _saveLinks()
*/
protected function _saveProductAttributes(array $attributesData)
{
+ $linkField = $this->getProductEntityLinkField();
foreach ($attributesData as $tableName => $skuData) {
$tableData = [];
foreach ($skuData as $sku => $attributes) {
- $linkId = $this->_connection->fetchOne(
- $this->_connection->select()
- ->from($this->getResource()->getTable('catalog_product_entity'))
- ->where('sku = ?', (string)$sku)
- ->columns($this->getProductEntityLinkField())
- );
-
+ $linkId = $this->_oldSku[strtolower($sku)][$linkField];
foreach ($attributes as $attributeId => $storeValues) {
foreach ($storeValues as $storeId => $storeValue) {
$tableData[] = [
- $this->getProductEntityLinkField() => $linkId,
+ $linkField => $linkId,
'attribute_id' => $attributeId,
'store_id' => $storeId,
'value' => $storeValue,
@@ -1321,6 +1315,7 @@ protected function _saveProductAttributes(array $attributesData)
}
$this->_connection->insertOnDuplicate($tableName, $tableData, ['value']);
}
+
return $this;
}
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
index 048a9f88f87a2..428407912725e 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
@@ -6,7 +6,6 @@
namespace Magento\CatalogImportExport\Test\Unit\Model\Import;
use Magento\Framework\App\Filesystem\DirectoryList;
-use Magento\Framework\Stdlib\DateTime;
use Magento\ImportExport\Model\Import;
/**
@@ -513,25 +512,6 @@ public function testSaveProductAttributes()
]
]
];
- $entityTable = 'catalog_product_entity';
- $resource = $this->getMockBuilder(\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel::class)
- ->disableOriginalConstructor()
- ->setMethods(['getTable'])
- ->getMock();
- $resource->expects($this->once())->method('getTable')->with($entityTable)->willReturnArgument(0);
- $this->_resourceFactory->expects($this->once())->method('create')->willReturn($resource);
- $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
- ->disableOriginalConstructor()
- ->getMock();
- $selectMock->expects($this->once())->method('from')->with($entityTable, '*', null)->willReturnSelf();
- $selectMock->expects($this->once())->method('where')->with('sku = ?', $testSku)->willReturnSelf();
- $selectMock->expects($this->once())->method('columns')->with('entity_id')->willReturnSelf();
- $this->_connection->expects($this->any())->method('fetchOne')->willReturn(self::ENTITY_ID);
- $this->_connection->expects($this->any())->method('select')->willReturn($selectMock);
- $this->_connection->expects($this->any())
- ->method('quoteInto')
- ->willReturnCallback([$this, 'returnQuoteCallback']);
-
$tableData[] = [
'entity_id' => self::ENTITY_ID,
'attribute_id' => $attributeId,
@@ -541,6 +521,7 @@ public function testSaveProductAttributes()
$this->_connection->expects($this->once())
->method('insertOnDuplicate')
->with($testTable, $tableData, ['value']);
+ $this->setPropertyValue($this->importProduct, '_oldSku', [$testSku => ['entity_id' => self::ENTITY_ID]]);
$object = $this->invokeMethod($this->importProduct, '_saveProductAttributes', [$attributesData]);
$this->assertEquals($this->importProduct, $object);
}
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
index 360a11cf2748f..e6345af40f37a 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
@@ -1296,7 +1296,7 @@ private function loadUsedProducts(\Magento\Catalog\Model\Product $product, $cach
if ($salableOnly) {
$collection = $this->salableProcessor->process($collection);
}
- $usedProducts = $collection->getItems();
+ $usedProducts = array_values($collection->getItems());
$this->saveUsedProductsCacheData($product, $usedProducts, $cacheKey);
}
$product->setData($dataFieldName, $usedProducts);
diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
index bee4479526037..016dca2fa526c 100644
--- a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
+++ b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
@@ -270,13 +270,29 @@ protected function _saveCustomerEntities(array $entitiesToCreate, array $entitie
$this->_connection->insertOnDuplicate(
$this->_entityTable,
$entitiesToUpdate,
- $this->customerFields
+ $this->getCustomerEntityFieldsToUpdate($entitiesToUpdate)
);
}
return $this;
}
+ /**
+ * Filter the entity that are being updated so we only change fields found in the importer file
+ *
+ * @param array $entitiesToUpdate
+ * @return array
+ */
+ private function getCustomerEntityFieldsToUpdate(array $entitiesToUpdate): array
+ {
+ $firstCustomer = reset($entitiesToUpdate);
+ $columnsToUpdate = array_keys($firstCustomer);
+ $customerFieldsToUpdate = array_filter($this->customerFields, function ($field) use ($columnsToUpdate) {
+ return in_array($field, $columnsToUpdate);
+ });
+ return $customerFieldsToUpdate;
+ }
+
/**
* Save customer attributes.
*
diff --git a/app/code/Magento/NewRelicReporting/Model/NewRelicWrapper.php b/app/code/Magento/NewRelicReporting/Model/NewRelicWrapper.php
index c4818c38cd9c6..845ed0429d2c3 100644
--- a/app/code/Magento/NewRelicReporting/Model/NewRelicWrapper.php
+++ b/app/code/Magento/NewRelicReporting/Model/NewRelicWrapper.php
@@ -28,6 +28,19 @@ public function addCustomParameter($param, $value)
return false;
}
+ /**
+ * Wrapper for 'newrelic_notice_error' function
+ *
+ * @param Exception $exception
+ * @return void
+ */
+ public function reportError($exception)
+ {
+ if (extension_loaded('newrelic')) {
+ newrelic_notice_error($exception->getMessage(), $exception);
+ }
+ }
+
/**
* Checks whether newrelic-php5 agent is installed
*
diff --git a/app/code/Magento/NewRelicReporting/Model/Observer/ReportApplicationHandledExceptionToNewRelic.php b/app/code/Magento/NewRelicReporting/Model/Observer/ReportApplicationHandledExceptionToNewRelic.php
new file mode 100644
index 0000000000000..724a488570207
--- /dev/null
+++ b/app/code/Magento/NewRelicReporting/Model/Observer/ReportApplicationHandledExceptionToNewRelic.php
@@ -0,0 +1,47 @@
+config = $config;
+ $this->newRelicWrapper = $newRelicWrapper;
+ }
+
+ public function execute(Observer $observer)
+ {
+ if ($this->config->isNewRelicEnabled()) {
+ $exception = $observer->getEvent()->getException();
+ $this->newRelicWrapper->reportError($exception);
+ }
+ }
+}
diff --git a/app/code/Magento/NewRelicReporting/Plugin/HttpPlugin.php b/app/code/Magento/NewRelicReporting/Plugin/HttpPlugin.php
new file mode 100644
index 0000000000000..a37d93329d43a
--- /dev/null
+++ b/app/code/Magento/NewRelicReporting/Plugin/HttpPlugin.php
@@ -0,0 +1,53 @@
+config = $config;
+ $this->newRelicWrapper = $newRelicWrapper;
+ }
+
+ /**
+ * Report exception to New Relic
+ *
+ * @param Http $subject
+ * @param Bootstrap $bootstrap
+ * @param \Exception $exception
+ * @return void
+ *
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeCatchException(Http $subject, Bootstrap $bootstrap, \Exception $exception)
+ {
+ if ($this->config->isNewRelicEnabled()) {
+ $this->newRelicWrapper->reportError($exception);
+ }
+ }
+}
diff --git a/app/code/Magento/NewRelicReporting/etc/di.xml b/app/code/Magento/NewRelicReporting/etc/di.xml
index a0d06105dd3fe..cba92f91cd4bb 100644
--- a/app/code/Magento/NewRelicReporting/etc/di.xml
+++ b/app/code/Magento/NewRelicReporting/etc/di.xml
@@ -27,4 +27,7 @@
+