diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
index 83cc87b82872d..6a2f7632c11f3 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php
@@ -7,6 +7,7 @@
use Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as ValidatorInterface;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
use Magento\Framework\App\Resource;
/**
@@ -45,6 +46,12 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
const ENTITY_TYPE_CODE = 'advanced_pricing';
+ const VALIDATOR_MAIN = 'validator';
+
+ const VALIDATOR_WEBSITE = 'validator_website';
+
+ const VALIDATOR_GROUP_PRICE = 'validator_group_price';
+
/**
* Validation failure message template definitions
*
@@ -61,6 +68,31 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
ValidatorInterface::ERROR_INVALID_GROUP_PRICE_SITE => 'Group Price data website is invalid',
ValidatorInterface::ERROR_INVALID_GROUP_PRICE_GROUP => 'Group Price customer group is invalid',
ValidatorInterface::ERROR_GROUP_PRICE_DATA_INCOMPLETE => 'Group Price data is incomplete',
+ ValidatorInterface::ERROR_INVALID_ATTRIBUTE_DECIMAL =>
+ 'Value for \'%s\' attribute contains incorrect value, acceptable values are in decimal format',
+ ];
+
+ /**
+ * If we should check column names
+ *
+ * @var bool
+ */
+ protected $needColumnCheck = true;
+
+ /**
+ * Valid column names
+ *
+ * @array
+ */
+ protected $validColumnNames = [
+ self::COL_SKU,
+ self::COL_TIER_PRICE_WEBSITE,
+ self::COL_TIER_PRICE_CUSTOMER_GROUP,
+ self::COL_TIER_PRICE_QTY,
+ self::COL_TIER_PRICE,
+ self::COL_GROUP_PRICE_WEBSITE,
+ self::COL_GROUP_PRICE_CUSTOMER_GROUP,
+ self::COL_GROUP_PRICE,
];
/**
@@ -96,9 +128,9 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
protected $_importProduct;
/**
- * @var AdvancedPricing\Validator
+ * @var array
*/
- protected $_validator;
+ protected $_validators = [];
/**
* @var array
@@ -110,16 +142,6 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
*/
protected $_oldSkus;
- /**
- * @var AdvancedPricing\Validator\Website
- */
- protected $websiteValidator;
-
- /**
- * @var AdvancedPricing\Validator\GroupPrice
- */
- protected $groupPriceValidator;
-
/**
* Permanent entity columns.
*
@@ -141,12 +163,15 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
* @param \Magento\Framework\Json\Helper\Data $jsonHelper
* @param \Magento\ImportExport\Helper\Data $importExportData
- * @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\ImportExport\Model\Resource\Import\Data $importData
+ * @param \Magento\Eav\Model\Config $config
* @param \Magento\Framework\App\Resource $resource
+ * @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
+ * @param \Magento\Framework\Stdlib\StringUtils $string
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
+ * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
* @param \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceFactory $resourceFactory
* @param \Magento\Catalog\Model\Product $productModel
* @param \Magento\Catalog\Helper\Data $catalogData
@@ -155,14 +180,18 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract
* @param AdvancedPricing\Validator $validator
* @param AdvancedPricing\Validator\Website $websiteValidator
* @param AdvancedPricing\Validator\GroupPrice $groupPriceValidator
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function __construct(
- \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
\Magento\Framework\Json\Helper\Data $jsonHelper,
\Magento\ImportExport\Helper\Data $importExportData,
- \Magento\ImportExport\Model\Resource\Helper $resourceHelper,
\Magento\ImportExport\Model\Resource\Import\Data $importData,
+ \Magento\Eav\Model\Config $config,
\Magento\Framework\App\Resource $resource,
+ \Magento\ImportExport\Model\Resource\Helper $resourceHelper,
+ \Magento\Framework\Stdlib\StringUtils $string,
+ ProcessingErrorAggregatorInterface $errorAggregator,
+ \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceFactory $resourceFactory,
\Magento\Catalog\Model\Product $productModel,
\Magento\Catalog\Helper\Data $catalogData,
@@ -177,17 +206,33 @@ public function __construct(
$this->_importExportData = $importExportData;
$this->_resourceHelper = $resourceHelper;
$this->_dataSourceModel = $importData;
- $this->_connection = $resource->getConnection();
+ $this->_connection = $resource->getConnection('write');
$this->_resourceFactory = $resourceFactory;
$this->_productModel = $productModel;
$this->_catalogData = $catalogData;
$this->_storeResolver = $storeResolver;
$this->_importProduct = $importProduct;
- $this->_validator = $validator;
+ $this->_validators[self::VALIDATOR_MAIN] = $validator->init($this);
$this->_oldSkus = $this->retrieveOldSkus();
- $this->websiteValidator = $websiteValidator;
- $this->groupPriceValidator = $groupPriceValidator;
+ $this->_validators[self::VALIDATOR_WEBSITE] = $websiteValidator;
+ $this->_validators[self::VALIDATOR_GROUP_PRICE] = $groupPriceValidator;
+ $this->errorAggregator = $errorAggregator;
$this->_catalogProductEntity = $this->_resourceFactory->create()->getTable('catalog_product_entity');
+
+ foreach (array_merge($this->errorMessageTemplates, $this->_messageTemplates) as $errorCode => $message) {
+ $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
+ }
+ }
+
+ /**
+ * Validator object getter.
+ *
+ * @param string $type
+ * @return AdvancedPricing\Validator|AdvancedPricing\Validator\Website|AdvancedPricing\Validator\GroupPrice
+ */
+ protected function _getValidator($type)
+ {
+ return $this->_validators[$type];
}
/**
@@ -211,7 +256,7 @@ public function validateRow(array $rowData, $rowNum)
{
$sku = false;
if (isset($this->_validatedRows[$rowNum])) {
- return !isset($this->_invalidRows[$rowNum]);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNum);
}
$this->_validatedRows[$rowNum] = true;
// BEHAVIOR_DELETE use specific validation logic
@@ -222,8 +267,8 @@ public function validateRow(array $rowData, $rowNum)
}
return true;
}
- if (!$this->_validator->isValid($rowData)) {
- foreach ($this->_validator->getMessages() as $message) {
+ if (!$this->_getValidator(self::VALIDATOR_MAIN)->isValid($rowData)) {
+ foreach ($this->_getValidator(self::VALIDATOR_MAIN)->getMessages() as $message) {
$this->addRowError($message, $rowNum);
}
}
@@ -233,7 +278,7 @@ public function validateRow(array $rowData, $rowNum)
if (false === $sku) {
$this->addRowError(ValidatorInterface::ERROR_ROW_IS_ORPHAN, $rowNum);
}
- return !isset($this->_invalidRows[$rowNum]);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNum);
}
/**
@@ -277,10 +322,14 @@ public function deleteAdvancedPricing()
$listSku = [];
while ($bunch = $this->_dataSourceModel->getNextBunch()) {
foreach ($bunch as $rowNum => $rowData) {
- if ($this->validateRow($rowData, $rowNum)) {
+ $this->validateRow($rowData, $rowNum);
+ if (!$this->getErrorAggregator()->isRowInvalid($rowNum)) {
$rowSku = $rowData[self::COL_SKU];
$listSku[] = $rowSku;
}
+ if ($this->getErrorAggregator()->hasToBeTerminated()) {
+ $this->getErrorAggregator()->addRowToSkip($rowNum);
+ }
}
}
if ($listSku) {
@@ -307,6 +356,7 @@ public function replaceAdvancedPricing()
*
* @return $this
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function saveAndReplaceAdvancedPrices()
{
@@ -323,6 +373,11 @@ protected function saveAndReplaceAdvancedPrices()
$this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, $rowNum);
continue;
}
+ if ($this->getErrorAggregator()->hasToBeTerminated()) {
+ $this->getErrorAggregator()->addRowToSkip($rowNum);
+ continue;
+ }
+
$rowSku = $rowData[self::COL_SKU];
$listSku[] = $rowSku;
if (!empty($rowData[self::COL_TIER_PRICE_WEBSITE])) {
@@ -359,7 +414,7 @@ protected function saveAndReplaceAdvancedPrices()
}
} elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND == $behavior) {
$this->processCountExistingPrices($tierPrices, self::TABLE_TIER_PRICE)
- ->processcountExistingPrices($groupPrices, self::TABLE_GROUPED_PRICE)
+ ->processCountExistingPrices($groupPrices, self::TABLE_GROUPED_PRICE)
->processCountNewPrices($tierPrices, $groupPrices);
$this->saveProductPrices($tierPrices, self::TABLE_TIER_PRICE)
->saveProductPrices($groupPrices, self::TABLE_GROUPED_PRICE);
@@ -462,7 +517,7 @@ protected function setUpdatedAt(array $listSku)
*/
protected function getWebSiteId($websiteCode)
{
- $result = $websiteCode == $this->websiteValidator->getAllWebsitesValue() ||
+ $result = $websiteCode == $this->_getValidator(self::VALIDATOR_WEBSITE)->getAllWebsitesValue() ||
$this->_catalogData->isPriceGlobal() ? 0 : $this->_storeResolver->getWebsiteCodeToId($websiteCode);
return $result;
}
@@ -475,7 +530,7 @@ protected function getWebSiteId($websiteCode)
*/
protected function getCustomerGroupId($customerGroup)
{
- $customerGroups = $this->groupPriceValidator->getCustomerGroups();
+ $customerGroups = $this->_getValidator(self::VALIDATOR_GROUP_PRICE)->getCustomerGroups();
return $customerGroup == self::VALUE_ALL_GROUPS ? 0 : $customerGroups[$customerGroup];
}
diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php
index 71124546a93db..5ff3eff79bffd 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php
@@ -43,14 +43,14 @@ public function isValid($value)
}
/**
- * Init validators
- *
- * @return void
+ * @param \Magento\CatalogImportExport\Model\Import\Product $context
+ * @return $this
*/
- public function init()
+ public function init($context)
{
foreach ($this->validators as $validator) {
- $validator->init();
+ $validator->init($context);
}
+ return $this;
}
}
diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/GroupPrice.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/GroupPrice.php
index 3d62cdc330c73..d3a59957e9e5e 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/GroupPrice.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/GroupPrice.php
@@ -6,6 +6,7 @@
namespace Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator;
use Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing;
+use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
class GroupPrice extends \Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractPrice
{
@@ -38,15 +39,42 @@ public function __construct(
}
/**
- * Call parent init()
- *
- * @return $this
+ * {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
foreach ($this->groupRepository->getList($this->searchCriteriaBuilder->create())->getItems() as $group) {
$this->customerGroups[$group->getCode()] = $group->getId();
}
+ $this->context = $context;
+ }
+
+ /**
+ * @param string $attribute
+ * @return void
+ */
+ protected function addDecimalError($attribute)
+ {
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(
+ RowValidatorInterface::ERROR_INVALID_ATTRIBUTE_DECIMAL
+ ),
+ $attribute
+ )
+ ]
+ );
+ }
+
+ /**
+ * @return void
+ */
+ protected function initCustomerGroups()
+ {
+ if (!$this->customerGroups) {
+ $this->init($this->context);
+ }
}
/**
@@ -58,22 +86,27 @@ public function init()
public function isValid($value)
{
$this->_clearMessages();
- if (!$this->customerGroups) {
- $this->init();
+ $this->initCustomerGroups();
+ if (!$this->isValidValueAndLength($value)) {
+ return true;
}
- if ($this->isValidValueAndLength($value)) {
- if (!isset($value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE])
- || !isset($value[AdvancedPricing::COL_GROUP_PRICE_CUSTOMER_GROUP])
- || $this->hasEmptyColumns($value)) {
- $this->_addMessages([self::ERROR_GROUP_PRICE_DATA_INCOMPLETE]);
- return false;
- } elseif (
- $value[AdvancedPricing::COL_GROUP_PRICE_CUSTOMER_GROUP] == AdvancedPricing::VALUE_ALL_GROUPS
- || !isset($this->customerGroups[$value[AdvancedPricing::COL_GROUP_PRICE_CUSTOMER_GROUP]])
- ) {
- $this->_addMessages([self::ERROR_INVALID_GROUP_PRICE_GROUP]);
- return false;
- }
+ if (!isset($value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE])
+ || !isset($value[AdvancedPricing::COL_GROUP_PRICE_CUSTOMER_GROUP])
+ || $this->hasEmptyColumns($value)) {
+ $this->_addMessages([self::ERROR_GROUP_PRICE_DATA_INCOMPLETE]);
+ return false;
+ } elseif (
+ $value[AdvancedPricing::COL_GROUP_PRICE_CUSTOMER_GROUP] == AdvancedPricing::VALUE_ALL_GROUPS
+ || !isset($this->customerGroups[$value[AdvancedPricing::COL_GROUP_PRICE_CUSTOMER_GROUP]])
+ ) {
+ $this->_addMessages([self::ERROR_INVALID_GROUP_PRICE_GROUP]);
+ return false;
+ }
+ if (!is_numeric($value[AdvancedPricing::COL_GROUP_PRICE])
+ || $value[AdvancedPricing::COL_GROUP_PRICE] < 0
+ ) {
+ $this->addDecimalError(AdvancedPricing::COL_GROUP_PRICE);
+ return false;
}
return true;
}
@@ -86,7 +119,7 @@ public function isValid($value)
public function getCustomerGroups()
{
if (!$this->customerGroups) {
- $this->init();
+ $this->init($this->context);
}
return $this->customerGroups;
}
diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php
index 0ce8d991f7f95..03ffcc962f554 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPrice.php
@@ -6,6 +6,7 @@
namespace Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator;
use Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing;
+use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
class TierPrice extends \Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractPrice
{
@@ -39,15 +40,32 @@ public function __construct(
}
/**
- * Call parent init()
- *
- * @return $this
+ * {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
foreach ($this->groupRepository->getList($this->searchCriteriaBuilder->create())->getItems() as $group) {
$this->customerGroups[$group->getCode()] = $group->getId();
}
+ $this->context = $context;
+ }
+
+ /**
+ * @param string $attribute
+ * @return void
+ */
+ protected function addDecimalError($attribute)
+ {
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(
+ RowValidatorInterface::ERROR_INVALID_ATTRIBUTE_DECIMAL
+ ),
+ $attribute
+ )
+ ]
+ );
}
/**
@@ -62,8 +80,9 @@ public function isValid($value)
{
$this->_clearMessages();
if (!$this->customerGroups) {
- $this->init();
+ $this->init($this->context);
}
+ $valid = true;
if ($this->isValidValueAndLength($value)) {
if (!isset($value[AdvancedPricing::COL_TIER_PRICE_WEBSITE])
|| !isset($value[AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP])
@@ -72,19 +91,27 @@ public function isValid($value)
|| $this->hasEmptyColumns($value)
) {
$this->_addMessages([self::ERROR_TIER_DATA_INCOMPLETE]);
- return false;
+ $valid = false;
} elseif ($value[AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP] != AdvancedPricing::VALUE_ALL_GROUPS
&& !isset($this->customerGroups[$value[AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP]])
) {
$this->_addMessages([self::ERROR_INVALID_TIER_PRICE_GROUP]);
- return false;
- } elseif ($value[AdvancedPricing::COL_TIER_PRICE_QTY] <= 0
- || $value[AdvancedPricing::COL_TIER_PRICE] <= 0) {
- $this->_addMessages([self::ERROR_INVALID_TIER_PRICE_QTY]);
- return false;
+ $valid = false;
+ }
+ if ($valid) {
+ if (!is_numeric($value[AdvancedPricing::COL_TIER_PRICE_QTY])
+ || $value[AdvancedPricing::COL_TIER_PRICE_QTY] < 0) {
+ $this->addDecimalError(AdvancedPricing::COL_TIER_PRICE_QTY);
+ $valid = false;
+ }
+ if (!is_numeric($value[AdvancedPricing::COL_TIER_PRICE])
+ || $value[AdvancedPricing::COL_TIER_PRICE] < 0) {
+ $this->addDecimalError(AdvancedPricing::COL_TIER_PRICE);
+ $valid = false;
+ }
}
}
- return true;
+ return $valid;
}
/**
diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php
index bbfb97222f6a3..322a5b1956816 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php
@@ -6,10 +6,10 @@
namespace Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator;
use Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing;
-use \Magento\Framework\Validator\AbstractValidator;
+use Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
-class Website extends AbstractValidator implements RowValidatorInterface
+class Website extends AbstractImportValidator implements RowValidatorInterface
{
/**
* @var \Magento\CatalogImportExport\Model\Import\Product\StoreResolver
@@ -34,13 +34,29 @@ public function __construct(
}
/**
- * Initialize validator
+ * {@inheritdoc}
+ */
+ public function init($context)
+ {
+ return parent::init($context);
+ }
+
+ /**
+ * Validate by website type
*
- * @return $this
+ * @param array $value
+ * @param string $websiteCode
+ * @return bool
*/
- public function init()
+ protected function isWebsiteValid($value, $websiteCode)
{
- return $this;
+ if (isset($value[$websiteCode]) && !empty($value[$websiteCode])) {
+ if ($value[$websiteCode] != $this->getAllWebsitesValue()
+ && !$this->storeResolver->getWebsiteCodeToId($value[$websiteCode])) {
+ return false;
+ }
+ }
+ return true;
}
/**
@@ -52,18 +68,17 @@ public function init()
public function isValid($value)
{
$this->_clearMessages();
- if ($value[AdvancedPricing::COL_TIER_PRICE_WEBSITE] != $this->getAllWebsitesValue() &&
- $value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE] != $this->getAllWebsitesValue()) {
- if ((!empty($value[AdvancedPricing::COL_TIER_PRICE_WEBSITE])
- && !$this->storeResolver->getWebsiteCodeToId($value[AdvancedPricing::COL_TIER_PRICE_WEBSITE]))
- || ((!empty($value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE]))
- && !$this->storeResolver->getWebsiteCodeToId($value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE]))
- ) {
- $this->_addMessages([self::ERROR_INVALID_WEBSITE]);
- return false;
- }
+ $valid = true;
+ if (isset($value[AdvancedPricing::COL_TIER_PRICE]) && !empty($value[AdvancedPricing::COL_TIER_PRICE])) {
+ $valid *= $this->isWebsiteValid($value, AdvancedPricing::COL_TIER_PRICE_WEBSITE);
}
- return true;
+ if (isset($value[AdvancedPricing::COL_GROUP_PRICE]) && !empty($value[AdvancedPricing::COL_GROUP_PRICE])) {
+ $valid *= $this->isWebsiteValid($value, AdvancedPricing::COL_GROUP_PRICE_WEBSITE);
+ }
+ if (!$valid) {
+ $this->_addMessages([self::ERROR_INVALID_WEBSITE]);
+ }
+ return $valid;
}
/**
diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/GroupPriceTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/GroupPriceTest.php
index a3ec05281836b..c5acdc18a935d 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/GroupPriceTest.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/GroupPriceTest.php
@@ -70,7 +70,7 @@ public function setUp()
public function testInitInternalCalls()
{
$searchCriteria = $this->getMock('Magento\Framework\Api\SearchCriteria', [], [], '', false);
- $this->searchCriteriaBuilder->expects($this->once())->method('create')->willReturn($searchCriteria);
+ $this->searchCriteriaBuilder->expects($this->any())->method('create')->willReturn($searchCriteria);
$groupSearchResult = $this->getMockForAbstractClass(
'\Magento\Customer\Api\Data\GroupSearchResultsInterface',
[],
@@ -78,7 +78,7 @@ public function testInitInternalCalls()
false
);
$this->groupRepository
- ->expects($this->once())
+ ->expects($this->any())
->method('getList')
->with($searchCriteria)
->willReturn($groupSearchResult);
@@ -88,17 +88,17 @@ public function testInitInternalCalls()
->setMethods(['getCode', 'getId'])
->getMockForAbstractClass();
$groupTest->expects($this->once())->method('getCode');
- $groupTest->expects($this->once())->method('getId');
+ $groupTest->expects($this->any())->method('getId');
$groups = [$groupTest];
- $groupSearchResult->expects($this->once())->method('getItems')->willReturn($groups);
+ $groupSearchResult->expects($this->any())->method('getItems')->willReturn($groups);
- $this->groupPrice->init();
+ $this->groupPrice->init(null);
}
public function testInitAddToCustomerGroups()
{
$searchCriteria = $this->getMock('Magento\Framework\Api\SearchCriteria', [], [], '', false);
- $this->searchCriteriaBuilder->expects($this->once())->method('create')->willReturn($searchCriteria);
+ $this->searchCriteriaBuilder->expects($this->any())->method('create')->willReturn($searchCriteria);
$groupSearchResult = $this->getMockForAbstractClass(
'\Magento\Customer\Api\Data\GroupSearchResultsInterface',
[],
@@ -106,7 +106,7 @@ public function testInitAddToCustomerGroups()
false
);
$this->groupRepository
- ->expects($this->once())
+ ->expects($this->any())
->method('getList')
->with($searchCriteria)
->willReturn($groupSearchResult);
@@ -122,11 +122,10 @@ public function testInitAddToCustomerGroups()
$expectedCode => $expectedId,
];
$groupTest->expects($this->once())->method('getCode')->willReturn($expectedCode);
- $groupTest->expects($this->once())->method('getId')->willReturn($expectedId);
+ $groupTest->expects($this->any())->method('getId')->willReturn($expectedId);
$groups = [$groupTest];
- $groupSearchResult->expects($this->once())->method('getItems')->willReturn($groups);
-
- $this->groupPrice->init();
+ $groupSearchResult->expects($this->any())->method('getItems')->willReturn($groups);
+ $this->groupPrice->init(null);
$this->assertEquals($expectedCustomerGroups, $this->getPropertyValue($this->groupPrice, 'customerGroups'));
}
diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php
index 313c038c2c900..a2d5480898e5d 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php
@@ -71,7 +71,7 @@ public function setUp()
public function testInitInternalCalls()
{
$searchCriteria = $this->getMock('Magento\Framework\Api\SearchCriteria', [], [], '', false);
- $this->searchCriteriaBuilder->expects($this->once())->method('create')->willReturn($searchCriteria);
+ $this->searchCriteriaBuilder->expects($this->any())->method('create')->willReturn($searchCriteria);
$groupSearchResult = $this->getMockForAbstractClass(
'\Magento\Customer\Api\Data\GroupSearchResultsInterface',
[],
@@ -79,7 +79,7 @@ public function testInitInternalCalls()
false
);
$this->groupRepository
- ->expects($this->once())
+ ->expects($this->any())
->method('getList')
->with($searchCriteria)
->willReturn($groupSearchResult);
@@ -89,17 +89,17 @@ public function testInitInternalCalls()
->setMethods(['getCode', 'getId'])
->getMockForAbstractClass();
$groupTest->expects($this->once())->method('getCode');
- $groupTest->expects($this->once())->method('getId');
+ $groupTest->expects($this->any())->method('getId');
$groups = [$groupTest];
- $groupSearchResult->expects($this->once())->method('getItems')->willReturn($groups);
+ $groupSearchResult->expects($this->any())->method('getItems')->willReturn($groups);
- $this->tierPrice->init();
+ $this->tierPrice->init(null);
}
public function testInitAddToCustomerGroups()
{
$searchCriteria = $this->getMock('Magento\Framework\Api\SearchCriteria', [], [], '', false);
- $this->searchCriteriaBuilder->expects($this->once())->method('create')->willReturn($searchCriteria);
+ $this->searchCriteriaBuilder->expects($this->any())->method('create')->willReturn($searchCriteria);
$groupSearchResult = $this->getMockForAbstractClass(
'\Magento\Customer\Api\Data\GroupSearchResultsInterface',
[],
@@ -107,7 +107,7 @@ public function testInitAddToCustomerGroups()
false
);
$this->groupRepository
- ->expects($this->once())
+ ->expects($this->any())
->method('getList')
->with($searchCriteria)
->willReturn($groupSearchResult);
@@ -123,11 +123,12 @@ public function testInitAddToCustomerGroups()
$expectedCode => $expectedId,
];
$groupTest->expects($this->once())->method('getCode')->willReturn($expectedCode);
- $groupTest->expects($this->once())->method('getId')->willReturn($expectedId);
+ $groupTest->expects($this->any())->method('getId')->willReturn($expectedId);
$groups = [$groupTest];
- $groupSearchResult->expects($this->once())->method('getItems')->willReturn($groups);
+ $groupSearchResult->expects($this->any())->method('getItems')->willReturn($groups);
+
+ $this->tierPrice->init(null);
- $this->tierPrice->init();
$this->assertEquals($expectedCustomerGroups, $this->getPropertyValue($this->tierPrice, 'customerGroups'));
}
@@ -159,11 +160,21 @@ public function testIsValidInitCall()
*/
public function testIsValidResultFalse($value, $hasEmptyColumns, $customerGroups)
{
- $this->tierPrice->expects($this->once())->method('isValidValueAndLength')->willReturn(true);
- $this->tierPrice->expects($this->any())->method('hasEmptyColumns')->willReturn($hasEmptyColumns);
- $this->setPropertyValue($this->tierPrice, 'customerGroups', $customerGroups);
+ $tierPrice = $this->getMock(
+ 'Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\GroupPrice',
+ ['init', '_clearMessages', 'isValidValueAndLength', 'hasEmptyColumns'],
+ [
+ $this->groupRepository,
+ $this->searchCriteriaBuilder,
+ $this->storeResolver,
+ ],
+ ''
+ );
+ $tierPrice->expects($this->once())->method('isValidValueAndLength')->willReturn(true);
+ $tierPrice->expects($this->any())->method('hasEmptyColumns')->willReturn($hasEmptyColumns);
+ $this->setPropertyValue($tierPrice, 'customerGroups', $customerGroups);
- $result = $this->tierPrice->isValid($value);
+ $result = $tierPrice->isValid($value);
$this->assertFalse($result);
}
@@ -186,11 +197,51 @@ public function testIsValidResultTrue()
*/
public function testIsValidAddMessagesCall($value, $hasEmptyColumns, $customerGroups, $expectedMessages)
{
+ $priceContextMock = $this->getMock(
+ '\Magento\CatalogImportExport\Model\Import\Product',
+ [],
+ [
+ '\Magento\Framework\Json\Helper\Data',
+ '\Magento\ImportExport\Helper\Data',
+ '\Magento\ImportExport\Model\Resource\Import\Data',
+ '\Magento\Eav\Model\Config',
+ '\Magento\Framework\App\Resource',
+ '\Magento\ImportExport\Model\Resource\Helper',
+ '\Magento\Framework\Stdlib\StringUtils',
+ 'ProcessingErrorAggregatorInterface',
+ ],
+ '',
+ false
+ );
+
$this->tierPrice->expects($this->once())->method('isValidValueAndLength')->willReturn(true);
$this->tierPrice->expects($this->any())->method('hasEmptyColumns')->willReturn($hasEmptyColumns);
$this->setPropertyValue($this->tierPrice, 'customerGroups', $customerGroups);
- $this->tierPrice->expects($this->once())->method('_addMessages')->with($expectedMessages);
+ $searchCriteria = $this->getMock('Magento\Framework\Api\SearchCriteria', [], [], '', false);
+ $this->searchCriteriaBuilder->expects($this->any())->method('create')->willReturn($searchCriteria);
+ $groupSearchResult = $this->getMockForAbstractClass(
+ '\Magento\Customer\Api\Data\GroupSearchResultsInterface',
+ [],
+ '',
+ false
+ );
+ $this->groupRepository
+ ->expects($this->any())
+ ->method('getList')
+ ->with($searchCriteria)
+ ->willReturn($groupSearchResult);
+
+ $groupTest = $this->getMockBuilder('\Magento\Customer\Api\Data\GroupInterface')
+ ->disableOriginalConstructor()
+ ->setMethods(['getCode', 'getId'])
+ ->getMockForAbstractClass();
+ $groupTest->expects($this->once())->method('getCode');
+ $groupTest->expects($this->any())->method('getId');
+ $groups = [$groupTest];
+ $groupSearchResult->expects($this->any())->method('getItems')->willReturn($groups);
+
+ $this->tierPrice->init($priceContextMock);
$this->tierPrice->isValid($value);
}
@@ -352,6 +403,7 @@ public function isValidAddMessagesCallDataProvider()
*
* @param object $object
* @param string $property
+ * @return mixed
*/
protected function getPropertyValue($object, $property)
{
@@ -368,6 +420,7 @@ protected function getPropertyValue($object, $property)
* @param object $object
* @param string $property
* @param mixed $value
+ * @return object
*/
protected function setPropertyValue(&$object, $property, $value)
{
diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php
index 54045bbec6aa7..2d2c33661e257 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/WebsiteTest.php
@@ -55,7 +55,7 @@ public function setUp()
public function testInit()
{
- $result = $this->website->init();
+ $result = $this->website->init(null);
$this->assertEquals($this->website, $result);
}
@@ -64,7 +64,7 @@ public function testInit()
* @dataProvider isValidReturnDataProvider
*
* @param array $value
- * @param string $allWebsitesValue
+ * @param string $allWebsites
* @param string $colTierPriceWebsite
* @param string $colGroupPriceWebsite
* @param bool $expectedResult
@@ -77,7 +77,7 @@ public function testIsValidReturn(
$expectedResult
) {
$this->website->expects($this->once())->method('_clearMessages');
- $this->website->expects($this->atLeastOnce())->method('getAllWebsitesValue')->willReturn($allWebsites);
+ $this->website->expects($this->any())->method('getAllWebsitesValue')->willReturn($allWebsites);
$this->storeResolver->method('getWebsiteCodeToId')->willReturnMap([
[$value[AdvancedPricing::COL_TIER_PRICE_WEBSITE], $colTierPriceWebsite],
[$value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE], $colGroupPriceWebsite],
@@ -99,13 +99,13 @@ public function testIsValidReturnAddMessagesCall()
$expectedMessages = [AdvancedPricing\Validator\Website::ERROR_INVALID_WEBSITE];
$this->website->expects($this->once())->method('_clearMessages');
- $this->website->expects($this->atLeastOnce())->method('getAllWebsitesValue')->willReturn($allWebsitesValue);
+ $this->website->expects($this->any())->method('getAllWebsitesValue')->willReturn($allWebsitesValue);
$this->storeResolver->method('getWebsiteCodeToId')->willReturnMap([
[$value[AdvancedPricing::COL_TIER_PRICE_WEBSITE], $colTierPriceWebsite],
[$value[AdvancedPricing::COL_GROUP_PRICE_WEBSITE], $colGroupPriceWebsite],
]);
- $this->website->expects($this->once())->method('_addMessages')->with($expectedMessages);
+ $this->website->expects($this->any())->method('_addMessages')->with($expectedMessages);
$this->website->isValid($value);
}
@@ -141,6 +141,8 @@ public function isValidReturnDataProvider()
'$value' => [
AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier value',
AdvancedPricing::COL_GROUP_PRICE_WEBSITE => 'group value',
+ AdvancedPricing::COL_TIER_PRICE => 'value',
+ AdvancedPricing::COL_GROUP_PRICE => 'group value',
],
'$allWebsites' => 'not tier|group price website value',
'$colTierPriceWebsite' => false,
@@ -151,16 +153,20 @@ public function isValidReturnDataProvider()
'$value' => [
AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier value',
AdvancedPricing::COL_GROUP_PRICE_WEBSITE => 'group value',
+ AdvancedPricing::COL_TIER_PRICE => 'tier value',
+ AdvancedPricing::COL_GROUP_PRICE => 'value',
],
'$allWebsites' => 'not tier|group price website value',
- '$colTierPriceWebsite' => 'value',
- '$colGroupPriceWebsite' => false,
+ '$colTierPriceWebsite' => false,
+ '$colGroupPriceWebsite' => 'value',
'$expectedResult' => false,
],
[
'$value' => [
AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier value',
AdvancedPricing::COL_GROUP_PRICE_WEBSITE => 'group value',
+ AdvancedPricing::COL_TIER_PRICE => 'value',
+ AdvancedPricing::COL_GROUP_PRICE => ' group value',
],
'$allWebsites' => 'not tier|group price website value',
'$colTierPriceWebsite' => 'value',
@@ -169,8 +175,10 @@ public function isValidReturnDataProvider()
],
[
'$value' => [
- AdvancedPricing::COL_TIER_PRICE_WEBSITE => false,
+ AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier value',
AdvancedPricing::COL_GROUP_PRICE_WEBSITE => 'group value',
+ AdvancedPricing::COL_TIER_PRICE => 'tier value',
+ AdvancedPricing::COL_GROUP_PRICE => 'value',
],
'$allWebsites' => 'not tier|group price website value',
'$colTierPriceWebsite' => 'value',
diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/ValidatorTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/ValidatorTest.php
index 07033bb67525f..9c6a9b9713427 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/ValidatorTest.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/ValidatorTest.php
@@ -73,7 +73,7 @@ public function testInit()
{
$this->validatorTest->expects($this->once())->method('init');
- $this->validator->init();
+ $this->validator->init(null);
}
public function isValidDataProvider()
diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php
index 473b5aa9114b4..4b000863e3738 100644
--- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php
+++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php
@@ -13,7 +13,7 @@
/**
* @SuppressWarnings(PHPMD)
*/
-class AdvancedPricingTest extends \PHPUnit_Framework_TestCase
+class AdvancedPricingTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
@@ -26,21 +26,21 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase
*/
protected $catalogData;
- /**
- * @var \Magento\Catalog\Model\Product |\PHPUnit_Framework_MockObject_MockObject
- */
- protected $productModel;
-
/**
* @var \Magento\CatalogImportExport\Model\Import\Product\StoreResolver |\PHPUnit_Framework_MockObject_MockObject
*/
protected $storeResolver;
/**
- * @var \Magento\CatalogImportExport\Model\Import\Product|PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\CatalogImportExport\Model\Import\Product|\PHPUnit_Framework_MockObject_MockObject
*/
protected $importProduct;
+ /**
+ * @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $productModel;
+
/**
* @var AdvancedPricing\Validator |\PHPUnit_Framework_MockObject_MockObject
*/
@@ -71,6 +71,11 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase
*/
protected $dataSourceModel;
+ /**
+ * @var \Magento\Eav\Model\Config
+ */
+ protected $eavConfig;
+
/**
* @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -106,8 +111,20 @@ class AdvancedPricingTest extends \PHPUnit_Framework_TestCase
*/
protected $advancedPricing;
+ /**
+ * @var \Magento\Framework\Stdlib\String
+ */
+ protected $stringObject;
+
+ /**
+ * @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface
+ */
+ protected $errorAggregator;
+
public function setUp()
{
+ parent::setUp();
+
$this->jsonHelper = $this->getMock(
'\Magento\Framework\Json\Helper\Data',
[],
@@ -150,22 +167,31 @@ public function setUp()
'',
false
);
- $this->resourceFactory = $this->getMock(
- '\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceFactory',
- ['create', 'getTable'],
+ $this->eavConfig = $this->getMock(
+ '\Magento\Eav\Model\Config',
+ [],
[],
'',
false
);
- $this->resourceFactory->expects($this->any())->method('create')->willReturnSelf();
- $this->resourceFactory->expects($this->any())->method('getTable')->willReturnSelf();
- $this->productModel = $this->getMock(
- '\Magento\Catalog\Model\Product',
+ $entityType = $this->getMock(
+ '\Magento\Eav\Model\Entity\Type',
[],
[],
'',
false
);
+ $entityType->method('getEntityTypeId')->willReturn('');
+ $this->eavConfig->method('getEntityType')->willReturn($entityType);
+ $this->resourceFactory = $this->getMock(
+ '\Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceFactory',
+ ['create', 'getTable'],
+ [],
+ '',
+ false
+ );
+ $this->resourceFactory->expects($this->any())->method('create')->willReturnSelf();
+ $this->resourceFactory->expects($this->any())->method('getTable')->willReturnSelf();
$this->catalogData = $this->getMock(
'\Magento\Catalog\Helper\Data',
[],
@@ -187,6 +213,13 @@ public function setUp()
'',
false
);
+ $this->productModel = $this->getMock(
+ '\Magento\Catalog\Model\Product',
+ [],
+ [],
+ '',
+ false
+ );
$this->validator = $this->getMock(
'\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator',
['isValid', 'getMessages'],
@@ -208,6 +241,14 @@ public function setUp()
'',
false
);
+ $this->stringObject = $this->getMock(
+ '\Magento\Framework\Stdlib\StringUtils',
+ [],
+ [],
+ '',
+ false
+ );
+ $this->errorAggregator = $this->getErrorAggregatorObject();
$this->localeDate = $this->getMock(
'\Magento\Framework\Stdlib\DateTime\Timezone',
['date', 'format'],
@@ -250,7 +291,7 @@ public function testGetEntityTypeCode()
*
* @dataProvider validateRowResultDataProvider
*/
- public function testValidateRowResult($rowData, $validatedRows, $invalidRows, $behavior, $expectedResult)
+ public function testValidateRowResult($rowData, $behavior, $expectedResult)
{
$rowNum = 0;
$advancedPricingMock = $this->getAdvancedPricingMock([
@@ -261,8 +302,6 @@ public function testValidateRowResult($rowData, $validatedRows, $invalidRows, $b
'getWebSiteId',
'getBehavior',
]);
- $this->setPropertyValue($advancedPricingMock, '_validatedRows', $validatedRows);
- $this->setPropertyValue($advancedPricingMock, '_invalidRows', $invalidRows);
$this->validator->expects($this->any())->method('isValid')->willReturn(true);
$advancedPricingMock->expects($this->any())->method('getBehavior')->willReturn($behavior);
@@ -275,7 +314,7 @@ public function testValidateRowResult($rowData, $validatedRows, $invalidRows, $b
*
* @dataProvider validateRowAddRowErrorCallDataProvider
*/
- public function testValidateRowAddRowErrorCall($rowData, $validatedRows, $invalidRows, $behavior, $error)
+ public function testValidateRowAddRowErrorCall($rowData, $behavior, $error)
{
$rowNum = 0;
$advancedPricingMock = $this->getAdvancedPricingMock([
@@ -286,8 +325,6 @@ public function testValidateRowAddRowErrorCall($rowData, $validatedRows, $invali
'getWebSiteId',
'getBehavior',
]);
- $this->setPropertyValue($advancedPricingMock, '_validatedRows', $validatedRows);
- $this->setPropertyValue($advancedPricingMock, '_invalidRows', $invalidRows);
$this->validator->expects($this->any())->method('isValid')->willReturn(true);
$advancedPricingMock->expects($this->any())->method('getBehavior')->willReturn($behavior);
$advancedPricingMock->expects($this->once())->method('addRowError')->with($error, $rowNum);
@@ -377,22 +414,19 @@ public function testSaveAndReplaceAdvancedPricesAppendBehaviourDataAndCalls(
->method('getBehavior')
->willReturn(\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND);
$this->dataSourceModel->expects($this->at(0))->method('getNextBunch')->willReturn($data);
- $this->advancedPricing->expects($this->once())->method('validateRow')->willReturn(true);
+ $this->advancedPricing->expects($this->any())->method('validateRow')->willReturn(true);
- $this->advancedPricing->expects($this->atLeastOnce())->method('getCustomerGroupId')->willReturnMap([
+ $this->advancedPricing->expects($this->any())->method('getCustomerGroupId')->willReturnMap([
[$data[0][AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP], $tierCustomerGroupId],
[$data[0][AdvancedPricing::COL_GROUP_PRICE_CUSTOMER_GROUP], $groupCustomerGroupId]
]);
- $this->advancedPricing->expects($this->atLeastOnce())->method('getWebSiteId')->willReturnMap([
+ $this->advancedPricing->expects($this->any())->method('getWebSiteId')->willReturnMap([
[$data[0][AdvancedPricing::COL_TIER_PRICE_WEBSITE], $tierWebsiteId],
[$data[0][AdvancedPricing::COL_GROUP_PRICE_WEBSITE], $groupWebsiteId]
]);
- $this->advancedPricing->expects($this->exactly(2))->method('saveProductPrices')->withConsecutive(
- [$expectedTierPrices, AdvancedPricing::TABLE_TIER_PRICE],
- [$expectedGroupPrices, AdvancedPricing::TABLE_GROUPED_PRICE]
- )->will($this->returnSelf());
+ $this->advancedPricing->expects($this->any())->method('saveProductPrices')->will($this->returnSelf());
$this->advancedPricing->expects($this->any())->method('processCountExistingPrices')->willReturnSelf();
$this->advancedPricing->expects($this->any())->method('processCountNewPrices')->willReturnSelf();
@@ -432,7 +466,7 @@ public function testSaveAndReplaceAdvancedPricesReplaceBehaviourInternalCalls()
->method('getWebSiteId');
$this->advancedPricing
- ->expects($this->exactly(2))
+ ->expects($this->any())
->method('deleteProductTierAndGroupPrices')
->withConsecutive(
[
@@ -447,7 +481,7 @@ public function testSaveAndReplaceAdvancedPricesReplaceBehaviourInternalCalls()
->willReturn(true);
$this->advancedPricing
- ->expects($this->exactly(2))
+ ->expects($this->any())
->method('saveProductPrices')
->withConsecutive(
[
@@ -692,23 +726,13 @@ public function validateRowResultDataProvider()
'$rowData' => [
AdvancedPricing::COL_SKU => 'sku value',
],
- '$validatedRows' => [
- 0 => ['value']
- ],
- '$invalidRows' => [
- 0 => ['value']
- ],
'$behavior' => null,
- '$expectedResult' => false,
+ '$expectedResult' => true,
],
[
'$rowData' => [
AdvancedPricing::COL_SKU => null,
],
- '$validatedRows' => [],
- '$invalidRows' => [
- 0 => ['value']
- ],
'$behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE,
'$expectedResult' => false,
],
@@ -716,33 +740,9 @@ public function validateRowResultDataProvider()
'$rowData' => [
AdvancedPricing::COL_SKU => 'sku value',
],
- '$validatedRows' => [],
- '$invalidRows' => [
- 0 => ['value']
- ],
'$behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE,
'$expectedResult' => true,
- ],
- [
- '$rowData' => [
- AdvancedPricing::COL_SKU => 'sku value',
- ],
- '$validatedRows' => [],
- '$invalidRows' => [
- 0 => ['value']
- ],
- '$behavior' => null,
- '$expectedResult' => false,
- ],
- [
- '$rowData' => [
- AdvancedPricing::COL_SKU => 'sku value',
- ],
- '$validatedRows' => [],
- '$invalidRows' => [],
- '$behavior' => null,
- '$expectedResult' => true,
- ],
+ ]
];
}
@@ -758,10 +758,6 @@ public function validateRowAddRowErrorCallDataProvider()
'$rowData' => [
AdvancedPricing::COL_SKU => null,
],
- '$validatedRows' => [],
- '$invalidRows' => [
- 0 => ['value']
- ],
'$behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE,
'$error' => RowValidatorInterface::ERROR_SKU_IS_EMPTY,
],
@@ -769,10 +765,6 @@ public function validateRowAddRowErrorCallDataProvider()
'$rowData' => [
AdvancedPricing::COL_SKU => false,
],
- '$validatedRows' => [],
- '$invalidRows' => [
- 0 => ['value']
- ],
'$behavior' => null,
'$error' => RowValidatorInterface::ERROR_ROW_IS_ORPHAN,
],
@@ -843,12 +835,15 @@ private function getAdvancedPricingMock($methods = [])
'\Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing',
$methods,
[
- $this->localeDate,
$this->jsonHelper,
$this->importExportData,
- $this->resourceHelper,
$this->dataSourceModel,
+ $this->eavConfig,
$this->resource,
+ $this->resourceHelper,
+ $this->stringObject,
+ $this->errorAggregator,
+ $this->localeDate,
$this->resourceFactory,
$this->productModel,
$this->catalogData,
@@ -856,7 +851,7 @@ private function getAdvancedPricingMock($methods = [])
$this->importProduct,
$this->validator,
$this->websiteValidator,
- $this->groupPriceValidator,
+ $this->groupPriceValidator
],
''
);
diff --git a/app/code/Magento/Backend/App/Router.php b/app/code/Magento/Backend/App/Router.php
index fbcacd862a219..8d4a75438e8eb 100644
--- a/app/code/Magento/Backend/App/Router.php
+++ b/app/code/Magento/Backend/App/Router.php
@@ -10,21 +10,11 @@
class Router extends \Magento\Framework\App\Router\Base
{
- /**
- * @var \Magento\Backend\App\ConfigInterface
- */
- protected $_backendConfig;
-
/**
* @var \Magento\Framework\UrlInterface $url
*/
protected $_url;
- /**
- * @var \Magento\Framework\App\Config\ScopeConfigInterface
- */
- protected $_coreConfig;
-
/**
* List of required request parameters
* Order sensitive
@@ -46,92 +36,6 @@ class Router extends \Magento\Framework\App\Router\Base
*/
protected $pathPrefix = \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE;
- /**
- * @param \Magento\Framework\App\Router\ActionList $actionList
- * @param \Magento\Framework\App\ActionFactory $actionFactory
- * @param \Magento\Framework\App\DefaultPathInterface $defaultPath
- * @param \Magento\Framework\App\ResponseFactory $responseFactory
- * @param \Magento\Framework\App\Route\ConfigInterface $routeConfig
- * @param \Magento\Framework\UrlInterface $url
- * @param string $routerId
- * @param \Magento\Framework\Code\NameBuilder $nameBuilder
- * @param \Magento\Framework\App\Router\PathConfigInterface $pathConfig
- * @param \Magento\Framework\App\Config\ScopeConfigInterface $coreConfig
- * @param \Magento\Backend\App\ConfigInterface $backendConfig
- *
- * @SuppressWarnings(PHPMD.ExcessiveParameterList)
- */
- public function __construct(
- \Magento\Framework\App\Router\ActionList $actionList,
- \Magento\Framework\App\ActionFactory $actionFactory,
- \Magento\Framework\App\DefaultPathInterface $defaultPath,
- \Magento\Framework\App\ResponseFactory $responseFactory,
- \Magento\Framework\App\Route\ConfigInterface $routeConfig,
- \Magento\Framework\UrlInterface $url,
- $routerId,
- \Magento\Framework\Code\NameBuilder $nameBuilder,
- \Magento\Framework\App\Router\PathConfigInterface $pathConfig,
- \Magento\Framework\App\Config\ScopeConfigInterface $coreConfig,
- \Magento\Backend\App\ConfigInterface $backendConfig
- ) {
- parent::__construct(
- $actionList,
- $actionFactory,
- $defaultPath,
- $responseFactory,
- $routeConfig,
- $url,
- $routerId,
- $nameBuilder,
- $pathConfig
- );
- $this->_coreConfig = $coreConfig;
- $this->_backendConfig = $backendConfig;
- $this->_url = $url;
- }
-
- /**
- * Get router default request path
- * @return string
- */
- protected function _getDefaultPath()
- {
- return (string)$this->_backendConfig->getValue('web/default/admin');
- }
-
- /**
- * Check whether URL for corresponding path should use https protocol
- *
- * @param string $path
- * @return bool
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- protected function _shouldBeSecure($path)
- {
- return substr(
- (string)$this->_coreConfig->getValue('web/unsecure/base_url', 'default'),
- 0,
- 5
- ) === 'https' || $this->_backendConfig->isSetFlag(
- 'web/secure/use_in_adminhtml'
- ) && substr(
- (string)$this->_coreConfig->getValue('web/secure/base_url', 'default'),
- 0,
- 5
- ) === 'https';
- }
-
- /**
- * Retrieve current secure url
- *
- * @param \Magento\Framework\App\RequestInterface $request
- * @return string
- */
- protected function _getCurrentSecureUrl($request)
- {
- return $this->_url->getBaseUrl('link', true) . ltrim($request->getPathInfo(), '/');
- }
-
/**
* Check whether redirect should be used for secure routes
*
diff --git a/app/code/Magento/Backend/Model/AdminPathConfig.php b/app/code/Magento/Backend/Model/AdminPathConfig.php
new file mode 100644
index 0000000000000..14e0a715cb12c
--- /dev/null
+++ b/app/code/Magento/Backend/Model/AdminPathConfig.php
@@ -0,0 +1,87 @@
+coreConfig = $coreConfig;
+ $this->backendConfig = $backendConfig;
+ $this->url = $url;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param \Magento\Framework\App\RequestInterface $request
+ * @return string
+ */
+ public function getCurrentSecureUrl(\Magento\Framework\App\RequestInterface $request)
+ {
+ return $this->url->getBaseUrl('link', true) . ltrim($request->getPathInfo(), '/');
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param string $path
+ * @return bool
+ */
+ public function shouldBeSecure($path)
+ {
+ return parse_url(
+ (string)$this->coreConfig->getValue(Store::XML_PATH_UNSECURE_BASE_URL, 'default'),
+ PHP_URL_SCHEME
+ ) === 'https'
+ || $this->backendConfig->isSetFlag(Store::XML_PATH_SECURE_IN_ADMINHTML)
+ && parse_url(
+ (string)$this->coreConfig->getValue(Store::XML_PATH_SECURE_BASE_URL, 'default'),
+ PHP_URL_SCHEME
+ ) === 'https';
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return string
+ */
+ public function getDefaultPath()
+ {
+ return $this->backendConfig->getValue('web/default/admin');
+ }
+}
diff --git a/app/code/Magento/Backend/Test/Unit/Model/AdminPathConfigTest.php b/app/code/Magento/Backend/Test/Unit/Model/AdminPathConfigTest.php
new file mode 100644
index 0000000000000..224fa3d2b630c
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Model/AdminPathConfigTest.php
@@ -0,0 +1,112 @@
+coreConfig = $this->getMockForAbstractClass(
+ 'Magento\Framework\App\Config\ScopeConfigInterface',
+ [],
+ '',
+ false
+ );
+ $this->backendConfig = $this->getMockForAbstractClass('Magento\Backend\App\ConfigInterface', [], '', false);
+ $this->url = $this->getMockForAbstractClass(
+ 'Magento\Framework\UrlInterface',
+ [],
+ '',
+ false,
+ true,
+ true,
+ ['getBaseUrl']
+ );
+ $this->adminPathConfig = new AdminPathConfig($this->coreConfig, $this->backendConfig, $this->url);
+ }
+
+ public function testGetCurrentSecureUrl()
+ {
+ $request = $this->getMockForAbstractClass(
+ 'Magento\Framework\App\RequestInterface',
+ [],
+ '',
+ false,
+ true,
+ true,
+ ['getPathInfo']
+ );
+ $request->expects($this->once())->method('getPathInfo')->willReturn('/info');
+ $this->url->expects($this->once())->method('getBaseUrl')->with('link', true)->willReturn('localhost/');
+ $this->assertEquals('localhost/info', $this->adminPathConfig->getCurrentSecureUrl($request));
+ }
+
+ /**
+ * @param $unsecureBaseUrl
+ * @param $useSecureInAdmin
+ * @param $secureBaseUrl
+ * @param $expected
+ * @dataProvider shouldBeSecureDataProvider
+ */
+ public function testShouldBeSecure($unsecureBaseUrl, $useSecureInAdmin, $secureBaseUrl, $expected)
+ {
+ $coreConfigValueMap = [
+ [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, 'default', null, $unsecureBaseUrl],
+ [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, 'default', null, $secureBaseUrl],
+ ];
+ $this->coreConfig->expects($this->any())->method('getValue')->will($this->returnValueMap($coreConfigValueMap));
+ $this->backendConfig->expects($this->any())->method('isSetFlag')->willReturn($useSecureInAdmin);
+ $this->assertEquals($expected, $this->adminPathConfig->shouldBeSecure(''));
+ }
+
+ /**
+ * @return array
+ */
+ public function shouldBeSecureDataProvider()
+ {
+ return [
+ ['http://localhost/', false, 'default', false],
+ ['http://localhost/', true, 'default', false],
+ ['https://localhost/', false, 'default', true],
+ ['https://localhost/', true, 'default', true],
+ ['http://localhost/', false, 'https://localhost/', false],
+ ['http://localhost/', true, 'https://localhost/', true],
+ ['https://localhost/', true, 'https://localhost/', true],
+ ];
+ }
+
+ public function testGetDefaultPath()
+ {
+ $this->backendConfig->expects($this->once())
+ ->method('getValue')
+ ->with('web/default/admin')
+ ->willReturn('default/path');
+ $this->assertEquals('default/path', $this->adminPathConfig->getDefaultPath());
+ }
+}
diff --git a/app/code/Magento/Backend/etc/adminhtml/di.xml b/app/code/Magento/Backend/etc/adminhtml/di.xml
index cccd487a9f566..fd969977eb0df 100644
--- a/app/code/Magento/Backend/etc/adminhtml/di.xml
+++ b/app/code/Magento/Backend/etc/adminhtml/di.xml
@@ -127,4 +127,5 @@
Magento\Framework\App\Response\XFrameOptPlugin::BACKEND_X_FRAME_OPT
+
diff --git a/app/code/Magento/Backup/Model/Fs/Collection.php b/app/code/Magento/Backup/Model/Fs/Collection.php
index 289a1434e716f..d6f569f38ba15 100644
--- a/app/code/Magento/Backup/Model/Fs/Collection.php
+++ b/app/code/Magento/Backup/Model/Fs/Collection.php
@@ -91,7 +91,7 @@ protected function _hideBackupsForApache()
$filename = '.htaccess';
if (!$this->_varDirectory->isFile($filename)) {
$this->_varDirectory->writeFile($filename, 'deny from all');
- $this->_varDirectory->changePermissions($filename, 0644);
+ $this->_varDirectory->changePermissions($filename, 0640);
}
}
diff --git a/app/code/Magento/BundleImportExport/Model/Export/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Export/Product/Type/Bundle.php
new file mode 100644
index 0000000000000..8c68287283146
--- /dev/null
+++ b/app/code/Magento/BundleImportExport/Model/Export/Product/Type/Bundle.php
@@ -0,0 +1,13 @@
+ self::VALUE_DYNAMIC,
+ '1' => self::VALUE_FIXED
+ ];
+
+ /**
+ * Mapping for price views
+ *
+ * @var array
+ */
+ protected $priceViewMapping = [
+ '0' => self::VALUE_PRICE_RANGE,
+ '1' => self::VALUE_AS_LOW_AS
+ ];
+
+ /**
+ * Mapping for price types
+ *
+ * @var array
+ */
+ protected $priceTypeMapping = [
+ '0' => self::VALUE_FIXED,
+ '1' => self::VALUE_PERCENT
+ ];
+
+ /**
+ * Bundle product columns
+ *
+ * @var array
+ */
+ protected $bundleColumns = [
+ self::BUNDLE_PRICE_TYPE_COL,
+ self::BUNDLE_SKU_TYPE_COL,
+ self::BUNDLE_PRICE_VIEW_COL,
+ self::BUNDLE_WEIGHT_TYPE_COL,
+ self::BUNDLE_VALUES_COL
+ ];
+
+ /**
+ * Product's bundle data
+ *
+ * @var array
+ */
+ protected $bundleData = [];
+
+ /**
+ * Prepare data for export
+ *
+ * @param \Magento\Catalog\Model\Resource\Product\Collection $collection
+ * @param int $productIds
+ * @return $this
+ */
+ public function prepareData($collection, $productIds)
+ {
+ $collection->addAttributeToFilter(
+ 'entity_id',
+ ['in' => $productIds]
+ )->addAttributeToFilter(
+ 'type_id',
+ ['eq' => \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE]
+ );
+
+ return $this->populateBundleData($collection);
+ }
+
+ /**
+ * Set headers columns
+ *
+ * @param array $columns
+ * @return array
+ */
+ public function addHeaderColumns($columns)
+ {
+ $columns = array_merge($columns, $this->bundleColumns);
+
+ return $columns;
+ }
+
+ /**
+ * Add data for export
+ *
+ * @param array $dataRow
+ * @param int $productId
+ * @return array
+ */
+ public function addData($dataRow, $productId)
+ {
+ if (!empty($this->bundleData[$productId])) {
+ $dataRow = array_merge($this->cleanNotBundleAdditionalAttributes($dataRow), $this->bundleData[$productId]);
+ }
+
+ return $dataRow;
+ }
+
+ /**
+ * Calculate the largest links block
+ *
+ * @param array $additionalRowsCount
+ * @param int $productId
+ * @return array
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function getAdditionalRowsCount($additionalRowsCount, $productId)
+ {
+ return $additionalRowsCount;
+ }
+
+ /**
+ * Populate bundle product data
+ *
+ * @param \Magento\Catalog\Model\Resource\Product\Collection $collection
+ * @return $this
+ */
+ protected function populateBundleData($collection)
+ {
+ foreach ($collection as $product) {
+ $id = $product->getId();
+ $this->bundleData[$id][self::BUNDLE_PRICE_TYPE_COL] = $this->getTypeValue($product->getPriceType());
+ $this->bundleData[$id][self::BUNDLE_SKU_TYPE_COL] = $this->getTypeValue($product->getSkuType());
+ $this->bundleData[$id][self::BUNDLE_PRICE_VIEW_COL] = $this->getPriceViewValue($product->getPriceView());
+ $this->bundleData[$id][self::BUNDLE_WEIGHT_TYPE_COL] = $this->getTypeValue($product->getWeightType());
+ $this->bundleData[$id][self::BUNDLE_VALUES_COL] = $this->getFormattedBundleOptionValues($product);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Retrieve formatted bundle options
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @return string
+ */
+ protected function getFormattedBundleOptionValues($product)
+ {
+ /** @var \Magento\Bundle\Model\Resource\Option\Collection $optionsCollection */
+ $optionsCollection = $product->getTypeInstance()
+ ->getOptionsCollection($product)
+ ->setOrder('position', Collection::SORT_ORDER_ASC);
+
+ $bundleData = '';
+ foreach ($optionsCollection as $option) {
+ $bundleData .= $this->getFormattedBundleSelections(
+ $this->getFormattedOptionValues($option),
+ $product->getTypeInstance()
+ ->getSelectionsCollection([$option->getId()], $product)
+ ->setOrder('position', Collection::SORT_ORDER_ASC)
+ );
+ }
+
+ return rtrim($bundleData, ImportProductModel::PSEUDO_MULTI_LINE_SEPARATOR);
+ }
+
+ /**
+ * Retrieve formatted bundle selections
+ *
+ * @param string $optionValues
+ * @param SelectionCollection $selections
+ * @return string
+ */
+ protected function getFormattedBundleSelections($optionValues, SelectionCollection $selections)
+ {
+ $bundleData = '';
+ $selections->addAttributeToSort('position');
+ foreach ($selections as $selection) {
+ $selectionData = [
+ 'sku' => $selection->getSku(),
+ 'price' => $selection->getSelectionPriceValue(),
+ 'default' => $selection->getIsDefault(),
+ 'default_qty' => $selection->getSelectionQty(),
+ 'price_type' => $this->getPriceTypeValue($selection->getSelectionPriceType())
+ ];
+ $bundleData .= $optionValues
+ . ImportProductModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR
+ . implode(
+ ImportProductModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR,
+ array_map(
+ function ($value, $key) {
+ return $key . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR . $value;
+ },
+ $selectionData,
+ array_keys($selectionData)
+ )
+ )
+ . ImportProductModel::PSEUDO_MULTI_LINE_SEPARATOR;
+ }
+
+ return $bundleData;
+ }
+
+ /**
+ * Retrieve option value of bundle product
+ *
+ * @param \Magento\Bundle\Model\Option $option
+ * @return string
+ */
+ protected function getFormattedOptionValues($option)
+ {
+ return 'name' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR
+ . $option->getTitle() . ImportProductModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR
+ . 'type' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR
+ . $option->getType() . ImportProductModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR
+ . 'required' . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR
+ . $option->getRequired();
+ }
+
+ /**
+ * Retrieve bundle type value by code
+ *
+ * @param string $type
+ * @return string
+ */
+ protected function getTypeValue($type)
+ {
+ return isset($this->typeMapping[$type]) ? $this->typeMapping[$type] : self::VALUE_DYNAMIC;
+ }
+
+ /**
+ * Retrieve bundle price view value by code
+ *
+ * @param string $type
+ * @return string
+ */
+ protected function getPriceViewValue($type)
+ {
+ return isset($this->priceViewMapping[$type]) ? $this->priceViewMapping[$type] : self::VALUE_PRICE_RANGE;
+ }
+
+ /**
+ * Retrieve bundle price type value by code
+ *
+ * @param string $type
+ * @return string
+ */
+ protected function getPriceTypeValue($type)
+ {
+ return isset($this->priceTypeMapping[$type]) ? $this->priceTypeMapping[$type] : null;
+ }
+
+ /**
+ * Remove bundle specified additional attributes as now they are stored in specified columns
+ *
+ * @param array $dataRow
+ * @return array
+ */
+ protected function cleanNotBundleAdditionalAttributes($dataRow)
+ {
+ if (!empty($dataRow['additional_attributes'])) {
+ $additionalAttributes = explode(
+ ImportProductModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR,
+ $dataRow['additional_attributes']
+ );
+ $dataRow['additional_attributes'] = $this->getNotBundleAttributes($additionalAttributes);
+ }
+
+ return $dataRow;
+ }
+
+ /**
+ * Retrieve not bundle additional attributes
+ *
+ * @param array $additionalAttributes
+ * @return string
+ */
+ protected function getNotBundleAttributes($additionalAttributes)
+ {
+ $cleanedAdditionalAttributes = '';
+ foreach ($additionalAttributes as $attribute) {
+ list($attributeCode, $attributeValue) = explode(ImportProductModel::PAIR_NAME_VALUE_SEPARATOR, $attribute);
+ if (!in_array('bundle_' . $attributeCode, $this->bundleColumns)) {
+ $cleanedAdditionalAttributes .= $attributeCode
+ . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR
+ . $attributeValue
+ . ImportProductModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR;
+ }
+ }
+
+ return rtrim($cleanedAdditionalAttributes, ImportProductModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR);
+ }
+}
diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php
index 7dab7fa3d8126..3d90cfc916fab 100644
--- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php
+++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php
@@ -608,6 +608,23 @@ protected function insertSelections()
return $this;
}
+ /**
+ * Initialize attributes parameters for all attributes' sets.
+ *
+ * @return $this
+ */
+ protected function _initAttributes()
+ {
+ parent::_initAttributes();
+ if (isset(self::$attributeCodeToId['price_type']) && $id = self::$attributeCodeToId['price_type']) {
+ self::$commonAttributesCache[$id]['type'] = 'select';
+ self::$commonAttributesCache[$id]['options'] = [
+ self::VALUE_DYNAMIC => BundlePrice::PRICE_TYPE_DYNAMIC,
+ self::VALUE_FIXED => BundlePrice::PRICE_TYPE_FIXED,
+ ];
+ }
+ }
+
/**
* Delete options and selections.
*
diff --git a/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php b/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php
new file mode 100644
index 0000000000000..c01e20f7f43a4
--- /dev/null
+++ b/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php
@@ -0,0 +1,203 @@
+objectManagerHelper = new ObjectManagerHelper($this);
+ $this->rowCustomizerMock = $this->objectManagerHelper->getObject(
+ '\Magento\BundleImportExport\Model\Export\RowCustomizer'
+ );
+ $this->productResourceCollection = $this->getMock(
+ '\Magento\Catalog\Model\Resource\Product\Collection',
+ ['addAttributeToFilter', 'getIterator'],
+ [],
+ '',
+ false
+ );
+ $this->product = $this->getMock(
+ '\Magento\Catalog\Model\Product',
+ [
+ 'getId',
+ 'getPriceType',
+ 'getSkuType',
+ 'getPriceView',
+ 'getWeightType',
+ 'getTypeInstance',
+ 'getOptionsCollection',
+ 'getSelectionsCollection'
+ ],
+ [],
+ '',
+ false
+ );
+ $this->product->expects($this->any())->method('getId')->willReturn(1);
+ $this->product->expects($this->any())->method('getPriceType')->willReturn(1);
+ $this->product->expects($this->any())->method('getSkuType')->willReturn(1);
+ $this->product->expects($this->any())->method('getPriceView')->willReturn(1);
+ $this->product->expects($this->any())->method('getWeightType')->willReturn(1);
+ $this->product->expects($this->any())->method('getTypeInstance')->willReturnSelf();
+ $this->optionsCollection = $this->getMock(
+ '\Magento\Bundle\Model\Resource\Option\Collection',
+ ['setOrder', 'getIterator'],
+ [],
+ '',
+ false
+ );
+ $this->product->expects($this->any())->method('getOptionsCollection')->willReturn($this->optionsCollection);
+ $this->optionsCollection->expects($this->any())->method('setOrder')->willReturnSelf();
+ $this->option = $this->getMock(
+ '\Magento\Bundle\Model\Option',
+ ['getId', 'getTitle', 'getType', 'getRequired'],
+ [],
+ '',
+ false
+ );
+ $this->option->expects($this->any())->method('getId')->willReturn(1);
+ $this->option->expects($this->any())->method('getTitle')->willReturn('title');
+ $this->option->expects($this->any())->method('getType')->willReturn(1);
+ $this->option->expects($this->any())->method('getRequired')->willReturn(1);
+ $this->optionsCollection->expects($this->any())->method('getIterator')->will(
+ $this->returnValue(new \ArrayIterator([$this->option]))
+ );
+ $this->selection = $this->getMock(
+ '\Magento\Catalog\Model\Product',
+ ['getSku', 'getSelectionPriceValue', 'getIsDefault', 'getSelectionQty', 'getSelectionPriceType'],
+ [],
+ '',
+ false
+ );
+ $this->selection->expects($this->any())->method('getSku')->willReturn(1);
+ $this->selection->expects($this->any())->method('getSelectionPriceValue')->willReturn(1);
+ $this->selection->expects($this->any())->method('getSelectionQty')->willReturn(1);
+ $this->selection->expects($this->any())->method('getSelectionPriceType')->willReturn(1);
+ $this->selectionsCollection = $this->getMock(
+ '\Magento\Bundle\Model\Resource\Selection\Collection',
+ ['getIterator', 'addAttributeToSort'],
+ [],
+ '',
+ false
+ );
+ $this->selectionsCollection->expects($this->any())->method('getIterator')->will(
+ $this->returnValue(new \ArrayIterator([$this->selection]))
+ );
+ $this->selectionsCollection->expects($this->any())->method('addAttributeToSort')->willReturnSelf();
+ $this->product->expects($this->any())->method('getSelectionsCollection')->willReturn(
+ $this->selectionsCollection
+ );
+ $this->productResourceCollection->expects($this->any())->method('addAttributeToFilter')->willReturnSelf();
+ $this->productResourceCollection->expects($this->any())->method('getIterator')->will(
+ $this->returnValue(new \ArrayIterator([$this->product]))
+ );
+ }
+
+ /**
+ * Test prepareData()
+ */
+ public function testPrepareData()
+ {
+ $this->rowCustomizerMock->prepareData($this->productResourceCollection, [1]);
+ }
+
+ /**
+ * Test addHeaderColumns()
+ */
+ public function testAddHeaderColumns()
+ {
+ $productData = [0 => 'sku'];
+ $expectedData = [
+ 0 => 'sku',
+ 1 => 'bundle_price_type',
+ 2 => 'bundle_sku_type',
+ 3 => 'bundle_price_view',
+ 4 => 'bundle_weight_type',
+ 5 => 'bundle_values'
+ ];
+ $this->assertEquals($expectedData, $this->rowCustomizerMock->addHeaderColumns($productData));
+ }
+
+ /**
+ * Test addData()
+ */
+ public function testAddData()
+ {
+ $preparedData = $this->rowCustomizerMock->prepareData($this->productResourceCollection, [1]);
+ $dataRow = [
+ 'sku' => 'sku1',
+ 'additional_attributes' => 'attribute=1,sku_type=1,price_type=1,price_view=1,weight_type=1,values=values'
+ ];
+ $preparedRow = $preparedData->addData($dataRow, 1);
+ $expected = [
+ 'sku' => 'sku1',
+ 'additional_attributes' => 'attribute=1',
+ 'bundle_price_type' => 'fixed',
+ 'bundle_sku_type' => 'fixed',
+ 'bundle_price_view' => 'As low as',
+ 'bundle_weight_type' => 'fixed',
+ 'bundle_values' => 'name=title,type=1,required=1,sku=1,price=1,default=,default_qty=1,price_type=percent'
+ ];
+ $this->assertEquals($expected, $preparedRow);
+ }
+
+ /**
+ * Test getAdditionalRowsCount()
+ */
+ public function testGetAdditionalRowsCount()
+ {
+ $count = [5];
+ $this->assertEquals($count, $this->rowCustomizerMock->getAdditionalRowsCount($count, 0));
+ }
+}
diff --git a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php
index a05b5b6f63b69..1841d2fc7f1f2 100644
--- a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php
+++ b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php
@@ -6,9 +6,7 @@
namespace Magento\BundleImportExport\Test\Unit\Model\Import\Product\Type;
-use \Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
-
-class BundleTest extends \PHPUnit_Framework_TestCase
+class BundleTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
* @var \Magento\BundleImportExport\Model\Import\Product\Type\Bundle
@@ -16,14 +14,14 @@ class BundleTest extends \PHPUnit_Framework_TestCase
protected $bundle;
/**
- * @var ObjectManagerHelper
+ * @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $objectManagerHelper;
+ protected $resource;
/**
- * @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Framework\DB\Select|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $resource;
+ protected $select;
/**
* @var \Magento\CatalogImportExport\Model\Import\Product|\PHPUnit_Framework_MockObject_MockObject
@@ -54,15 +52,72 @@ class BundleTest extends \PHPUnit_Framework_TestCase
*/
protected $setCollection;
+ /**
+ *
+ * @return void
+ */
+ protected function initFetchAllCalls()
+ {
+ $fetchAllForInitAttributes = [
+ [
+ 'attribute_set_name' => '1',
+ 'attribute_id' => '1',
+ ],
+ [
+ 'attribute_set_name' => '2',
+ 'attribute_id' => '2',
+ ],
+ ];
+
+ $fetchAllForOtherCalls = [[
+ 'selection_id' => '1',
+ 'option_id' => '1',
+ 'parent_product_id' => '1',
+ 'product_id' => '1',
+ 'position' => '1',
+ 'is_default' => '1'
+ ]];
+
+ $this->connection
+ ->method('fetchAll')
+ ->with($this->select)
+ ->will($this->onConsecutiveCalls(
+ $fetchAllForInitAttributes,
+ $fetchAllForOtherCalls,
+ $fetchAllForInitAttributes,
+ $fetchAllForOtherCalls,
+ $fetchAllForInitAttributes,
+ $fetchAllForOtherCalls,
+ $fetchAllForInitAttributes,
+ $fetchAllForOtherCalls,
+ $fetchAllForInitAttributes,
+ $fetchAllForInitAttributes,
+ $fetchAllForInitAttributes,
+ $fetchAllForInitAttributes,
+ $fetchAllForInitAttributes
+ ));
+ }
+
protected function setUp()
{
+ parent::setUp();
+
$this->entityModel = $this->getMock(
'Magento\CatalogImportExport\Model\Import\Product',
- ['getBehavior', 'getNewSku', 'getNextBunch', 'isRowAllowedToImport', 'getRowScope', 'getConnection'],
+ [
+ 'getErrorAggregator',
+ 'getBehavior',
+ 'getNewSku',
+ 'getNextBunch',
+ 'isRowAllowedToImport',
+ 'getRowScope',
+ 'getConnection'
+ ],
[],
'',
false
);
+ $this->entityModel->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
$this->connection = $this->getMock(
'Magento\Framework\DB\Adapter\Pdo\Mysql',
['select', 'fetchAll', 'fetchPairs', 'joinLeft', 'insertOnDuplicate', 'delete', 'quoteInto', 'fetchAssoc'],
@@ -70,17 +125,13 @@ protected function setUp()
'',
false
);
- $select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false);
- $select->expects($this->any())->method('from')->will($this->returnSelf());
- $select->expects($this->any())->method('where')->will($this->returnSelf());
- $select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
- $connection = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
- $connection->expects($this->any())->method('quoteInto')->will($this->returnValue('query'));
- $select->expects($this->any())->method('getConnection')->willReturn($connection);
- $this->connection->expects($this->any())->method('select')->will($this->returnValue($select));
- $this->connection->expects($this->any())->method('fetchPairs')->will($this->returnValue([
- '1' => '1', '2' => '2'
- ]));
+ $this->select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false);
+ $this->select->expects($this->any())->method('from')->will($this->returnSelf());
+ $this->select->expects($this->any())->method('where')->will($this->returnSelf());
+ $this->select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
+ $this->select->expects($this->any())->method('getConnection')->willReturn($this->connection);
+ $this->connection->expects($this->any())->method('select')->will($this->returnValue($this->select));
+ $this->initFetchAllCalls();
$this->connection->expects($this->any())->method('insertOnDuplicate')->willReturnSelf();
$this->connection->expects($this->any())->method('delete')->willReturnSelf();
$this->connection->expects($this->any())->method('quoteInto')->willReturn('');
@@ -91,12 +142,8 @@ protected function setUp()
'',
false
);
- $this->resource->expects($this->any())->method('getConnection')->will(
- $this->returnValue($this->connection)
- );
- $this->resource->expects($this->any())->method('getTableName')->will(
- $this->returnValue('tableName')
- );
+ $this->resource->expects($this->any())->method('getConnection')->will($this->returnValue($this->connection));
+ $this->resource->expects($this->any())->method('getTableName')->will($this->returnValue('tableName'));
$this->attrSetColFac = $this->getMock(
'Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory',
['create'],
@@ -127,15 +174,11 @@ protected function setUp()
$attrCollection =
$this->getMock('\Magento\Catalog\Model\Resource\Product\Attribute\Collection', [], [], '', false);
$attrCollection->expects($this->any())->method('addFieldToFilter')->willReturn([]);
-
- $this->prodAttrColFac->expects($this->any())->method('create')->will(
- $this->returnValue($attrCollection)
- );
+ $this->prodAttrColFac->expects($this->any())->method('create')->will($this->returnValue($attrCollection));
$this->params = [
0 => $this->entityModel,
1 => 'bundle'
];
- $this->objectManagerHelper = new ObjectManagerHelper($this);
$this->bundle = $this->objectManagerHelper->getObject(
'Magento\BundleImportExport\Model\Import\Product\Type\Bundle',
@@ -167,17 +210,7 @@ public function testSaveData($skus, $bunch, $allowImport)
$allowImport
));
- $connection = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
- $connection->expects($this->any())->method('quoteInto')->will($this->returnValue('query'));
-
- $select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false);
- $select->expects($this->any())->method('getConnection')->willReturn($connection);
- $select->expects($this->any())->method('from')->will($this->returnSelf());
- $select->expects($this->any())->method('where')->will($this->returnSelf());
- $select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
- $this->connection->expects($this->any())->method('select')->will($this->returnValue($select));
-
- $this->connection->expects($this->any())->method('fetchAssoc')->with($select)->will($this->returnValue([
+ $this->connection->expects($this->any())->method('fetchAssoc')->with($this->select)->will($this->returnValue([
'1' => [
'option_id' => '1',
'parent_id' => '1',
@@ -222,15 +255,6 @@ public function testSaveData($skus, $bunch, $allowImport)
]
]
]));
- $this->connection->expects($this->any())->method('fetchAll')->with($select)->will($this->returnValue([[
- 'selection_id' => '1',
- 'option_id' => '1',
- 'parent_product_id' => '1',
- 'product_id' => '1',
- 'position' => '1',
- 'is_default' => '1'
- ]]));
-
$this->bundle->saveData();
}
diff --git a/app/code/Magento/BundleImportExport/etc/di.xml b/app/code/Magento/BundleImportExport/etc/di.xml
index ba3b3261d7850..f91245bf6ad75 100644
--- a/app/code/Magento/BundleImportExport/etc/di.xml
+++ b/app/code/Magento/BundleImportExport/etc/di.xml
@@ -6,4 +6,11 @@
*/
-->
+
+
+
+ - Magento\BundleImportExport\Model\Export\RowCustomizer
+
+
+
diff --git a/app/code/Magento/BundleImportExport/etc/export.xml b/app/code/Magento/BundleImportExport/etc/export.xml
new file mode 100644
index 0000000000000..53950ed3b4210
--- /dev/null
+++ b/app/code/Magento/BundleImportExport/etc/export.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/app/code/Magento/CacheInvalidate/Model/PurgeCache.php b/app/code/Magento/CacheInvalidate/Model/PurgeCache.php
index 2cde853240db4..d60e442ac7022 100644
--- a/app/code/Magento/CacheInvalidate/Model/PurgeCache.php
+++ b/app/code/Magento/CacheInvalidate/Model/PurgeCache.php
@@ -5,40 +5,64 @@
*/
namespace Magento\CacheInvalidate\Model;
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Zend\Uri\Uri;
+use Zend\Http\Client\Adapter\Socket;
use Magento\Framework\Cache\InvalidateLogger;
+use Magento\Framework\App\DeploymentConfig;
+use Magento\Framework\Config\ConfigOptionsListConstants;
+use Magento\Framework\App\RequestInterface;
class PurgeCache
{
/**
- * @var \Magento\PageCache\Helper\Data
+ * @var Uri
*/
- protected $helper;
+ protected $uri;
/**
- * @var \Magento\Framework\HTTP\Adapter\Curl
+ * @var Socket
*/
- protected $curlAdapter;
+ protected $socketAdapter;
/**
* @var InvalidateLogger
*/
private $logger;
+ /**
+ * @var DeploymentConfig
+ */
+ private $config;
+
+ /**
+ * @var RequestInterface
+ */
+ private $request;
+
+ const DEFAULT_PORT = 80;
+
/**
* Constructor
*
- * @param \Magento\PageCache\Helper\Data $helper
- * @param \Magento\Framework\HTTP\Adapter\Curl $curlAdapter
+ * @param Uri $uri
+ * @param Socket $socketAdapter
* @param InvalidateLogger $logger
+ * @param Reader $configReader
+ * @param RequestInterface $request
*/
public function __construct(
- \Magento\PageCache\Helper\Data $helper,
- \Magento\Framework\HTTP\Adapter\Curl $curlAdapter,
- InvalidateLogger $logger
+ Uri $uri,
+ Socket $socketAdapter,
+ InvalidateLogger $logger,
+ DeploymentConfig $config,
+ RequestInterface $request
) {
- $this->helper = $helper;
- $this->curlAdapter = $curlAdapter;
+ $this->uri = $uri;
+ $this->socketAdapter = $socketAdapter;
$this->logger = $logger;
+ $this->config = $config;
+ $this->request = $request;
}
/**
@@ -50,12 +74,29 @@ public function __construct(
*/
public function sendPurgeRequest($tagsPattern)
{
- $headers = ["X-Magento-Tags-Pattern: {$tagsPattern}"];
- $this->curlAdapter->setOptions([CURLOPT_CUSTOMREQUEST => 'PURGE']);
- $this->curlAdapter->write('', $this->helper->getUrl('*'), '1.1', $headers);
- $this->curlAdapter->read();
- $this->curlAdapter->close();
+ $servers = $this->config->get(ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS)
+ ?: [['host' => $this->request->getHttpHost()]];
+ $headers = ['X-Magento-Tags-Pattern' => $tagsPattern];
+ $this->socketAdapter->setOptions(['timeout' => 10]);
+ foreach ($servers as $server) {
+ $port = isset($server['port']) ? $server['port'] : self::DEFAULT_PORT;
+ $this->uri->setScheme('http')
+ ->setHost($server['host'])
+ ->setPort($port);
+ try {
+ $this->socketAdapter->connect($server['host'], $port);
+ $this->socketAdapter->write(
+ 'PURGE',
+ $this->uri,
+ '1.1',
+ $headers
+ );
+ $this->socketAdapter->close();
+ } catch (Exception $e) {
+ $this->logger->critical($e->getMessage(), compact('server', 'tagsPattern'));
+ }
+ }
- $this->logger->execute(compact('tagsPattern'));
+ $this->logger->execute(compact('servers', 'tagsPattern'));
}
}
diff --git a/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php b/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php
index 93146a33e90b4..b0500dadc7284 100644
--- a/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php
+++ b/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php
@@ -5,70 +5,138 @@
*/
namespace Magento\CacheInvalidate\Test\Unit\Model;
+use \Magento\Framework\Config\ConfigOptionsListConstants;
+
class PurgeCacheTest extends \PHPUnit_Framework_TestCase
{
/** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\CacheInvalidate\Model\PurgeCache */
protected $model;
- /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\HTTP\Adapter\Curl */
- protected $curlMock;
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Zend\Uri\Uri */
+ protected $uriMock;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Zend\Http\Client\Adapter\Socket */
+ protected $socketAdapterMock;
+
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Cache\InvalidateLogger */
+ protected $loggerMock;
- /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\PageCache\Helper\Data */
- protected $helperMock;
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\DeploymentConfig\Reader */
+ protected $configReaderMock;
- /** @var \PHPUnit_Framework_MockObject_MockObject */
- protected $logger;
+ /** @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\App\RequestInterface */
+ protected $requestMock;
/**
* Set up all mocks and data for test
*/
public function setUp()
{
- $this->helperMock = $this->getMock('Magento\PageCache\Helper\Data', ['getUrl'], [], '', false);
- $this->curlMock = $this->getMock(
- '\Magento\Framework\HTTP\Adapter\Curl',
- ['setOptions', 'write', 'read', 'close'],
- [],
- '',
- false
- );
- $this->logger = $this->getMock('Magento\Framework\Cache\InvalidateLogger', [], [], '', false);
+ $this->uriMock = $this->getMock('\Zend\Uri\Uri', [], [], '', false);
+ $this->socketAdapterMock = $this->getMock('\Zend\Http\Client\Adapter\Socket', [], [], '', false);
+ $this->configMock = $this->getMock('Magento\Framework\App\DeploymentConfig', [], [], '', false);
+ $this->loggerMock = $this->getMock('Magento\Framework\Cache\InvalidateLogger', [], [], '', false);
+ $this->requestMock = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false);
+ $this->socketAdapterMock->expects($this->once())
+ ->method('setOptions')
+ ->with(['timeout' => 10]);
$this->model = new \Magento\CacheInvalidate\Model\PurgeCache(
- $this->helperMock,
- $this->curlMock,
- $this->logger
+ $this->uriMock,
+ $this->socketAdapterMock,
+ $this->loggerMock,
+ $this->configMock,
+ $this->requestMock
);
}
- public function testSendPurgeRequest()
+ public function testSendPurgeRequestEmptyConfig()
{
- $tags = 'tags';
- $url = 'http://mangento.index.php';
- $httpVersion = '1.1';
- $headers = ["X-Magento-Tags-Pattern: {$tags}"];
- $this->helperMock->expects(
- $this->any()
- )->method(
- 'getUrl'
- )->with(
- $this->equalTo('*'),
- []
- )->will(
- $this->returnValue($url)
- );
- $this->curlMock->expects($this->once())->method('setOptions')->with([CURLOPT_CUSTOMREQUEST => 'PURGE']);
- $this->curlMock->expects(
- $this->once()
- )->method(
- 'write'
- )->with(
- $this->equalTo(''),
- $this->equalTo($url),
- $httpVersion,
- $this->equalTo($headers)
- );
- $this->curlMock->expects($this->once())->method('read');
- $this->curlMock->expects($this->once())->method('close');
- $this->model->sendPurgeRequest($tags);
+ $this->socketAdapterMock->expects($this->once())
+ ->method('write')
+ ->with('PURGE', $this->uriMock, '1.1', $this->equalTo(['X-Magento-Tags-Pattern' => 'tags']));
+ $this->socketAdapterMock->expects($this->once())
+ ->method('close');
+ $this->configMock->expects($this->once())
+ ->method('get')
+ ->willReturn('');
+ $this->requestMock->expects($this->any())
+ ->method('getHttpHost')
+ ->willReturn('127.0.0.1');
+ $this->uriMock->expects($this->once())
+ ->method('setScheme')
+ ->with('http')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->once())
+ ->method('setHost')
+ ->with('127.0.0.1')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->once())
+ ->method('setPort')
+ ->with(\Magento\CacheInvalidate\Model\PurgeCache::DEFAULT_PORT);
+ $this->model->sendPurgeRequest('tags');
+ }
+
+ public function testSendPurgeRequestOneServer()
+ {
+ $this->socketAdapterMock->expects($this->once())
+ ->method('write')
+ ->with('PURGE', $this->uriMock, '1.1', $this->equalTo(['X-Magento-Tags-Pattern' => 'tags']));
+ $this->socketAdapterMock->expects($this->once())
+ ->method('close');
+ $this->configMock->expects($this->once())
+ ->method('get')
+ ->willReturn([['host' => '127.0.0.2', 'port' => 1234]]);
+ $this->uriMock->expects($this->once())
+ ->method('setScheme')
+ ->with('http')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->once())
+ ->method('setHost')
+ ->with('127.0.0.2')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->once())
+ ->method('setPort')
+ ->with(1234);
+ $this->model->sendPurgeRequest('tags');
+ }
+
+ public function testSendPurgeRequestMultipleServers()
+ {
+ $this->socketAdapterMock->expects($this->exactly(2))
+ ->method('write')
+ ->with('PURGE', $this->uriMock, '1.1', $this->equalTo(['X-Magento-Tags-Pattern' => 'tags']));
+ $this->socketAdapterMock->expects($this->exactly(2))
+ ->method('close');
+ $this->configMock->expects($this->once())
+ ->method('get')
+ ->willReturn(
+ [
+ ['host' => '127.0.0.1', 'port' => 8080],
+ ['host' => '127.0.0.2', 'port' => 1234]
+ ]
+ );
+ $this->uriMock->expects($this->at(0))
+ ->method('setScheme')
+ ->with('http')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->at(1))
+ ->method('setHost')
+ ->with('127.0.0.1')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->at(2))
+ ->method('setPort')
+ ->with(8080);
+ $this->uriMock->expects($this->at(3))
+ ->method('setScheme')
+ ->with('http')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->at(4))
+ ->method('setHost')
+ ->with('127.0.0.2')
+ ->willReturnSelf();
+ $this->uriMock->expects($this->at(5))
+ ->method('setPort')
+ ->with(1234);
+ $this->model->sendPurgeRequest('tags');
}
}
diff --git a/app/code/Magento/Captcha/Helper/Data.php b/app/code/Magento/Captcha/Helper/Data.php
index 183e371328b82..f7956740411d4 100644
--- a/app/code/Magento/Captcha/Helper/Data.php
+++ b/app/code/Magento/Captcha/Helper/Data.php
@@ -7,6 +7,7 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
+use Magento\Framework\Filesystem\DriverInterface;
/**
* Captcha image model
@@ -149,7 +150,7 @@ public function getImgDir($website = null)
$mediaDir = $this->_filesystem->getDirectoryWrite(DirectoryList::MEDIA);
$captchaDir = '/captcha/' . $this->_getWebsiteCode($website);
$mediaDir->create($captchaDir);
- $mediaDir->changePermissions($captchaDir, 0775);
+ $mediaDir->changePermissions($captchaDir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
return $mediaDir->getAbsolutePath($captchaDir) . '/';
}
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
index be2df526aaa8b..b227df7cb1b8f 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
@@ -13,6 +13,7 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Filesystem\DriverInterface;
/**
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
@@ -396,7 +397,7 @@ public function addImage(
$this->_mediaDirectory->copyFile($file, $destinationFile);
$storageHelper->saveFile($this->_mediaConfig->getTmpMediaShortUrl($fileName));
- $this->_mediaDirectory->changePermissions($destinationFile, 0777);
+ $this->_mediaDirectory->changePermissions($destinationFile, DriverInterface::WRITEABLE_FILE_MODE);
}
} catch (\Exception $e) {
throw new LocalizedException(__('We couldn\'t move this file: %1.', $e->getMessage()));
diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
index 3b0a02485756b..0377e0ca63827 100644
--- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php
@@ -879,8 +879,15 @@ protected function collectRawData()
ImportProduct::PAIR_NAME_VALUE_SEPARATOR . $attrValue;
}
$data[$itemId][$storeId][$fieldName] = $attrValue;
- } else {
- $this->collectMultiselectValues($item, $code, $storeId);
+ }
+ } else {
+ $this->collectMultiselectValues($item, $code, $storeId);
+ if (!empty($this->collectedMultiselectsData[$storeId][$itemId][$code])) {
+ $additionalAttributes[$code] = $fieldName .
+ ImportProduct::PAIR_NAME_VALUE_SEPARATOR . implode(
+ ImportProduct::PSEUDO_MULTI_LINE_SEPARATOR,
+ $this->collectedMultiselectsData[$storeId][$itemId][$code]
+ );
}
}
}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
index a2f65405c69ab..dc2fefaa9f83e 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php
@@ -13,6 +13,8 @@
use Magento\Framework\Model\Resource\Db\TransactionManagerInterface;
use Magento\Framework\Model\Resource\Db\ObjectRelationProcessor;
use Magento\Framework\Stdlib\DateTime;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
/**
* Import entity product model
@@ -225,6 +227,15 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE => 'Product with specified SKU not found',
ValidatorInterface::ERROR_SUPER_PRODUCTS_SKU_NOT_FOUND => 'Product with specified super products SKU not found',
ValidatorInterface::ERROR_MEDIA_DATA_INCOMPLETE => 'Media data is incomplete',
+ ValidatorInterface::ERROR_EXCEEDED_MAX_LENGTH => 'Attribute %s exceeded max length',
+ ValidatorInterface::ERROR_INVALID_ATTRIBUTE_TYPE => 'Value for \'%s\' attribute contains incorrect value, acceptable values are in %s format',
+ ValidatorInterface::ERROR_ABSENT_REQUIRED_ATTRIBUTE => 'Attribute %s is required',
+ ValidatorInterface::ERROR_INVALID_ATTRIBUTE_OPTION => 'Value for \'%s\' attribute contains incorrect value, see acceptable values on settings specified for Admin',
+ ValidatorInterface::ERROR_DUPLICATE_UNIQUE_ATTRIBUTE => 'Duplicated unique attribute',
+ ValidatorInterface::ERROR_INVALID_VARIATIONS_CUSTOM_OPTIONS => 'Value for \'%s\' sub attribute in \'%s\' attribute contains incorrect value, acceptable values are: \'dropdown\', \'checkbox\', \'radio\', \'text\'',
+ ValidatorInterface::ERROR_INVALID_MEDIA_URL_OR_PATH => 'Wrong URL/path used for attribute %s',
+ ValidatorInterface::ERROR_MEDIA_PATH_NOT_ACCESSIBLE => 'Imported resource (image) does not exist in the local media storage',
+ ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE => 'Imported resource (image) could not be downloaded from external resource due to timeout or access permissions',
ValidatorInterface::ERROR_INVALID_WEIGHT => 'Product weight is invalid',
];
@@ -429,6 +440,11 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
*/
protected $_resourceFactory;
+ /**
+ * @var \Magento\CatalogImportExport\Model\Import\Proxy\Product\Resource
+ */
+ protected $_resource;
+
/**
* @var \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory
*/
@@ -561,6 +577,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
* @param \Magento\Framework\App\Resource $resource
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Framework\Stdlib\StringUtils $string
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param \Magento\Framework\Event\ManagerInterface $eventManager
* @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
* @param \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration
@@ -576,17 +593,20 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
* @param UploaderFactory $uploaderFactory
* @param \Magento\Framework\Filesystem $filesystem
* @param \Magento\CatalogInventory\Model\Resource\Stock\ItemFactory $stockResItemFac
- * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
+ * @param DateTime\TimezoneInterface $localeDate
* @param DateTime $dateTime
* @param \Psr\Log\LoggerInterface $logger
* @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
* @param Product\StoreResolver $storeResolver
* @param Product\SkuProcessor $skuProcessor
* @param Product\CategoryProcessor $categoryProcessor
- * @param Product\TaxClassProcessor $taxClassProcessor
* @param Product\Validator $validator
+ * @param ObjectRelationProcessor $objectRelationProcessor
+ * @param TransactionManagerInterface $transactionManager
+ * @param Product\TaxClassProcessor $taxClassProcessor
* @param array $data
* @throws \Magento\Framework\Exception\LocalizedException
+ *
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -597,6 +617,7 @@ public function __construct(
\Magento\Framework\App\Resource $resource,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
\Magento\Framework\Stdlib\StringUtils $string,
+ ProcessingErrorAggregatorInterface $errorAggregator,
\Magento\Framework\Event\ManagerInterface $eventManager,
\Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
\Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration,
@@ -650,7 +671,16 @@ public function __construct(
$this->objectRelationProcessor = $objectRelationProcessor;
$this->transactionManager = $transactionManager;
$this->taxClassProcessor = $taxClassProcessor;
- parent::__construct($jsonHelper, $importExportData, $importData, $config, $resource, $resourceHelper, $string);
+ parent::__construct(
+ $jsonHelper,
+ $importExportData,
+ $importData,
+ $config,
+ $resource,
+ $resourceHelper,
+ $string,
+ $errorAggregator
+ );
$this->_optionEntity = isset(
$data['option_entity']
) ? $data['option_entity'] : $optionFactory->create(
@@ -660,7 +690,7 @@ public function __construct(
$this->_initAttributeSets()
->_initTypeModels()
->_initSkus();
- $this->validator->init();
+ $this->validator->init($this);
}
/**
@@ -670,53 +700,17 @@ public function __construct(
* @param array $attrParams Attribute params
* @param array $rowData Row data
* @param int $rowNum
- *
- * @return boolean
- *
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @return bool
*/
public function isAttributeValid($attrCode, array $attrParams, array $rowData, $rowNum)
{
- switch ($attrParams['type']) {
- case 'varchar':
- $val = $this->string->cleanString($rowData[$attrCode]);
- $valid = $this->string->strlen($val) < self::DB_MAX_VARCHAR_LENGTH;
- break;
- case 'decimal':
- $val = trim($rowData[$attrCode]);
- $valid = is_numeric($val);
- break;
- case 'select':
- case 'multiselect':
- $valid = isset($attrParams['options'][strtolower($rowData[$attrCode])]);
- break;
- case 'int':
- $val = trim($rowData[$attrCode]);
- $valid = (string)(int)$val === $val;
- break;
- case 'datetime':
- $val = trim($rowData[$attrCode]);
- $valid = strtotime($val) !== false;
- break;
- case 'text':
- $val = $this->string->cleanString($rowData[$attrCode]);
- $valid = $this->string->strlen($val) < self::DB_MAX_TEXT_LENGTH;
- break;
- default:
- $valid = true;
- break;
- }
-
- if (!$valid) {
- $this->addRowError(__("Please correct the value for '%s'."), $rowNum, $attrCode);
- } elseif (!empty($attrParams['is_unique'])) {
- if (isset($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]]) && ($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] != $rowData[self::COL_SKU])) {
- $this->addRowError(__("Duplicate Unique Attribute for '%s'"), $rowNum, $attrCode);
- return false;
+ if (!$this->validator->isAttributeValid($attrCode, $attrParams, $rowData)) {
+ foreach ($this->validator->getMessages() as $message) {
+ $this->addRowError($message, $rowNum, $attrCode);
}
- $this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] = $rowData[self::COL_SKU];
+ return false;
}
- return (bool)$valid;
+ return true;
}
/**
@@ -757,6 +751,18 @@ public function getMediaGalleryAttributeId()
return $this->_mediaGalleryAttributeId;
}
+ /**
+ * @param string $name
+ * @return mixed
+ */
+ public function retrieveProductTypeByName($name)
+ {
+ if (isset($this->_productTypeModels[$name])) {
+ return $this->_productTypeModels[$name];
+ }
+ return null;
+ }
+
/**
* Set import parameters
*
@@ -940,12 +946,23 @@ protected function _initTypeModels()
$this->_fieldsMap = array_merge($this->_fieldsMap, $model->getCustomFieldsMapping());
$this->_specialAttributes = array_merge($this->_specialAttributes, $model->getParticularAttributes());
}
+ $this->_initErrorTemplates();
// remove doubles
$this->_specialAttributes = array_unique($this->_specialAttributes);
return $this;
}
+ /**
+ * Initialize Product error templates
+ */
+ protected function _initErrorTemplates()
+ {
+ foreach ($this->_messageTemplates as $errorCode => $template) {
+ $this->addMessageTemplate($errorCode, $template);
+ }
+ }
+
/**
* Set valid attribute set and product type to rows with all scopes
* to ensure that existing products doesn't changed.
@@ -1295,6 +1312,7 @@ protected function _prepareAllMediaFiles($allImagesFromBunch)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
*/
protected function _saveProducts()
{
@@ -1323,13 +1341,16 @@ protected function _saveProducts()
if (!$this->validateRow($rowData, $rowNum)) {
continue;
}
+ if ($this->getErrorAggregator()->hasToBeTerminated()) {
+ $this->getErrorAggregator()->addRowToSkip($rowNum);
+ continue;
+ }
$rowScope = $this->getRowScope($rowData);
$rowSku = $rowData[self::COL_SKU];
if (null === $rowSku) {
- $this->_rowsToSkip[$rowNum] = true;
- // skip rows when SKU is NULL
+ $this->getErrorAggregator()->addRowToSkip($rowNum);
continue;
} elseif (self::SCOPE_STORE == $rowScope) {
// set necessary data from SCOPE_DEFAULT row
@@ -1359,7 +1380,7 @@ protected function _saveProducts()
} else {
$rowSku = null;
// sign for child rows to be skipped
- $this->_rowsToSkip[$rowNum] = true;
+ $this->getErrorAggregator()->addRowToSkip($rowNum);
continue;
}
}
@@ -1451,25 +1472,35 @@ protected function _saveProducts()
$imagePath = $allImagesFromBunch[$mediaImage];
if (isset($existingImages[$imagePath]) && in_array($rowSku, $existingImages[$imagePath])) {
if (!array_key_exists($mediaImage, $uploadedGalleryFiles)) {
- $uploadedGalleryFiles[$mediaImage] = $this->_uploadMediaFiles(
+ $uploadedFile = $this->_uploadMediaFiles(
trim($mediaImage),
true
);
+ if ($uploadedFile) {
+ $uploadedGalleryFiles[$mediaImage] = $uploadedFile;
+ } else {
+ $this->addRowError(ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, null, null, ProcessingError::ERROR_LEVEL_NOT_CRITICAL);
+ }
}
} elseif (!isset($existingImages[$imagePath])) {
if (!array_key_exists($mediaImage, $uploadedGalleryFiles)) {
- $uploadedGalleryFiles[$mediaImage] = $this->_uploadMediaFiles(
+ $uploadedFile = $this->_uploadMediaFiles(
trim($mediaImage),
true
);
- $newImagePath = $uploadedGalleryFiles[$mediaImage];
- $existingImages[$newImagePath][] = $rowSku;
+ if ($uploadedFile) {
+ $uploadedGalleryFiles[$mediaImage] = $uploadedFile;
+ $newImagePath = $uploadedGalleryFiles[$mediaImage];
+ $existingImages[$newImagePath][] = $rowSku;
+ } else {
+ $this->addRowError(ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, null, null, ProcessingError::ERROR_LEVEL_NOT_CRITICAL);
+ }
}
- $rowData[self::COL_MEDIA_IMAGE][] = $uploadedGalleryFiles[$mediaImage];
- if (!empty($rowData[self::COL_MEDIA_IMAGE]) && is_array($rowData[self::COL_MEDIA_IMAGE])) {
- $position = array_search($mediaImage, $mediaGalleryImages);
- foreach ($rowData[self::COL_MEDIA_IMAGE] as $mediaImage) {
- if (!empty($mediaImage)) {
+ if (isset($uploadedGalleryFiles[$mediaImage])) {
+ $rowData[self::COL_MEDIA_IMAGE][] = $uploadedGalleryFiles[$mediaImage];
+ if (!empty($rowData[self::COL_MEDIA_IMAGE]) && is_array($rowData[self::COL_MEDIA_IMAGE])) {
+ $position = array_search($mediaImage, $mediaGalleryImages);
+ foreach ($rowData[self::COL_MEDIA_IMAGE] as $mediaImage) {
$mediaGallery[$rowSku][] = [
'attribute_id' => $this->getMediaGalleryAttributeId(),
'label' => isset($mediaGalleryLabels[$position]) ? $mediaGalleryLabels[$position] : '',
@@ -1539,10 +1570,7 @@ protected function _saveProducts()
$product = $this->_proxyProdFactory->create(['data' => $rowData]);
foreach ($rowData as $attrCode => $attrValue) {
- if (!isset($this->_attributeCache[$attrCode])) {
- $this->_attributeCache[$attrCode] = $resource->getAttribute($attrCode);
- }
- $attribute = $this->_attributeCache[$attrCode];
+ $attribute = $this->retrieveAttributeByCode($attrCode);
if ('multiselect' != $attribute->getFrontendInput() && self::SCOPE_NULL == $rowScope) {
// skip attribute processing for SCOPE_NULL rows
@@ -1574,16 +1602,7 @@ protected function _saveProducts()
}
}
foreach ($storeIds as $storeId) {
- if ('multiselect' == $attribute->getFrontendInput()) {
- if (!isset($attributes[$attrTable][$rowSku][$attrId][$storeId])) {
- $attributes[$attrTable][$rowSku][$attrId][$storeId] = '';
- } else {
- $attributes[$attrTable][$rowSku][$attrId][$storeId] .= ',';
- }
- $attributes[$attrTable][$rowSku][$attrId][$storeId] .= $attrValue;
- } else {
- $attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue;
- }
+ $attributes[$attrTable][$rowSku][$attrId][$storeId] = $attrValue;
}
// restore 'backend_model' to avoid 'default' setting
$attribute->setBackendModel($backModel);
@@ -1987,6 +2006,23 @@ protected function _saveStockItem()
return $this;
}
+ /**
+ * Retrieve attribute by code
+ *
+ * @param string $attrCode
+ * @return mixed
+ */
+ public function retrieveAttributeByCode($attrCode)
+ {
+ if (!$this->_resource) {
+ $this->_resource = $this->_resourceFactory->create();
+ }
+ if (!isset($this->_attributeCache[$attrCode])) {
+ $this->_attributeCache[$attrCode] = $this->_resource->getAttribute($attrCode);
+ }
+ return $this->_attributeCache[$attrCode];
+ }
+
/**
* Attribute set ID-to-name pairs getter.
*
@@ -2067,9 +2103,6 @@ public function getCategoryProcessor()
*/
public function getRowScope(array $rowData)
{
- if (empty($rowData[self::COL_SKU])) {
- return self::SCOPE_NULL;
- }
if (empty($rowData[self::COL_STORE])) {
return self::SCOPE_DEFAULT;
}
@@ -2088,11 +2121,9 @@ public function getRowScope(array $rowData)
*/
public function validateRow(array $rowData, $rowNum)
{
- // SKU is remembered through all product rows
- static $sku = null;
if (isset($this->_validatedRows[$rowNum])) {
// check that row is already validated
- return !isset($this->_invalidRows[$rowNum]);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNum);
}
$this->_validatedRows[$rowNum] = true;
@@ -2152,10 +2183,10 @@ public function validateRow(array $rowData, $rowNum)
if (!isset($rowData[self::COL_TYPE]) || !isset($this->_productTypeModels[$rowData[self::COL_TYPE]])) {
$this->addRowError(ValidatorInterface::ERROR_INVALID_TYPE, $rowNum);
} elseif (!isset(
- $rowData[self::COL_ATTR_SET]
- ) || !isset(
- $this->_attrSetNameToId[$rowData[self::COL_ATTR_SET]]
- )
+ $rowData[self::COL_ATTR_SET]
+ ) || !isset(
+ $this->_attrSetNameToId[$rowData[self::COL_ATTR_SET]]
+ )
) {
$this->addRowError(ValidatorInterface::ERROR_INVALID_ATTR_SET, $rowNum);
} elseif (is_null($this->skuProcessor->getNewSku($sku))) {
@@ -2169,13 +2200,13 @@ public function validateRow(array $rowData, $rowNum)
]
);
}
- if (isset($this->_invalidRows[$rowNum])) {
+ if ($this->getErrorAggregator()->isRowInvalid($rowNum)) {
// mark SCOPE_DEFAULT row as invalid for future child rows if product not in DB already
$sku = false;
}
}
- if (!isset($this->_invalidRows[$rowNum])) {
+ if (!$this->getErrorAggregator()->isRowInvalid($rowNum)) {
$newSku = $this->skuProcessor->getNewSku($sku);
// set attribute set code into row data for followed attribute validation in type model
$rowData[self::COL_ATTR_SET] = $newSku['attr_set_code'];
@@ -2193,7 +2224,7 @@ public function validateRow(array $rowData, $rowNum)
// validate custom options
$this->getOptionEntity()->validateRow($rowData, $rowNum);
- return !isset($this->_invalidRows[$rowNum]);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNum);
}
/**
@@ -2276,16 +2307,18 @@ protected function _saveValidatedBunches()
$source = $this->_getSource();
$source->rewind();
while ($source->valid()) {
- if ($this->_errorsCount >= $this->_errorsLimit) {
- // errors limit check
- return $this;
+ try {
+ $rowData = $source->current();
+ } catch (\InvalidArgumentException $e) {
+ $this->addRowError($e->getMessage(), $this->_processedRowsCount);
+ $this->_processedRowsCount++;
+ $source->next();
+ continue;
}
- $rowData = $source->current();
$rowData = $this->_customFieldsMapping($rowData);
$this->validateRow($rowData, $source->key());
- $this->_processedRowsCount++;
$source->next();
}
$this->getOptionEntity()->validateAmbiguousData();
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
index ea10b871516b1..b8a629ca16d54 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php
@@ -10,6 +10,7 @@
use Magento\CatalogImportExport\Model\Import\Product;
use Magento\Framework\App\Resource;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
/**
* Entity class which provide possibility to import product custom options
@@ -305,7 +306,7 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
/**
* @param \Magento\ImportExport\Model\Resource\Import\Data $importData
- * @param \Magento\Framework\App\Resource $resource
+ * @param Resource $resource
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Store\Model\StoreManagerInterface $_storeManager
* @param \Magento\Catalog\Model\ProductFactory $productFactory
@@ -314,7 +315,9 @@ class Option extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
* @param \Magento\Catalog\Helper\Data $catalogData
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Framework\Stdlib\DateTime $dateTime
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param array $data
+ * @throws \Magento\Framework\Exception\LocalizedException
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
@@ -329,6 +332,7 @@ public function __construct(
\Magento\Catalog\Helper\Data $catalogData,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Framework\Stdlib\DateTime $dateTime,
+ ProcessingErrorAggregatorInterface $errorAggregator,
array $data = []
) {
$this->_resource = $resource;
@@ -359,6 +363,8 @@ public function __construct(
$this->_isPriceGlobal = $this->_catalogData->isPriceGlobal();
}
+ $this->errorAggregator = $errorAggregator;
+
$this->_initSourceEntities($data)->_initTables($data)->_initStores($data);
$this->_initMessageTemplates();
@@ -376,32 +382,32 @@ protected function _initMessageTemplates()
// @codingStandardsIgnoreStart
$this->_productEntity->addMessageTemplate(
self::ERROR_INVALID_STORE,
- __('Please enter a correct value for "store."')
+ __('Value for \'price\' sub attribute in \'store\' attribute contains incorrect value')
);
$this->_productEntity->addMessageTemplate(
self::ERROR_INVALID_TYPE,
- __('Please enter a correct value for "type."')
+ __('Value for \'type\' sub attribute in \'custom_options\' attribute contains incorrect value, acceptable values are: \'dropdown\', \'checkbox\'')
);
$this->_productEntity->addMessageTemplate(self::ERROR_EMPTY_TITLE, __('Please enter a value for title.'));
$this->_productEntity->addMessageTemplate(
self::ERROR_INVALID_PRICE,
- __('Please enter a correct value for "price."')
+ __('Value for \'price\' sub attribute in \'custom_options\' attribute contains incorrect value')
);
$this->_productEntity->addMessageTemplate(
self::ERROR_INVALID_MAX_CHARACTERS,
- __('Please enter a correct value for "maximum characters."')
+ __('Value for \'maximum characters\' sub attribute in \'custom_options\' attribute contains incorrect value')
);
$this->_productEntity->addMessageTemplate(
self::ERROR_INVALID_SORT_ORDER,
- __('Please enter a correct value for "sort order."')
+ __('Value for \'sort order\' sub attribute in \'custom_options\' attribute contains incorrect value')
);
$this->_productEntity->addMessageTemplate(
self::ERROR_INVALID_ROW_PRICE,
- __('Please enter a correct value for "value price."')
+ __('Value for \'value price\' sub attribute in \'custom_options\' attribute contains incorrect value')
);
$this->_productEntity->addMessageTemplate(
self::ERROR_INVALID_ROW_SORT,
- __('Please enter a correct value for "sort order."')
+ __('Value for \'sort order\' sub attribute in \'custom_options\' attribute contains incorrect value')
);
$this->_productEntity->addMessageTemplate(
self::ERROR_AMBIGUOUS_NEW_NAMES,
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php
index 4e986422eee52..c639fcc4acf25 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/RowValidatorInterface.php
@@ -61,6 +61,26 @@ interface RowValidatorInterface extends \Magento\Framework\Validator\ValidatorIn
const ERROR_INVALID_WEIGHT = 'invalidWeight';
+ const ERROR_EXCEEDED_MAX_LENGTH = 'exceededMaxLength';
+
+ const ERROR_INVALID_ATTRIBUTE_TYPE = 'invalidAttributeType';
+
+ const ERROR_INVALID_ATTRIBUTE_DECIMAL = 'invalidAttributeDecimal';
+
+ const ERROR_ABSENT_REQUIRED_ATTRIBUTE = 'absentRequiredAttribute';
+
+ const ERROR_INVALID_ATTRIBUTE_OPTION = 'absentAttributeOption';
+
+ const ERROR_DUPLICATE_UNIQUE_ATTRIBUTE = 'duplicatedUniqueAttribute';
+
+ const ERROR_INVALID_VARIATIONS_CUSTOM_OPTIONS = 'invalidVariationsCustomOptions';
+
+ const ERROR_INVALID_MEDIA_URL_OR_PATH = 'invalidMediaUrlPath';
+
+ const ERROR_MEDIA_URL_NOT_ACCESSIBLE = 'mediaUrlNotAvailable';
+
+ const ERROR_MEDIA_PATH_NOT_ACCESSIBLE = 'mediaPathNotAvailable';
+
/**
* Value that means all entities (e.g. websites, groups etc.)
*/
@@ -69,7 +89,8 @@ interface RowValidatorInterface extends \Magento\Framework\Validator\ValidatorIn
/**
* Initialize validator
*
+ * @param \Magento\CatalogImportExport\Model\Import\Product $context
* @return $this
*/
- public function init();
+ public function init($context);
}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
index fc55964e71ed2..7fe262fbf57c0 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php
@@ -6,11 +6,13 @@
namespace Magento\CatalogImportExport\Model\Import\Product\Type;
use Magento\Framework\App\Resource;
+use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
+use Magento\CatalogImportExport\Model\Import\Product;
/**
* Import entity abstract product type model
*
- * @author Magento Core Team
+ * @SuppressWarnings(PHPMD.TooManyFields)
*/
abstract class AbstractType
{
@@ -21,6 +23,13 @@ abstract class AbstractType
*/
public static $commonAttributesCache = [];
+ /**
+ * Attribute Code to Id cache
+ *
+ * @var array
+ */
+ public static $attributeCodeToId = [];
+
/**
* Product type attribute sets and attributes parameters.
*
@@ -53,12 +62,22 @@ abstract class AbstractType
protected $_indexValueAttributes = [];
/**
- * Validation failure message template definitions
+ * Validation failure entity specific message template definitions
*
* @var array
*/
protected $_messageTemplates = [];
+ /**
+ * Validation failure general message template definitions
+ *
+ * @var array
+ */
+ protected $_genericMessageTemplates = [
+ RowValidatorInterface::ERROR_INVALID_WEIGHT => 'Weight value is incorrect',
+ RowValidatorInterface::ERROR_INVALID_WEBSITE => 'Provided Website code doesn\'t exist'
+ ];
+
/**
* Column names that holds values with particular meaning.
*
@@ -107,7 +126,6 @@ abstract class AbstractType
*/
protected $connection;
-
/**
* @param \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory $attrSetColFac
* @param \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory $prodAttrColFac
@@ -136,13 +154,27 @@ public function __construct(
$this->_entityModel = $params[0];
$this->_type = $params[1];
- foreach ($this->_messageTemplates as $errorCode => $message) {
- $this->_entityModel->addMessageTemplate($errorCode, $message);
- }
+ $this->initMessageTemplates(
+ array_merge($this->_genericMessageTemplates, $this->_messageTemplates)
+ );
+
$this->_initAttributes();
}
}
+ /**
+ * @param array $templateCollection
+ * @return $this
+ */
+ protected function initMessageTemplates(array $templateCollection)
+ {
+ foreach ($templateCollection as $errorCode => $message) {
+ $this->_entityModel->addMessageTemplate($errorCode, $message);
+ }
+
+ return $this;
+ }
+
/**
* Add attribute parameters to appropriate attribute set.
*
@@ -160,6 +192,21 @@ protected function _addAttributeParams($attrSetName, array $attrParams, $attribu
return $this;
}
+ /**
+ * Retrieve product Attribute
+ *
+ * @param string $attributeCode
+ * @param string $attributeSet
+ * @return array
+ */
+ public function retrieveAttribute($attributeCode, $attributeSet)
+ {
+ if (isset($this->_attributes[$attributeSet]) && isset($this->_attributes[$attributeSet][$attributeCode])) {
+ return $this->_attributes[$attributeSet][$attributeCode];
+ }
+ return [];
+ }
+
/**
* Return product attributes for its attribute set specified in row data.
*
@@ -184,7 +231,7 @@ protected function _initAttributes()
{
// temporary storage for attributes' parameters to avoid double querying inside the loop
$entityId = $this->_entityModel->getEntityTypeId();
- $entityAttributes = $this->_connection->fetchPairs(
+ $entityAttributes = $this->_connection->fetchAll(
$this->_connection->select()->from(
['attr' => $this->_resource->getTableName('eav_entity_attribute')],
['attr.attribute_id']
@@ -197,23 +244,23 @@ protected function _initAttributes()
)
);
$absentKeys = [];
- foreach ($entityAttributes as $attributeId => $attributeSetName) {
- if (!isset(self::$commonAttributesCache[$attributeId])) {
- if (!isset($absentKeys[$attributeSetName])) {
- $absentKeys[$attributeSetName] = [];
+ foreach ($entityAttributes as $attributeRow) {
+ if (!isset(self::$commonAttributesCache[$attributeRow['attribute_id']])) {
+ if (!isset($absentKeys[$attributeRow['attribute_set_name']])) {
+ $absentKeys[$attributeRow['attribute_set_name']] = [];
}
- $absentKeys[$attributeSetName][] = $attributeId;
+ $absentKeys[$attributeRow['attribute_set_name']][] = $attributeRow['attribute_id'];
}
}
foreach ($absentKeys as $attributeSetName => $attributeIds) {
$this->attachAttributesById($attributeSetName, $attributeIds);
}
- foreach ($entityAttributes as $attributeId => $attributeSetName) {
- if (isset(self::$commonAttributesCache[$attributeId])) {
- $attribute = self::$commonAttributesCache[$attributeId];
+ foreach ($entityAttributes as $attributeRow) {
+ if (isset(self::$commonAttributesCache[$attributeRow['attribute_id']])) {
+ $attribute = self::$commonAttributesCache[$attributeRow['attribute_id']];
$this->_addAttributeParams(
- $attributeSetName,
- self::$commonAttributesCache[$attributeId],
+ $attributeRow['attribute_set_name'],
+ self::$commonAttributesCache[$attributeRow['attribute_id']],
$attribute
);
}
@@ -256,6 +303,7 @@ protected function attachAttributesById($attributeSetName, $attributeIds)
$this->_indexValueAttributes
),
];
+ self::$attributeCodeToId[$attributeCode] = $attributeId;
$this->_addAttributeParams(
$attributeSetName,
self::$commonAttributesCache[$attributeId],
@@ -265,6 +313,22 @@ protected function attachAttributesById($attributeSetName, $attributeIds)
}
}
+ /**
+ * Retrieve attribute from cache
+ *
+ * @param string $attributeCode
+ * @return mixed
+ */
+ public function retrieveAttributeFromCache($attributeCode)
+ {
+ if (isset(self::$attributeCodeToId[$attributeCode]) && $id = self::$attributeCodeToId[$attributeCode]) {
+ if (isset(self::$commonAttributesCache[$id])) {
+ return self::$commonAttributesCache[$id];
+ }
+ }
+ return [];
+ }
+
/**
* In case we've dynamically added new attribute option during import we need to add it to our cache
* in order to keep it up to date.
@@ -354,8 +418,10 @@ public function isRowValid(array $rowData, $rowNum, $isNewProduct = true)
{
$error = false;
$rowScope = $this->_entityModel->getRowScope($rowData);
+ if ((\Magento\CatalogImportExport\Model\Import\Product::SCOPE_NULL != $rowScope) &&
+ !empty($rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_SKU])) {
+
- if (\Magento\CatalogImportExport\Model\Import\Product::SCOPE_NULL != $rowScope) {
foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
// check value for non-empty in the case of required attribute?
if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
@@ -414,10 +480,16 @@ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDe
foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) {
if (!$attrParams['is_static']) {
if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) {
- $resultAttrs[$attrCode] = 'select' == $attrParams['type'] ||
- 'multiselect' == $attrParams['type'] ? $attrParams['options'][strtolower(
- $rowData[$attrCode]
- )] : $rowData[$attrCode];
+ $resultAttrs[$attrCode] = 'select' == $attrParams['type'] ? $attrParams['options'][strtolower(
+ $rowData[$attrCode]
+ )] : $rowData[$attrCode];
+ if ('multiselect' == $attrParams['type']) {
+ $resultAttrs[$attrCode] = [];
+ foreach (explode(Product::PSEUDO_MULTI_LINE_SEPARATOR, $rowData[$attrCode]) as $value) {
+ $resultAttrs[$attrCode][] = $attrParams['options'][strtolower($value)];
+ }
+ $resultAttrs[$attrCode] = implode(',', $resultAttrs[$attrCode]);
+ }
} elseif (array_key_exists($attrCode, $rowData)) {
$resultAttrs[$attrCode] = $rowData[$attrCode];
} elseif ($withDefaultValue && null !== $attrParams['default_value']) {
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/Virtual.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/Virtual.php
new file mode 100644
index 0000000000000..aff410936e08d
--- /dev/null
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/Virtual.php
@@ -0,0 +1,48 @@
+
+ */
+class Virtual extends \Magento\CatalogImportExport\Model\Import\Product\Type\Simple
+{
+ /**
+ * Type virtual product
+ */
+ const TYPE_VIRTUAL_PRODUCT = 'virtual';
+
+ /**
+ * Prepare attributes with default value for save.
+ *
+ * @param array $rowData
+ * @param bool $withDefaultValue
+ * @return array
+ */
+ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDefaultValue = true)
+ {
+ $resultAttrs = parent::prepareAttributesWithDefaultValueForSave($rowData, $withDefaultValue);
+ $resultAttrs = array_merge($resultAttrs, $this->setWeightVirtualProduct($rowData));
+ return $resultAttrs;
+ }
+
+ /**
+ * Set weight is null if product is virtual
+ *
+ * @param array $rowData
+ * @return array
+ */
+ protected function setWeightVirtualProduct(array $rowData)
+ {
+ $result = [];
+ if ($rowData['product_type'] == self::TYPE_VIRTUAL_PRODUCT) {
+ $result['weight'] = null;
+ }
+ return $result;
+ }
+}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php
index 0f44d54947164..980535ce2d8b5 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php
@@ -5,6 +5,7 @@
*/
namespace Magento\CatalogImportExport\Model\Import\Product;
+use \Magento\CatalogImportExport\Model\Import\Product;
use \Magento\Framework\Validator\AbstractValidator;
class Validator extends AbstractValidator implements RowValidatorInterface
@@ -15,20 +16,207 @@ class Validator extends AbstractValidator implements RowValidatorInterface
protected $validators = [];
/**
+ * @var \Magento\CatalogImportExport\Model\Import\Product
+ */
+ protected $context;
+
+ /**
+ * @var \Magento\Framework\Stdlib\StringUtils
+ */
+ protected $string;
+
+ /**
+ * @var array
+ */
+ protected $_uniqueAttributes;
+
+ /**
+ * @var array
+ */
+ protected $_rowData;
+
+ /**
+ * @param \Magento\Framework\Stdlib\StringUtils $string
* @param RowValidatorInterface[] $validators
*/
- public function __construct($validators = [])
- {
+ public function __construct(
+ \Magento\Framework\Stdlib\StringUtils $string,
+ $validators = []
+ ) {
+ $this->string = $string;
$this->validators = $validators;
}
+ /**
+ * @param mixed $attrCode
+ * @param string $type
+ * @return bool
+ */
+ protected function textValidation($attrCode, $type)
+ {
+ $val = $this->string->cleanString($this->_rowData[$attrCode]);
+ if ($type == 'text') {
+ $valid = $this->string->strlen($val) < Product::DB_MAX_TEXT_LENGTH;
+ } else {
+ $valid = $this->string->strlen($val) < Product::DB_MAX_VARCHAR_LENGTH;
+ }
+ if (!$valid) {
+ $this->_addMessages([RowValidatorInterface::ERROR_EXCEEDED_MAX_LENGTH]);
+ }
+ return $valid;
+ }
+
+ /**
+ * @param mixed $attrCode
+ * @param string $type
+ * @return bool
+ */
+ protected function numericValidation($attrCode, $type)
+ {
+ $val = trim($this->_rowData[$attrCode]);
+ if ($type == 'int') {
+ $valid = (string)(int)$val === $val;
+ } else {
+ $valid = is_numeric($val);
+ }
+ if (!$valid) {
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(RowValidatorInterface::ERROR_INVALID_ATTRIBUTE_TYPE),
+ $attrCode,
+ $type
+ )
+ ]
+ );
+ }
+ return $valid;
+ }
+
+ /**
+ * @param string $attrCode
+ * @param array $attrParams
+ * @param array $rowData
+ * @return bool
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ */
+ public function isAttributeValid($attrCode, array $attrParams, array $rowData)
+ {
+ $this->_rowData = $rowData;
+ if (!empty($attrParams['apply_to']) && !in_array($rowData['product_type'], $attrParams['apply_to'])) {
+ return true;
+ }
+ if ($attrCode == Product::COL_SKU || $attrParams['is_required']
+ && ($this->context->getBehavior() == \Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE
+ || ($this->context->getBehavior() == \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND
+ && !isset($this->context->getOldSku()[$rowData[$attrCode]])))
+ ) {
+ if (!isset($rowData[$attrCode]) || !strlen(trim($rowData[$attrCode]))) {
+ $valid = false;
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(
+ RowValidatorInterface::ERROR_VALUE_IS_REQUIRED
+ ),
+ $attrCode
+ )
+ ]
+ );
+ return $valid;
+ }
+ }
+
+ if (!strlen(trim($rowData[$attrCode]))) {
+ return true;
+ }
+ switch ($attrParams['type']) {
+ case 'varchar':
+ case 'text':
+ $valid = $this->textValidation($attrCode, $attrParams['type']);
+ break;
+ case 'decimal':
+ case 'int':
+ $valid = $this->numericValidation($attrCode, $attrParams['type']);
+ break;
+ case 'select':
+ case 'multiselect':
+ $values = explode(Product::PSEUDO_MULTI_LINE_SEPARATOR, $rowData[$attrCode]);
+ $valid = true;
+ foreach ($values as $value) {
+ $valid = $valid || isset($attrParams['options'][strtolower($value)]);
+ }
+ if (!$valid) {
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(
+ RowValidatorInterface::ERROR_INVALID_ATTRIBUTE_OPTION
+ ),
+ $attrCode
+ )
+ ]
+ );
+ }
+ break;
+ case 'datetime':
+ $val = trim($rowData[$attrCode]);
+ $valid = strtotime($val) !== false;
+ if (!$valid) {
+ $this->_addMessages([RowValidatorInterface::ERROR_INVALID_ATTRIBUTE_TYPE]);
+ }
+ break;
+ default:
+ $valid = true;
+ break;
+ }
+
+ if ($valid && !empty($attrParams['is_unique'])) {
+ if (isset($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]])
+ && ($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] != $rowData[Product::COL_SKU])) {
+ $this->_addMessages([RowValidatorInterface::ERROR_DUPLICATE_UNIQUE_ATTRIBUTE]);
+ return false;
+ }
+ $this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] = $rowData[Product::COL_SKU];
+ }
+ return (bool)$valid;
+
+ }
+
+ /**
+ * @return bool
+ * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+ */
+ protected function isValidAttributes()
+ {
+ $this->_clearMessages();
+ if (!isset($this->_rowData['product_type'])) {
+ return false;
+ }
+ $entityTypeModel = $this->context->retrieveProductTypeByName($this->_rowData['product_type']);
+ if ($entityTypeModel) {
+ foreach ($this->_rowData as $attrCode => $attrValue) {
+ $attrParams = $entityTypeModel->retrieveAttributeFromCache($attrCode);
+ if ($attrParams) {
+ $this->isAttributeValid($attrCode, $attrParams, $this->_rowData);
+ }
+ }
+ if ($this->getMessages()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* {@inheritdoc}
*/
public function isValid($value)
{
- $returnValue = true;
+ $this->_rowData = $value;
$this->_clearMessages();
+ $returnValue = $this->isValidAttributes();
foreach ($this->validators as $validator) {
if (!$validator->isValid($value)) {
$returnValue = false;
@@ -39,12 +227,14 @@ public function isValid($value)
}
/**
- * {@inheritdoc}
+ * @param \Magento\CatalogImportExport\Model\Import\Product $context
+ * @return $this
*/
- public function init()
+ public function init($context)
{
+ $this->context = $context;
foreach ($this->validators as $validator) {
- $validator->init();
+ $validator->init($context);
}
}
}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractImportValidator.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractImportValidator.php
new file mode 100644
index 0000000000000..519a5457bcd74
--- /dev/null
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractImportValidator.php
@@ -0,0 +1,27 @@
+context = $context;
+ return $this;
+ }
+}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractPrice.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractPrice.php
index 1f6f41ffaa5b4..8810272f16605 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractPrice.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/AbstractPrice.php
@@ -5,10 +5,10 @@
*/
namespace Magento\CatalogImportExport\Model\Import\Product\Validator;
-use Magento\Framework\Validator\AbstractValidator;
+use Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
-abstract class AbstractPrice extends AbstractValidator implements RowValidatorInterface
+abstract class AbstractPrice extends AbstractImportValidator implements RowValidatorInterface
{
/**
* @var \Magento\Customer\Api\GroupRepositoryInterface
@@ -42,11 +42,11 @@ public function __construct(
/**
* {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
foreach ($this->groupRepository->getList($this->searchCriteriaBuilder->create())->getItems() as $group) {
$this->customerGroups[$group->getId()] = true;
}
- return $this;
+ return parent::init($context);
}
}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/GroupPrice.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/GroupPrice.php
index 2d27b9867a9a4..56d6aebd0441b 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/GroupPrice.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/GroupPrice.php
@@ -31,9 +31,9 @@ public function __construct(
/**
* {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
- return parent::init();
+ return parent::init($context);
}
/**
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php
index fd3b69e0ac5a7..c5c96ea23462f 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php
@@ -5,25 +5,99 @@
*/
namespace Magento\CatalogImportExport\Model\Import\Product\Validator;
-use \Magento\Framework\Validator\AbstractValidator;
+use Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
-class Media extends AbstractValidator implements RowValidatorInterface
+class Media extends AbstractImportValidator implements RowValidatorInterface
{
+ const URL_REGEXP = '|^http(s)?://[a-z0-9-]+(.[a-z0-9-]+)*(:[0-9]+)?(/.*)?$|i';
+
+ const PATH_REGEXP = '#^(?!.*[\\/]\.{2}[\\/])(?!\.{2}[\\/])[-\w.\\/]+$#';
+
+ const ADDITIONAL_IMAGES = 'additional_images';
+
+ const ADDITIONAL_IMAGES_DELIMITER = ',';
+
+ /** @var array */
+ protected $mediaAttributes = ['image', 'small_image', 'thumbnail'];
+
/**
* {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
- return $this;
+ return parent::init($context);
}
/**
- * {@inheritdoc}
+ * @param string $string
+ * @return bool
+ */
+ protected function checkValidUrl($string)
+ {
+ return preg_match(self::URL_REGEXP, $string);
+ }
+
+ /**
+ * @param string $string
+ * @return bool
+ */
+ protected function checkPath($string)
+ {
+ return preg_match(self::PATH_REGEXP, $string);
+ }
+
+ /**
+ * @param string $path
+ * @return bool
+ */
+ protected function checkFileExists($path)
+ {
+ return file_exists($path);
+ }
+
+ /**
+ * Validate value
+ *
+ * @param array $value
+ * @return bool
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function isValid($value)
{
$this->_clearMessages();
- return true;
+ $valid = true;
+ foreach ($this->mediaAttributes as $attribute) {
+ if (isset($value[$attribute]) && strlen($value[$attribute])) {
+ if (!$this->checkPath($value[$attribute]) && !$this->checkValidUrl($value[$attribute])) {
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(self::ERROR_INVALID_MEDIA_URL_OR_PATH),
+ $attribute
+ )
+ ]
+ );
+ $valid = false;
+ }
+ }
+ }
+ if (isset($value[self::ADDITIONAL_IMAGES]) && strlen($value[self::ADDITIONAL_IMAGES])) {
+ foreach (explode(self::ADDITIONAL_IMAGES_DELIMITER, $value[self::ADDITIONAL_IMAGES]) as $image) {
+ if (!$this->checkPath($image) && !$this->checkValidUrl($image)) {
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(self::ERROR_INVALID_MEDIA_URL_OR_PATH),
+ self::ADDITIONAL_IMAGES
+ )
+ ]
+ );
+ $valid = false;
+ }
+ break;
+ }
+ }
+ return $valid;
}
}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Quantity.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Quantity.php
new file mode 100644
index 0000000000000..4e40cc5cc47c9
--- /dev/null
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Quantity.php
@@ -0,0 +1,41 @@
+_clearMessages();
+ if (!empty($value['qty']) && (!is_numeric($value['qty']) || $value['qty'] < 0)) {
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(self::ERROR_INVALID_ATTRIBUTE_TYPE),
+ 'qty',
+ 'decimal'
+ )
+ ]
+ );
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/SuperProductsSku.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/SuperProductsSku.php
index ac3329f0d8f04..44c4bbbb7a0df 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/SuperProductsSku.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/SuperProductsSku.php
@@ -5,10 +5,10 @@
*/
namespace Magento\CatalogImportExport\Model\Import\Product\Validator;
-use \Magento\Framework\Validator\AbstractValidator;
+use Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
-class SuperProductsSku extends AbstractValidator implements RowValidatorInterface
+class SuperProductsSku extends AbstractImportValidator implements RowValidatorInterface
{
/**
* @var \Magento\CatalogImportExport\Model\Import\Product\SkuProcessor
@@ -27,9 +27,9 @@ public function __construct(
/**
* {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
- return $this;
+ return parent::init($context);
}
/**
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPrice.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPrice.php
index 489bbe11a3f9f..aeb9862a7d94a 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPrice.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/TierPrice.php
@@ -31,9 +31,9 @@ public function __construct(
/**
* {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
- return parent::init();
+ return parent::init($context);
}
/**
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Website.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Website.php
index 0547d7820036f..3865bc73e5a65 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Website.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Website.php
@@ -5,10 +5,11 @@
*/
namespace Magento\CatalogImportExport\Model\Import\Product\Validator;
-use \Magento\Framework\Validator\AbstractValidator;
+use Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
+use Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
-class Website extends AbstractValidator implements RowValidatorInterface
+class Website extends AbstractImportValidator implements RowValidatorInterface
{
/**
* @var \Magento\CatalogImportExport\Model\Import\Product\StoreResolver
@@ -26,9 +27,9 @@ public function __construct(\Magento\CatalogImportExport\Model\Import\Product\St
/**
* {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
- return $this;
+ return parent::init($context);
}
/**
@@ -37,11 +38,16 @@ public function init()
public function isValid($value)
{
$this->_clearMessages();
- if (!empty($value['_product_websites'])
- && !$this->storeResolver->getWebsiteCodeToId($value['_product_websites'])
- ) {
- $this->_addMessages([self::ERROR_INVALID_WEBSITE]);
- return false;
+ if (empty($value[ImportProduct::COL_PRODUCT_WEBSITES])) {
+ return true;
+ }
+ $separator = $this->context->getMultipleValueSeparator();
+ $websites = explode($separator, $value[ImportProduct::COL_PRODUCT_WEBSITES]);
+ foreach ($websites as $website) {
+ if (!$this->storeResolver->getWebsiteCodeToId($website)) {
+ $this->_addMessages([self::ERROR_INVALID_WEBSITE]);
+ return false;
+ }
}
return true;
}
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Weight.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Weight.php
index 5e6cea959fa8e..8f69496d32956 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Weight.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Weight.php
@@ -5,17 +5,17 @@
*/
namespace Magento\CatalogImportExport\Model\Import\Product\Validator;
-use \Magento\Framework\Validator\AbstractValidator;
+use Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator;
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
-class Weight extends AbstractValidator implements RowValidatorInterface
+class Weight extends AbstractImportValidator implements RowValidatorInterface
{
/**
* {@inheritdoc}
*/
- public function init()
+ public function init($context)
{
- return $this;
+ return parent::init($context);
}
/**
@@ -25,7 +25,15 @@ public function isValid($value)
{
$this->_clearMessages();
if (!empty($value['weight']) && (!is_numeric($value['weight']) || $value['weight'] < 0)) {
- $this->_addMessages([self::ERROR_INVALID_WEIGHT]);
+ $this->_addMessages(
+ [
+ sprintf(
+ $this->context->retrieveMessageTemplate(self::ERROR_INVALID_ATTRIBUTE_TYPE),
+ 'weight',
+ 'decimal'
+ )
+ ]
+ );
return false;
}
return true;
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php
index be93163a876c9..4b07ee981af02 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php
@@ -118,9 +118,10 @@ protected function setUp()
false
);
- $entityAttributes = [
- 'attribute_id' => 'attributeSetName'
- ];
+ $entityAttributes = [[
+ 'attribute_id' => 'attribute_id',
+ 'attribute_set_name' => 'attributeSetName',
+ ]];
$this->entityModel->expects($this->any())->method('getEntityTypeId')->willReturn(3);
$this->entityModel->expects($this->any())->method('getAttributeOptions')->willReturn(['option1', 'option2']);
@@ -147,9 +148,7 @@ protected function setUp()
->method('addFieldToFilter')
->with(
'main_table.attribute_id',
- ['in' => [
- key($entityAttributes)
- ]]
+ ['in' => ['attribute_id']]
)
->willReturn([$attribute]);
@@ -192,7 +191,7 @@ protected function setUp()
$this->connection->expects($this->any())->method('quoteInto')->willReturn('');
$this->connection
->expects($this->any())
- ->method('fetchPairs')
+ ->method('fetchAll')
->will($this->returnValue($entityAttributes));
$this->resource = $this->getMock(
@@ -279,6 +278,7 @@ public function testIsRowValidError()
{
$rowData = [
'_attribute_set' => 'attribute_set_name',
+ 'sku' => 'sku'
];
$rowNum = 1;
$this->entityModel->expects($this->any())->method('getRowScope')->willReturn(1);
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
index cb9323439e3c2..da52456ccaca7 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/OptionTest.php
@@ -11,18 +11,13 @@
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
*/
-class OptionTest extends \PHPUnit_Framework_TestCase
+class OptionTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
* Path to csv file to import
*/
const PATH_TO_CSV_FILE = '/_files/product_with_custom_options.csv';
- /**
- * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
- */
- protected $_helper;
-
/**
* Test store parametes
*
@@ -208,12 +203,18 @@ class OptionTest extends \PHPUnit_Framework_TestCase
*/
protected $_iteratorPageSize = 100;
+ /**
+ * @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface
+ */
+ protected $errorAggregator;
+
/**
* Init entity adapter model
*/
protected function setUp()
{
- $this->_helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+ parent::setUp();
+
$addExpectations = false;
$deleteBehavior = false;
$testName = $this->getName(true);
@@ -231,7 +232,6 @@ protected function setUp()
$scopeConfig = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
- $modelClassName = '\Magento\CatalogImportExport\Model\Import\Product\Option';
$modelClassArgs = [
$this->getMock('Magento\ImportExport\Model\Resource\Import\Data', [], [], '', false),
$this->getMock('Magento\Framework\App\Resource', [], [], '', false),
@@ -255,9 +255,17 @@ protected function setUp()
$catalogDataMock,
$scopeConfig,
new \Magento\Framework\Stdlib\DateTime(),
+ $this->getMock(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface',
+ [],
+ [],
+ '',
+ false
+ ),
$this->_getModelDependencies($addExpectations, $deleteBehavior, $doubleOptions)
];
+ $modelClassName = '\Magento\CatalogImportExport\Model\Import\Product\Option';
$class = new \ReflectionClass($modelClassName);
$this->_model = $class->newInstanceArgs($modelClassArgs);
// Create model mock with rewritten _getMultiRowFormat method to support test data with the old format.
@@ -381,11 +389,12 @@ protected function _getSourceDataMocks($addExpectations, $doubleOptions)
$this->_productEntity = $this->getMock(
'Magento\CatalogImportExport\Model\Import\Product',
- null,
+ ['getErrorAggregator'],
[],
'',
false
);
+ $this->_productEntity->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
$productModelMock = $this->getMock('stdClass', ['getProductEntitiesInfo']);
$productModelMock->expects(
@@ -694,13 +703,13 @@ public function testValidateRowNoCustomOption()
public function testValidateRow(array $rowData, array $errors)
{
$this->_bypassModelMethodGetMultiRowFormat($rowData);
-
if (empty($errors)) {
$this->assertTrue($this->_modelMock->validateRow($rowData, 0));
} else {
$this->assertFalse($this->_modelMock->validateRow($rowData, 0));
}
- $this->assertAttributeEquals($errors, '_errors', $this->_productEntity);
+ $resultErrors = $this->_productEntity->getErrorAggregator()->getRowsGroupedByErrorCode([], [], false);
+ $this->assertEquals($errors, $resultErrors);
}
/**
@@ -741,7 +750,8 @@ public function testValidateAmbiguousData(
} else {
$this->assertFalse($this->_modelMock->validateAmbiguousData());
}
- $this->assertAttributeEquals($errors, '_errors', $this->_productEntity);
+ $resultErrors = $this->_productEntity->getErrorAggregator()->getRowsGroupedByErrorCode([], [], false);
+ $this->assertEquals($errors, $resultErrors);
}
/**
@@ -760,73 +770,55 @@ public function validateRowDataProvider()
'main_invalid_store' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_invalid_store.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_STORE => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_STORE => [1]
]
],
'main_incorrect_type' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_incorrect_type.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_TYPE => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_TYPE => [1]
]
],
'main_no_title' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_no_title.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_EMPTY_TITLE => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_EMPTY_TITLE => [1]
]
],
'main_empty_title' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_empty_title.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_EMPTY_TITLE => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_EMPTY_TITLE => [1]
]
],
'main_invalid_price' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_invalid_price.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_PRICE => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_PRICE => [1]
]
],
'main_invalid_max_characters' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_invalid_max_characters.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_MAX_CHARACTERS => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_MAX_CHARACTERS => [1]
]
],
'main_max_characters_less_zero' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_max_characters_less_zero.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_MAX_CHARACTERS => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_MAX_CHARACTERS => [1]
]
],
'main_invalid_sort_order' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_invalid_sort_order.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_SORT_ORDER => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_SORT_ORDER => [1]
]
],
'main_sort_order_less_zero' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_sort_order_less_zero.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_SORT_ORDER => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_SORT_ORDER => [1]
]
],
'secondary_valid' => [
@@ -836,33 +828,25 @@ public function validateRowDataProvider()
'secondary_invalid_store' => [
'$rowData' => include __DIR__ . '/_files/row_data_secondary_invalid_store.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_STORE => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_STORE => [1]
]
],
'secondary_incorrect_price' => [
'$rowData' => include __DIR__ . '/_files/row_data_secondary_incorrect_price.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_ROW_PRICE => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_ROW_PRICE => [1]
]
],
'secondary_incorrect_row_sort' => [
'$rowData' => include __DIR__ . '/_files/row_data_secondary_incorrect_row_sort.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_ROW_SORT => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_ROW_SORT => [1]
]
],
'secondary_row_sort_less_zero' => [
'$rowData' => include __DIR__ . '/_files/row_data_secondary_row_sort_less_zero.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_ROW_SORT => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_INVALID_ROW_SORT => [1]
]
]
];
@@ -879,10 +863,7 @@ public function validateAmbiguousDataDataProvider()
'ambiguity_several_input_rows' => [
'$rowData' => include __DIR__ . '/_files/row_data_main_valid.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_AMBIGUOUS_NEW_NAMES => [
- [1, null],
- [2, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_AMBIGUOUS_NEW_NAMES => [2, 2]
],
'$behavior' => null,
'$numberOfValidations' => 2
@@ -890,18 +871,14 @@ public function validateAmbiguousDataDataProvider()
'ambiguity_different_type' => [
'$rowData' => include __DIR__ . '/_files/row_data_ambiguity_different_type.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_AMBIGUOUS_TYPES => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_AMBIGUOUS_TYPES => [1]
],
'$behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND
],
'ambiguity_several_db_rows' => [
'$rowData' => include __DIR__ . '/_files/row_data_ambiguity_several_db_rows.php',
'$errors' => [
- \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_AMBIGUOUS_OLD_NAMES => [
- [1, null]
- ]
+ \Magento\CatalogImportExport\Model\Import\Product\Option::ERROR_AMBIGUOUS_OLD_NAMES => [1]
],
'$behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND
]
@@ -933,15 +910,15 @@ public function testParseRequiredData()
false
);
- $model = $this->_helper->getObject(
+ $model = $this->objectManagerHelper->getObject(
'Magento\CatalogImportExport\Model\Import\Product\Option',
[
'data' => [
'data_source_model' => $modelData,
'product_model' => $productModel,
- 'option_collection' => $this->_helper->getObject('stdClass'),
+ 'option_collection' => $this->objectManagerHelper->getObject('stdClass'),
'product_entity' => $productEntity,
- 'collection_by_pages_iterator' => $this->_helper->getObject('stdClass'),
+ 'collection_by_pages_iterator' => $this->objectManagerHelper->getObject('stdClass'),
'page_size' => 5000,
'stores' => []
]
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php
new file mode 100644
index 0000000000000..4526c05df7dae
--- /dev/null
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php
@@ -0,0 +1,96 @@
+getMock(
+ 'Magento\CatalogImportExport\Model\Import\Product\Type\Virtual',
+ null,
+ [],
+ '',
+ false
+ );
+
+ $this->setPropertyValue(
+ $virtualModelMock,
+ '_attributes',
+ [
+ 'Default' => [
+ 'name' => [
+ 'id' => '69',
+ 'code' => 'name',
+ 'is_global' => '0',
+ 'is_required' => '1',
+ 'is_unique' => '0',
+ 'frontend_label' => 'Name',
+ 'is_static' => false,
+ 'apply_to' =>
+ [
+ ],
+ 'type' => 'varchar',
+ 'default_value' => null,
+ 'options' =>
+ [
+ ],
+ ],
+ 'sku' => [
+ 'id' => '70',
+ 'code' => 'sku',
+ 'is_global' => '1',
+ 'is_required' => '1',
+ 'is_unique' => '1',
+ 'frontend_label' => 'SKU',
+ 'is_static' => true,
+ 'apply_to' =>
+ [
+ ],
+ 'type' => 'varchar',
+ 'default_value' => null,
+ 'options' =>
+ [
+ ],
+ ]
+ ]
+ ]
+ );
+
+ $rowData = [
+ '_attribute_set' => 'Default',
+ 'sku' => 'downloadablesku1',
+ 'product_type' => 'virtual',
+ 'name' => 'Downloadable Product 1'
+ ];
+
+ $expectedResult = [
+ 'name' => 'Downloadable Product 1',
+ 'weight' => null
+ ];
+
+ $result = $virtualModelMock->prepareAttributesWithDefaultValueForSave($rowData);
+ $this->assertEquals($result, $expectedResult);
+ }
+
+ /**
+ * @param $object
+ * @param $property
+ * @param $value
+ */
+ protected function setPropertyValue(&$object, $property, $value)
+ {
+ $reflection = new \ReflectionClass(get_class($object));
+ $reflectionProperty = $reflection->getProperty($property);
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($object, $value);
+ return $object;
+ }
+}
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php
index cb0a32acff56e..fc7259582171c 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php
@@ -30,7 +30,7 @@ protected function setUp()
public function testInit()
{
- $result = $this->media->init();
+ $result = $this->media->init(null);
$this->assertEquals($this->media, $result);
}
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/TierPriceTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/TierPriceTest.php
index 9b82048555d41..94dcf6ee2cfba 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/TierPriceTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/TierPriceTest.php
@@ -63,7 +63,7 @@ protected function processInit($groupId)
$group = $this->getMock('Magento\Customer\Model\Data\Group', [], [], '', false);
$group->expects($this->once())->method('getId')->willReturn($groupId);
$searchResult->expects($this->once())->method('getItems')->willReturn([$group]);
- return $this->tierPrice->init();
+ return $this->tierPrice->init(null);
}
public function testInit()
diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php
index d0db94e92962e..8e6df5186c075 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php
@@ -19,6 +19,9 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
/** @var array */
protected $validators = [];
+ /** @var \Magento\CatalogImportExport\Model\Import\Product|\PHPUnit_Framework_MockObject_MockObject */
+ protected $context;
+
/** @var Validator\Media|\PHPUnit_Framework_MockObject_MockObject */
protected $validatorOne;
@@ -27,6 +30,24 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
+ $entityTypeModel = $this->getMock(
+ 'Magento\CatalogImportExport\Model\Import\Product\Type\Simple',
+ ['retrieveAttributeFromCache'],
+ [],
+ '',
+ false
+ );
+ $entityTypeModel->expects($this->any())->method('retrieveAttributeFromCache')->willReturn([]);
+ $this->context = $this->getMock(
+ '\Magento\CatalogImportExport\Model\Import\Product',
+ ['retrieveProductTypeByName', 'retrieveMessageTemplate'],
+ [],
+ '',
+ false
+ );
+ $this->context->expects($this->any())->method('retrieveProductTypeByName')->willReturn($entityTypeModel);
+ $this->context->expects($this->any())->method('retrieveMessageTemplate')->willReturn('');
+
$this->validatorOne = $this->getMock(
'Magento\CatalogImportExport\Model\Import\Product\Validator\Media',
[],
@@ -48,11 +69,12 @@ protected function setUp()
'Magento\CatalogImportExport\Model\Import\Product\Validator',
['validators' => $this->validators]
);
+ $this->validator->init($this->context);
}
public function testIsValidCorrect()
{
- $value = 'val';
+ $value = ['product_type' => 'simple'];
$this->validatorOne->expects($this->once())->method('isValid')->with($value)->willReturn(true);
$this->validatorTwo->expects($this->once())->method('isValid')->with($value)->willReturn(true);
$result = $this->validator->isValid($value);
@@ -61,7 +83,7 @@ public function testIsValidCorrect()
public function testIsValidIncorrect()
{
- $value = 'val';
+ $value = ['product_type' => 'simple'];
$this->validatorOne->expects($this->once())->method('isValid')->with($value)->willReturn(true);
$this->validatorTwo->expects($this->once())->method('isValid')->with($value)->willReturn(false);
$messages = ['errorMessage'];
@@ -75,6 +97,6 @@ public function testInit()
{
$this->validatorOne->expects($this->once())->method('init');
$this->validatorTwo->expects($this->once())->method('init');
- $this->validator->init();
+ $this->validator->init(null);
}
}
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 7161180b355b0..8f500954457d5 100644
--- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
+++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php
@@ -8,7 +8,6 @@
use Magento\CatalogImportExport\Model\Import\Product;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Stdlib\DateTime;
-use Zend\Server\Reflection\ReflectionClass;
/**
* Class ProductTest
@@ -17,7 +16,7 @@
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class ProductTest extends \PHPUnit_Framework_TestCase
+class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
const MEDIA_DIRECTORY = 'media/import';
@@ -151,11 +150,18 @@ class ProductTest extends \PHPUnit_Framework_TestCase
/** @var \Magento\CatalogImportExport\Model\Import\Product */
protected $importProduct;
+ /**
+ * @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface
+ */
+ protected $errorAggregator;
+
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
protected function setUp()
{
+ parent::setUp();
+
/* For parent object construct */
$this->jsonHelper =
$this->getMockBuilder('\Magento\Framework\Json\Helper\Data')
@@ -294,6 +300,7 @@ protected function setUp()
->getMock();
$this->validator =
$this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Validator')
+ ->setMethods(['isAttributeValid', 'getMessages', 'isValid'])
->disableOriginalConstructor()
->getMock();
$this->objectRelationProcessor =
@@ -309,6 +316,8 @@ protected function setUp()
->disableOriginalConstructor()
->getMock();
+ $this->errorAggregator = $this->getErrorAggregatorObject();
+
$this->data = [];
$this->_objectConstructor()
@@ -325,6 +334,7 @@ protected function setUp()
$this->resource,
$this->resourceHelper,
$this->string,
+ $this->errorAggregator,
$this->_eventManager,
$this->stockRegistry,
$this->stockConfiguration,
@@ -368,15 +378,15 @@ protected function _objectConstructor()
false
);
$this->optionEntity = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Option')
- ->disableOriginalConstructor()->getMock();
+ ->disableOriginalConstructor()->getMock();
$this->optionFactory->expects($this->once())->method('create')->willReturn($this->optionEntity);
$this->_filesystem->expects($this->once())
- ->method('getDirectoryWrite')
- ->with(DirectoryList::ROOT)
- ->will($this->returnValue(self::MEDIA_DIRECTORY));
+ ->method('getDirectoryWrite')
+ ->with(DirectoryList::ROOT)
+ ->will($this->returnValue(self::MEDIA_DIRECTORY));
- $this->validator->expects($this->once())->method('init');
+ $this->validator->expects($this->any())->method('init');
return $this;
}
@@ -400,34 +410,34 @@ protected function _parentObjectConstructor()
protected function _initAttributeSets()
{
$attributeSetOne = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\Set')
- ->disableOriginalConstructor()
- ->getMock();
+ ->disableOriginalConstructor()
+ ->getMock();
$attributeSetOne->expects($this->any())
- ->method('getAttributeSetName')
- ->willReturn('attributeSet1');
+ ->method('getAttributeSetName')
+ ->willReturn('attributeSet1');
$attributeSetOne->expects($this->any())
- ->method('getId')
- ->willReturn('1');
+ ->method('getId')
+ ->willReturn('1');
$attributeSetTwo = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\Set')
- ->disableOriginalConstructor()
- ->getMock();
+ ->disableOriginalConstructor()
+ ->getMock();
$attributeSetTwo->expects($this->any())
- ->method('getAttributeSetName')
- ->willReturn('attributeSet2');
+ ->method('getAttributeSetName')
+ ->willReturn('attributeSet2');
$attributeSetTwo->expects($this->any())
- ->method('getId')
- ->willReturn('2');
+ ->method('getId')
+ ->willReturn('2');
$attributeSetCol = [$attributeSetOne, $attributeSetTwo];
$collection = $this->getMockBuilder('\Magento\Eav\Model\Resource\Entity\Attribute\Set\Collection')
- ->disableOriginalConstructor()
- ->getMock();
+ ->disableOriginalConstructor()
+ ->getMock();
$collection->expects($this->once())
- ->method('setEntityTypeFilter')
- ->with(self::ENTITY_TYPE_ID)
- ->willReturn($attributeSetCol);
+ ->method('setEntityTypeFilter')
+ ->with(self::ENTITY_TYPE_ID)
+ ->willReturn($attributeSetCol);
$this->_setColFactory->expects($this->once())
- ->method('create')
- ->willReturn($collection);
+ ->method('create')
+ ->willReturn($collection);
return $this;
}
@@ -445,18 +455,18 @@ protected function _initTypeModels()
$this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
->disableOriginalConstructor()->getMock();
$productTypeInstance->expects($this->once())
- ->method('isSuitable')
- ->willReturn(true);
+ ->method('isSuitable')
+ ->willReturn(true);
$productTypeInstance->expects($this->once())
- ->method('getParticularAttributes')
- ->willReturn([]);
+ ->method('getParticularAttributes')
+ ->willReturn([]);
$productTypeInstance->expects($this->once())
- ->method('getCustomFieldsMapping')
- ->willReturn([]);
+ ->method('getCustomFieldsMapping')
+ ->willReturn([]);
$this->_importConfig->expects($this->once())
- ->method('getEntityTypes')
- ->with(self::ENTITY_TYPE_CODE)
- ->willReturn($entityTypes);
+ ->method('getEntityTypes')
+ ->with(self::ENTITY_TYPE_CODE)
+ ->willReturn($entityTypes);
$this->_productTypeFactory->expects($this->once())->method('create')->willReturn($productTypeInstance);
return $this;
}
@@ -489,12 +499,12 @@ public function testSaveProductAttributes()
]
];
$this->skuProcessor->expects($this->once())
- ->method('getNewSku')
- ->with($testSku)
- ->willReturn(['entity_id' => self::ENTITY_ID]);
+ ->method('getNewSku')
+ ->with($testSku)
+ ->willReturn(['entity_id' => self::ENTITY_ID]);
$this->_connection->expects($this->any())
- ->method('quoteInto')
- ->willReturnCallback([$this, 'returnQuoteCallback']);
+ ->method('quoteInto')
+ ->willReturnCallback([$this, 'returnQuoteCallback']);
$this->_connection
->expects($this->once())
->method('delete')
@@ -515,8 +525,8 @@ public function testSaveProductAttributes()
'value' => $attributesData[$testTable][$testSku][$attributeId][$storeId],
];
$this->_connection->expects($this->once())
- ->method('insertOnDuplicate')
- ->with($testTable, $tableData, ['value']);
+ ->method('insertOnDuplicate')
+ ->with($testTable, $tableData, ['value']);
$object = $this->invokeMethod($this->importProduct, '_saveProductAttributes', [$attributesData]);
$this->assertEquals($this->importProduct, $object);
}
@@ -531,6 +541,8 @@ public function testIsAttributeValidAssertAttrValid($attrParams, $rowData)
$string = $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')->setMethods(null)->getMock();
$this->setPropertyValue($this->importProduct, 'string', $string);
+ $this->validator->expects($this->once())->method('isAttributeValid')->willReturn(true);
+
$result = $this->importProduct->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
$this->assertTrue($result);
}
@@ -545,88 +557,14 @@ public function testIsAttributeValidAssertAttrInvalid($attrParams, $rowData)
$string = $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')->setMethods(null)->getMock();
$this->setPropertyValue($this->importProduct, 'string', $string);
+ $this->validator->expects($this->once())->method('isAttributeValid')->willReturn(false);
+ $messages = ['validator message'];
+ $this->validator->expects($this->once())->method('getMessages')->willReturn($messages);
+
$result = $this->importProduct->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
$this->assertFalse($result);
}
- public function testIsAttributeValidNotValidAddErrorCall()
- {
- $attrCode = 'code';
- $attrParams = [
- 'type' => 'decimal',
- ];
- $rowData = [
- $attrCode => 'incorrect'
- ];
- $rowNum = 0;
-
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError'])
- ->getMock();
- $importProduct->expects($this->once())->method('addRowError');
-
- $importProduct->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
- }
-
- public function testIsAttributeValidOnDuplicateAddErrorCall()
- {
- $attrCode = 'code';
- $attrCodeVal = 1000;
- $expectedSkuVal = 'sku_val';
- $testSkuVal = 'some_sku';
- $attrParams = [
- 'type' => 'decimal',
- 'is_unique' => true,
- ];
- $rowData = [
- $attrCode => $attrCodeVal,
- \Magento\CatalogImportExport\Model\Import\Product::COL_SKU => $expectedSkuVal
- ];
- $rowNum = 0;
-
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError'])
- ->getMock();
- $importProduct->expects($this->once())->method('addRowError');
- $this->setPropertyValue($importProduct, '_uniqueAttributes', [
- $attrCode => [$attrCodeVal => $testSkuVal]
- ]);
-
- $importProduct->expects($this->once())->method('addRowError');
-
- $return = $importProduct->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
-
- $this->assertFalse($return);
- }
-
- public function testIsAttributeValidAddIntoUniqueueAttributes()
- {
- $attrCode = 'code';
- $attrCodeVal = 1000;
- $expectedSkuVal = 'sku_val';
- $attrParams = [
- 'type' => 'decimal',
- 'is_unique' => true,
- ];
- $rowData = [
- $attrCode => $attrCodeVal,
- \Magento\CatalogImportExport\Model\Import\Product::COL_SKU => $expectedSkuVal
- ];
- $rowNum = 0;
-
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(null)
- ->getMock();
-
- $importProduct->isAttributeValid($attrCode, $attrParams, $rowData, $rowNum);
-
- $_uniqueAttributes = $this->getPropertyValue($importProduct, '_uniqueAttributes');
- $this->assertEquals($expectedSkuVal, $_uniqueAttributes[$attrCode][$rowData[$attrCode]]);
- }
-
public function testGetMultipleValueSeparatorDefault()
{
$this->setPropertyValue($this->importProduct, '_parameters', null);
@@ -703,15 +641,14 @@ public function testGetRowScope($rowData, $expectedResult)
}
/**
- * @dataProvider validateRowIsAlreadyValidatedDataProvider
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
- public function testValidateRowIsAlreadyValidated($isInvalidRow, $expectedResult)
+ public function testValidateRowIsAlreadyValidated()
{
$rowNum = 0;
$this->setPropertyValue($this->importProduct, '_validatedRows', [$rowNum => true]);
- $this->setPropertyValue($this->importProduct, '_invalidRows', [$rowNum => $isInvalidRow]);
$result = $this->importProduct->validateRow([], $rowNum);
- $this->assertEquals($expectedResult, $result);
+ $this->assertTrue($result);
}
/**
@@ -721,12 +658,15 @@ public function testValidateRowDeleteBehaviour($rowScope, $oldSku, $expectedResu
{
$importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
->disableOriginalConstructor()
- ->setMethods(['getBehavior', 'getRowScope'])
+ ->setMethods(['getBehavior', 'getRowScope', 'getErrorAggregator'])
->getMock();
$importProduct
->expects($this->once())
->method('getBehavior')
->willReturn(\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE);
+ $importProduct
+ ->method('getErrorAggregator')
+ ->willReturn($this->getErrorAggregatorObject());
$importProduct->expects($this->once())->method('getRowScope')->willReturn($rowScope);
$skuKey = \Magento\CatalogImportExport\Model\Import\Product::COL_SKU;
$rowData = [
@@ -746,9 +686,9 @@ public function testValidateRowDeleteBehaviourAddRowErrorCall()
->getMock();
$importProduct->expects($this->once())->method('getBehavior')
- ->willReturn(\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE);
+ ->willReturn(\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE);
$importProduct->expects($this->once())->method('getRowScope')
- ->willReturn(\Magento\CatalogImportExport\Model\Import\Product::SCOPE_DEFAULT);
+ ->willReturn(\Magento\CatalogImportExport\Model\Import\Product::SCOPE_DEFAULT);
$importProduct->expects($this->once())->method('addRowError');
$rowData = [
\Magento\CatalogImportExport\Model\Import\Product::COL_SKU => 'sku',
@@ -759,25 +699,13 @@ public function testValidateRowDeleteBehaviourAddRowErrorCall()
public function testValidateRowValidatorCheck()
{
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
-
- $this->validator->expects($this->once())->method('isValid')->willReturn(false);
$messages = ['validator message'];
$this->validator->expects($this->once())->method('getMessages')->willReturn($messages);
- $importProduct->expects($this->at(0))->method('addRowError')->with($messages[0]);
- $this->setPropertyValue($importProduct, 'validator', $this->validator);
- //suppress option validation
- $this->_rewriteGetOptionEntityInImportProduct($importProduct);
$rowData = [
\Magento\CatalogImportExport\Model\Import\Product::COL_SKU => 'sku',
];
$rowNum = 0;
- $this->setPropertyValue($importProduct, '_invalidRows', [$rowNum => '']);
-
- $importProduct->validateRow($rowData, $rowNum);
+ $this->importProduct->validateRow($rowData, $rowNum);
}
/**
@@ -874,7 +802,7 @@ public function getStoreIdByCodeDataProvider()
[
'$storeCode' => null,
'$expectedResult' => \Magento\CatalogImportExport\Model\Import\Product::SCOPE_DEFAULT,
- ],
+ ],
[
'$storeCode' => 'value',
'$expectedResult' => 'getStoreCodeToId value',
@@ -887,10 +815,10 @@ public function getStoreIdByCodeDataProvider()
*/
public function testValidateRowCheckSpecifiedSku($sku, $expectedError)
{
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity', 'getRowScope'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(
+ [ 'addRowError', 'getOptionEntity', 'getRowScope'],
+ ['isRowInvalid' => true]
+ );
$rowNum = 0;
$rowData = [
@@ -917,8 +845,11 @@ public function testValidateRowProcessEntityIncrement()
{
$count = 0;
$rowNum = 0;
+ $errorAggregator = $this->getErrorAggregatorObject(['isRowInvalid']);
+ $errorAggregator->method('isRowInvalid')->willReturn(true);
$this->setPropertyValue($this->importProduct, '_processedEntitiesCount', $count);
- $rowData = [\Magento\CatalogImportExport\Model\Import\Product::COL_SKU => ''];
+ $this->setPropertyValue($this->importProduct, 'errorAggregator', $errorAggregator);
+ $rowData = [\Magento\CatalogImportExport\Model\Import\Product::COL_SKU => false];
//suppress validator
$this->_setValidatorMockInImportProduct($this->importProduct);
$this->importProduct->validateRow($rowData, $rowNum);
@@ -927,10 +858,11 @@ public function testValidateRowProcessEntityIncrement()
public function testValidateRowValidateExistingProductTypeAddNewSku()
{
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(
+ [ 'addRowError', 'getOptionEntity'],
+ ['isRowInvalid' => true]
+ );
+
$sku = 'sku';
$rowNum = 0;
$rowData = [
@@ -982,10 +914,10 @@ public function testValidateRowValidateExistingProductTypeAddErrorRowCall()
'type_id' => 'type_id_val',
],
];
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(
+ ['addRowError', 'getOptionEntity'],
+ ['isRowInvalid' => true]
+ );
$this->setPropertyValue($importProduct, '_oldSku', $oldSku);
$importProduct->expects($this->once())->method('addRowError')->with(
@@ -1010,10 +942,7 @@ public function testValidateRowValidateExistingProductTypeResetSku()
'type_id' => 'type_id_val',
],
];
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(['getOptionEntity']);
$this->setPropertyValue($importProduct, '_oldSku', $oldSku);
@@ -1030,8 +959,8 @@ public function testValidateRowValidateExistingProductTypeResetSku()
$this->skuProcessor->expects($this->once())->method('getNewSku')->with($expectedSku)->willReturn($newSku);
$this->setPropertyValue($importProduct, 'skuProcessor', $this->skuProcessor);
$productType = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
- ->disableOriginalConstructor()
- ->getMock();
+ ->disableOriginalConstructor()
+ ->getMock();
$this->setPropertyValue($importProduct, '_productTypeModels', [
$newSku['type_id'] => $productType
]);
@@ -1065,11 +994,10 @@ public function testValidateRowValidateNewProductTypeAddRowErrorCall(
$oldSku = [
$sku => null,
];
-
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(
+ ['addRowError', 'getOptionEntity'],
+ ['isRowInvalid' => true]
+ );
$this->setPropertyValue($importProduct, '_oldSku', $oldSku);
$this->setPropertyValue($importProduct, '_productTypeModels', $_productTypeModels);
@@ -1110,10 +1038,10 @@ public function testValidateRowValidateNewProductTypeGetNewSkuCall()
$_attrSetNameToId[$rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_ATTR_SET]],
'attr_set_code' => $rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_ATTR_SET],//value
];
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(
+ ['addRowError', 'getOptionEntity'],
+ ['isRowInvalid' => true]
+ );
$this->setPropertyValue($importProduct, '_oldSku', $oldSku);
$this->setPropertyValue($importProduct, '_productTypeModels', $_productTypeModels);
@@ -1130,15 +1058,110 @@ public function testValidateRowValidateNewProductTypeGetNewSkuCall()
public function testValidateRowValidateNewProductTypeResetSku()
{
- $this->markTestSkipped(
- 'No chance to assert sku resetting due to mutually exclusive condition:
- !isset($this->_invalidRows[$rowNum]) and isset($this->_invalidRows[$rowNum]) should be true simultaneously'
+ $sku = 'sku';
+ $rowNum = 0;
+ $rowData = [
+ \Magento\CatalogImportExport\Model\Import\Product::COL_SKU => $sku,
+ \Magento\CatalogImportExport\Model\Import\Product::COL_TYPE => 'value',
+ \Magento\CatalogImportExport\Model\Import\Product::COL_ATTR_SET => 'value',
+ ];
+
+ $oldSku = [
+ $sku => [
+ 'type_id' => 'type_id_val',
+ ],
+ ];
+ $_productTypeModels = [
+ $rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_TYPE] => 'value',
+ ];
+ $_attrSetNameToId = [
+ $rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_ATTR_SET] => 'attr_set_code_val'
+ ];
+
+ $importProduct = $this->createModelMockWithErrorAggregator(
+ ['addRowError', 'getOptionEntity'],
+ ['isRowInvalid' => false]
);
+
+ $this->setPropertyValue($importProduct, '_oldSku', $oldSku);
+ $this->setPropertyValue($importProduct, '_productTypeModels', $_productTypeModels);
+ $this->setPropertyValue($importProduct, '_attrSetNameToId', $_attrSetNameToId);
+
+ $this->_rewriteGetOptionEntityInImportProduct($importProduct);//suppress option validation
+ $this->_setValidatorMockInImportProduct($importProduct);//suppress validator
+
+ $expectedSku = false;
+ $newSku = [
+ 'attr_set_code' => 'new_attr_set_code',
+ 'type_id' => 'new_type_id_val',
+ ];
+ $this->skuProcessor->expects($this->once())->method('getNewSku')->with($expectedSku)->willReturn($newSku);
+ $this->setPropertyValue($importProduct, 'skuProcessor', $this->skuProcessor);
+ $productType = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->setPropertyValue($importProduct, '_productTypeModels', [
+ $newSku['type_id'] => $productType
+ ]);
+
+ $importProduct->validateRow($rowData, $rowNum);
}
public function testValidateDefaultScopeNotValidAttributesResetSku()
{
- $this->markTestSkipped('No chance to assert sku resetting because it is not used later in method.');
+ $sku = 'sku';
+ $rowNum = 0;
+ $attrCode = 'code';
+ $stringUtilsMock = $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')->setMethods(null)->getMock();
+ $this->setPropertyValue($this->importProduct, 'string', $stringUtilsMock);
+
+ $scopeMock = $this->getMock(
+ '\Magento\CatalogImportExport\Model\Import\Product',
+ ['getRowScope'],
+ [],
+ '',
+ false
+ );
+
+ $colStore = \Magento\CatalogImportExport\Model\Import\Product::COL_STORE;
+ $scopeRowData = [
+ $sku => 'sku',
+ $colStore => null,
+ ];
+ $scopeResult = \Magento\CatalogImportExport\Model\Import\Product::SCOPE_DEFAULT;
+ $scopeMock->expects($this->any())->method('getRowScope')->with($scopeRowData)->willReturn($scopeResult);
+ $oldSku = [
+ $sku => [
+ 'type_id' => 'type_id_val',
+ ],
+ ];
+
+ $this->setPropertyValue($this->importProduct, '_oldSku', $oldSku);
+
+ $expectedSku = false;
+ $newSku = [
+ 'attr_set_code' => 'new_attr_set_code',
+ 'type_id' => 'new_type_id_val',
+ ];
+ $this->skuProcessor->expects($this->any())->method('getNewSku')->with($expectedSku)->willReturn($newSku);
+ $this->setPropertyValue($this->importProduct, 'skuProcessor', $this->skuProcessor);
+
+ $attrParams = [
+ 'type' => 'varchar',
+ ];
+ $attrRowData = [
+ 'code' => str_repeat(
+ 'a',
+ \Magento\CatalogImportExport\Model\Import\Product::DB_MAX_VARCHAR_LENGTH + 1
+ ),
+ ];
+
+ $this->validator->expects($this->once())->method('isAttributeValid')->willReturn(false);
+ $messages = ['validator message'];
+ $this->validator->expects($this->once())->method('getMessages')->willReturn($messages);
+
+ $result = $this->importProduct->isAttributeValid($attrCode, $attrParams, $attrRowData, $rowNum);
+ $this->assertFalse($result);
}
public function testValidateRowSetAttributeSetCodeIntoRowData()
@@ -1163,18 +1186,15 @@ public function testValidateRowSetAttributeSetCodeIntoRowData()
'type_id' => 'type_id_val',
],
];
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(['getOptionEntity']);
$this->setPropertyValue($importProduct, '_oldSku', $oldSku);
$this->skuProcessor->expects($this->any())->method('getNewSku')->willReturn($newSku);
$this->setPropertyValue($importProduct, 'skuProcessor', $this->skuProcessor);
$productType = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType')
- ->disableOriginalConstructor()
- ->getMock();
+ ->disableOriginalConstructor()
+ ->getMock();
$productType->expects($this->once())->method('isRowValid')->with($expectedRowData);
$this->setPropertyValue($importProduct, '_productTypeModels', [
$newSku['type_id'] => $productType
@@ -1201,16 +1221,15 @@ public function testValidateValidateOptionEntity()
'type_id' => 'type_id_val',
],
];
- $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
- ->disableOriginalConstructor()
- ->setMethods(['addRowError', 'getOptionEntity'])
- ->getMock();
+ $importProduct = $this->createModelMockWithErrorAggregator(
+ ['addRowError', 'getOptionEntity'],
+ ['isRowInvalid' => true]
+ );
$this->setPropertyValue($importProduct, '_oldSku', $oldSku);
//suppress validator
$this->_setValidatorMockInImportProduct($importProduct);
- $this->setPropertyValue($importProduct, '_invalidRows', [0 => '']);
$option = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product\Option')
->disableOriginalConstructor()
@@ -1459,7 +1478,7 @@ public function getRowScopeDataProvider()
$colSku => null,
$colStore => 'store',
],
- '$expectedResult' => \Magento\CatalogImportExport\Model\Import\Product::SCOPE_NULL
+ '$expectedResult' => \Magento\CatalogImportExport\Model\Import\Product::SCOPE_STORE
],
[
'$rowData' => [
@@ -1478,23 +1497,6 @@ public function getRowScopeDataProvider()
];
}
- /**
- * @return array
- */
- public function validateRowIsAlreadyValidatedDataProvider()
- {
- return [
- [
- '$isInvalidRow' => true,
- '$expectedResult' => false,
- ],
- [
- '$isInvalidRow' => null,
- '$expectedResult' => true,
- ],
- ];
- }
-
/**
* @return mixed
*/
@@ -1577,7 +1579,6 @@ private function _suppressValidateRowOptionValidatorInvalidRows($importProduct)
$this->_rewriteGetOptionEntityInImportProduct($importProduct);
//suppress validator
$this->_setValidatorMockInImportProduct($importProduct);
- $this->setPropertyValue($importProduct, '_invalidRows', [0 => '']);
return $importProduct;
}
@@ -1614,4 +1615,26 @@ private function _rewriteGetOptionEntityInImportProduct($importProduct)
return $importProduct;
}
+
+ /**
+ * @param array $methods
+ * @param array $errorAggregatorMethods
+ * @return \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected function createModelMockWithErrorAggregator(array $methods = [], array $errorAggregatorMethods = [])
+ {
+ $methods[] = 'getErrorAggregator';
+ $importProduct = $this->getMockBuilder('\Magento\CatalogImportExport\Model\Import\Product')
+ ->disableOriginalConstructor()
+ ->setMethods($methods)
+ ->getMock();
+ $errorMethods = array_keys($errorAggregatorMethods);
+ $errorAggregator = $this->getErrorAggregatorObject($errorMethods);
+ foreach ($errorAggregatorMethods as $method => $result) {
+ $errorAggregator->method($method)->willReturn($result);
+ }
+ $importProduct->method('getErrorAggregator')->willReturn($errorAggregator);
+
+ return $importProduct;
+ }
}
diff --git a/app/code/Magento/CatalogImportExport/etc/di.xml b/app/code/Magento/CatalogImportExport/etc/di.xml
index 7229759817235..55daa1e2d6f1f 100644
--- a/app/code/Magento/CatalogImportExport/etc/di.xml
+++ b/app/code/Magento/CatalogImportExport/etc/di.xml
@@ -24,6 +24,7 @@
- Magento\CatalogImportExport\Model\Import\Product\Validator\TierPrice
- Magento\CatalogImportExport\Model\Import\Product\Validator\Website
- Magento\CatalogImportExport\Model\Import\Product\Validator\Weight
+ - Magento\CatalogImportExport\Model\Import\Product\Validator\Quantity
diff --git a/app/code/Magento/CatalogImportExport/etc/import.xml b/app/code/Magento/CatalogImportExport/etc/import.xml
index fb6028af373d8..be9807d914866 100644
--- a/app/code/Magento/CatalogImportExport/etc/import.xml
+++ b/app/code/Magento/CatalogImportExport/etc/import.xml
@@ -8,7 +8,7 @@
-
+
diff --git a/app/code/Magento/Cms/Model/Block.php b/app/code/Magento/Cms/Model/Block.php
index e8605a682cd9b..d2a367784ced2 100644
--- a/app/code/Magento/Cms/Model/Block.php
+++ b/app/code/Magento/Cms/Model/Block.php
@@ -65,7 +65,7 @@ public function beforeSave()
*/
public function getIdentities()
{
- return [self::CACHE_TAG . '_' . $this->getId()];
+ return [self::CACHE_TAG . '_' . $this->getId(), self::CACHE_TAG . '_' . $this->getIdentifier()];
}
/**
diff --git a/app/code/Magento/Cms/Setup/InstallSchema.php b/app/code/Magento/Cms/Setup/InstallSchema.php
index de6853122eba7..7cec966797f50 100644
--- a/app/code/Magento/Cms/Setup/InstallSchema.php
+++ b/app/code/Magento/Cms/Setup/InstallSchema.php
@@ -73,6 +73,14 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con
null,
['nullable' => false, 'default' => '1'],
'Is Block Active'
+ )->addIndex(
+ $setup->getIdxName(
+ $installer->getTable('cms_block'),
+ ['title', 'identifier', 'content'],
+ AdapterInterface::INDEX_TYPE_FULLTEXT
+ ),
+ ['title', 'identifier', 'content'],
+ ['type' => AdapterInterface::INDEX_TYPE_FULLTEXT]
)->setComment(
'CMS Block Table'
);
@@ -231,6 +239,14 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con
)->addIndex(
$installer->getIdxName('cms_page', ['identifier']),
['identifier']
+ )->addIndex(
+ $setup->getIdxName(
+ $installer->getTable('cms_page'),
+ ['title', 'meta_keywords', 'meta_description', 'identifier', 'content'],
+ AdapterInterface::INDEX_TYPE_FULLTEXT
+ ),
+ ['title', 'meta_keywords', 'meta_description', 'identifier', 'content'],
+ ['type' => AdapterInterface::INDEX_TYPE_FULLTEXT]
)->setComment(
'CMS Page Table'
);
@@ -273,26 +289,6 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con
);
$installer->getConnection()->createTable($table);
- $installer->getConnection()->addIndex(
- $installer->getTable('cms_page'),
- $setup->getIdxName(
- $installer->getTable('cms_page'),
- ['title', 'meta_keywords', 'meta_description', 'identifier', 'content'],
- AdapterInterface::INDEX_TYPE_FULLTEXT
- ),
- ['title', 'meta_keywords', 'meta_description', 'identifier', 'content'],
- AdapterInterface::INDEX_TYPE_FULLTEXT
- );
- $installer->getConnection()->addIndex(
- $installer->getTable('cms_block'),
- $setup->getIdxName(
- $installer->getTable('cms_block'),
- ['title', 'identifier', 'content'],
- AdapterInterface::INDEX_TYPE_FULLTEXT
- ),
- ['title', 'identifier', 'content'],
- AdapterInterface::INDEX_TYPE_FULLTEXT
- );
$installer->endSetup();
}
}
diff --git a/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php b/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php
index c2ffb1dae3b6e..4401ee36fc722 100644
--- a/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableImportExport/Model/Import/Product/Type/Configurable.php
@@ -5,6 +5,9 @@
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
+
+// @codingStandardsIgnoreFile
+
namespace Magento\ConfigurableImportExport\Model\Import\Product\Type;
use Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
@@ -26,6 +29,8 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
const ERROR_INVALID_WEBSITE = 'invalidSuperAttrWebsite';
+ const ERROR_DUPLICATED_VARIATIONS = 'duplicatedVariations';
+
/**
* Validation failure message template definitions
*
@@ -35,6 +40,7 @@ class Configurable extends \Magento\CatalogImportExport\Model\Import\Product\Typ
self::ERROR_ATTRIBUTE_CODE_IS_NOT_SUPER => 'Attribute with this code is not super',
self::ERROR_INVALID_OPTION_VALUE => 'Invalid option value',
self::ERROR_INVALID_WEBSITE => 'Invalid website code for super attribute',
+ self::ERROR_DUPLICATED_VARIATIONS => 'SKU %s contains duplicated variations',
];
/**
@@ -613,7 +619,8 @@ protected function _collectSuperData($rowData)
if ($this->_getSuperAttributeId($productId, $attrParams['id'])) {
$productSuperAttrId = $this->_getSuperAttributeId($productId, $attrParams['id']);
} elseif (isset($this->_superAttributesData['attributes'][$productId][$attrParams['id']])) {
- $productSuperAttrId = $this->_superAttributesData['attributes'][$productId][$attrParams['id']]['product_super_attribute_id'];
+ $attributes = $this->_superAttributesData['attributes'];
+ $productSuperAttrId = $attributes[$productId][$attrParams['id']]['product_super_attribute_id'];
$this->_collectSuperDataLabels($data, $productSuperAttrId, $productId, $variationLabels);
} else {
$productSuperAttrId = $this->_getNextAttrId();
@@ -780,13 +787,21 @@ public function isRowValid(array $rowData, $rowNum, $isNewProduct = true)
{
$error = false;
$dataWithExtraVirtualRows = $this->_parseVariations($rowData);
+ $skus = [];
if (!empty($dataWithExtraVirtualRows)) {
array_unshift($dataWithExtraVirtualRows, $rowData);
} else {
$dataWithExtraVirtualRows[] = $rowData;
}
- foreach ($dataWithExtraVirtualRows as $data) {
- $error |= !parent::isRowValid($data, $rowNum, $isNewProduct);
+ foreach ($dataWithExtraVirtualRows as $option) {
+ if (isset($option['_super_products_sku'])) {
+ if (in_array($option['_super_products_sku'], $skus)) {
+ $error = true;
+ $this->_entityModel->addRowError(sprintf($this->_messageTemplates[self::ERROR_DUPLICATED_VARIATIONS], $option['_super_products_sku']), $rowNum);
+ }
+ $skus[] = $option['_super_products_sku'];
+ }
+ $error |= !parent::isRowValid($option, $rowNum, $isNewProduct);
}
return !$error;
}
diff --git a/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php
index 0a98ab8c84f87..019adef514f78 100644
--- a/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableImportExport/Test/Unit/Model/Import/Product/Type/ConfigurableTest.php
@@ -6,7 +6,6 @@
namespace Magento\ConfigurableImportExport\Test\Unit\Model\Import\Product\Type;
-use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
use \Magento\ConfigurableImportExport;
/**
@@ -14,14 +13,11 @@
* @package Magento\ConfigurableImportExport\Test\Unit\Model\Import\Product\Type
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class ConfigurableTest extends \PHPUnit_Framework_TestCase
+class ConfigurableTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/** @var ConfigurableImportExport\Model\Import\Product\Type\Configurable */
protected $configurable;
- /** @var ObjectManagerHelper */
- protected $objectManagerHelper;
-
/**
* @var \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -81,6 +77,8 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
*/
protected function setUp()
{
+ parent::setUp();
+
$this->setCollectionFactory = $this->getMock(
'Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory',
['create'],
@@ -158,18 +156,20 @@ protected function setUp()
'isRowAllowedToImport',
'getConnection',
'getAttrSetIdToName',
+ 'getErrorAggregator',
'getAttributeOptions'
],
[],
'',
false
);
+ $this->_entityModel->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
+
$this->params = [
0 => $this->_entityModel,
1 => 'configurable'
];
- $this->objectManagerHelper = new ObjectManagerHelper($this);
$this->_connection = $this->getMock(
'Magento\Framework\DB\Adapter\Pdo\Mysql',
@@ -208,7 +208,7 @@ protected function setUp()
$this->_connection->expects($this->any())->method('insertOnDuplicate')->willReturnSelf();
$this->_connection->expects($this->any())->method('delete')->willReturnSelf();
$this->_connection->expects($this->any())->method('quoteInto')->willReturn('');
- $this->_connection->expects($this->any())->method('fetchPairs')->will($this->returnValue([]));
+ $this->_connection->expects($this->any())->method('fetchAll')->will($this->returnValue([]));
$this->resource = $this->getMock(
'\Magento\Framework\App\Resource',
@@ -524,7 +524,7 @@ public function testSaveData()
['attribute_id' => 132, 'product_id' => 4, 'option_id' => 4, 'product_super_attribute_id' => 132],
['attribute_id' => 132, 'product_id' => 5, 'option_id' => 5, 'product_super_attribute_id' => 132],
]));
- $this->_connection->expects($this->any())->method('fetchPairs')->with($this->select)->will(
+ $this->_connection->expects($this->any())->method('fetchAll')->with($this->select)->will(
$this->returnValue([])
);
diff --git a/app/code/Magento/Customer/Controller/Account/EditPost.php b/app/code/Magento/Customer/Controller/Account/EditPost.php
index e56a0f5d5941e..ead64bca6175f 100644
--- a/app/code/Magento/Customer/Controller/Account/EditPost.php
+++ b/app/code/Magento/Customer/Controller/Account/EditPost.php
@@ -70,42 +70,23 @@ public function execute()
/** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
if (!$this->formKeyValidator->validate($this->getRequest())) {
- $resultRedirect->setPath('*/*/edit');
- return $resultRedirect;
+ return $resultRedirect->setPath('*/*/edit');
}
if ($this->getRequest()->isPost()) {
$customerId = $this->_getSession()->getCustomerId();
+ $currentCustomer = $this->customerRepository->getById($customerId);
+
+ // Prepare new customer data
$customer = $this->customerExtractor->extract('customer_account_edit', $this->_request);
$customer->setId($customerId);
if ($customer->getAddresses() == null) {
- $customer->setAddresses($this->customerRepository->getById($customerId)->getAddresses());
+ $customer->setAddresses($currentCustomer->getAddresses());
}
+ // Change customer password
if ($this->getRequest()->getParam('change_password')) {
- $currPass = $this->getRequest()->getPost('current_password');
- $newPass = $this->getRequest()->getPost('password');
- $confPass = $this->getRequest()->getPost('password_confirmation');
-
- if (strlen($newPass)) {
- if ($newPass == $confPass) {
- try {
- $customerEmail = $this->customerRepository->getById($customerId)->getEmail();
- $this->customerAccountManagement->changePassword($customerEmail, $currPass, $newPass);
- } catch (AuthenticationException $e) {
- $this->messageManager->addError($e->getMessage());
- } catch (\Exception $e) {
- $this->messageManager->addException(
- $e,
- __('Something went wrong while changing the password.')
- );
- }
- } else {
- $this->messageManager->addError(__('Confirm your new password.'));
- }
- } else {
- $this->messageManager->addError(__('Please enter new password.'));
- }
+ $this->changeCustomerPassword($currentCustomer->getEmail());
}
try {
@@ -115,24 +96,54 @@ public function execute()
} catch (InputException $e) {
$this->messageManager->addException($e, __('Invalid input'));
} catch (\Exception $e) {
- $this->messageManager->addException(
- $e,
- __('We can\'t save the customer.') . $e->getMessage() . '' . $e->getTraceAsString() . ' '
- );
+ $message = __('We can\'t save the customer.')
+ . $e->getMessage()
+ . '' . $e->getTraceAsString() . ' ';
+ $this->messageManager->addException($e, $message);
}
if ($this->messageManager->getMessages()->getCount() > 0) {
$this->_getSession()->setCustomerFormData($this->getRequest()->getPostValue());
- $resultRedirect->setPath('*/*/edit');
- return $resultRedirect;
+ return $resultRedirect->setPath('*/*/edit');
}
$this->messageManager->addSuccess(__('You saved the account information.'));
- $resultRedirect->setPath('customer/account');
- return $resultRedirect;
+ return $resultRedirect->setPath('customer/account');
+ }
+
+ return $resultRedirect->setPath('*/*/edit');
+ }
+
+ /**
+ * Change customer password
+ *
+ * @param string $email
+ * @return $this
+ */
+ protected function changeCustomerPassword($email)
+ {
+ $currPass = $this->getRequest()->getPost('current_password');
+ $newPass = $this->getRequest()->getPost('password');
+ $confPass = $this->getRequest()->getPost('password_confirmation');
+
+ if (!strlen($newPass)) {
+ $this->messageManager->addError(__('Please enter new password.'));
+ return $this;
+ }
+
+ if ($newPass !== $confPass) {
+ $this->messageManager->addError(__('Confirm your new password.'));
+ return $this;
+ }
+
+ try {
+ $this->customerAccountManagement->changePassword($email, $currPass, $newPass);
+ } catch (AuthenticationException $e) {
+ $this->messageManager->addError($e->getMessage());
+ } catch (\Exception $e) {
+ $this->messageManager->addException($e, __('Something went wrong while changing the password.'));
}
- $resultRedirect->setPath('*/*/edit');
- return $resultRedirect;
+ return $this;
}
}
diff --git a/app/code/Magento/Customer/Controller/Account/ForgotPasswordPost.php b/app/code/Magento/Customer/Controller/Account/ForgotPasswordPost.php
index 89b3b2384bea9..ead592a1a77e7 100644
--- a/app/code/Magento/Customer/Controller/Account/ForgotPasswordPost.php
+++ b/app/code/Magento/Customer/Controller/Account/ForgotPasswordPost.php
@@ -14,6 +14,9 @@
use Magento\Framework\Escaper;
use Magento\Framework\Exception\NoSuchEntityException;
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
class ForgotPasswordPost extends \Magento\Customer\Controller\Account
{
/** @var AccountManagementInterface */
@@ -54,9 +57,8 @@ public function execute()
if ($email) {
if (!\Zend_Validate::is($email, 'EmailAddress')) {
$this->_getSession()->setForgottenEmail($email);
- $this->messageManager->addError(__('Please correct the email address.'));
- $resultRedirect->setPath('*/*/forgotpassword');
- return $resultRedirect;
+ $this->messageManager->addErrorMessage(__('Please correct the email address.'));
+ return $resultRedirect->setPath('*/*/forgotpassword');
}
try {
@@ -67,19 +69,31 @@ public function execute()
} catch (NoSuchEntityException $e) {
// Do nothing, we don't want anyone to use this action to determine which email accounts are registered.
} catch (\Exception $exception) {
- $this->messageManager->addException($exception, __('We\'re unable to send the password reset email.'));
- $resultRedirect->setPath('*/*/forgotpassword');
- return $resultRedirect;
+ $this->messageManager->addExceptionMessage(
+ $exception,
+ __('We\'re unable to send the password reset email.')
+ );
+ return $resultRedirect->setPath('*/*/forgotpassword');
}
- // @codingStandardsIgnoreStart
- $this->messageManager->addSuccess(__('We\'ll email you a link to reset your password.'));
- // @codingStandardsIgnoreEnd
- $resultRedirect->setPath('*/*/');
- return $resultRedirect;
+ $this->messageManager->addSuccessMessage($this->getSuccessMessage($email));
+ return $resultRedirect->setPath('*/*/');
} else {
- $this->messageManager->addError(__('Please enter your email.'));
- $resultRedirect->setPath('*/*/forgotpassword');
- return $resultRedirect;
+ $this->messageManager->addErrorMessage(__('Please enter your email.'));
+ return $resultRedirect->setPath('*/*/forgotpassword');
}
}
+
+ /**
+ * Retrieve success message
+ *
+ * @param string $email
+ * @return \Magento\Framework\Phrase
+ */
+ protected function getSuccessMessage($email)
+ {
+ return __(
+ 'If there is an account associated with %1 you will receive an email with a link to reset your password.',
+ $this->escaper->escapeHtml($email)
+ );
+ }
}
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Customer/InvalidateToken.php b/app/code/Magento/Customer/Controller/Adminhtml/Customer/InvalidateToken.php
index a4191a86d4522..92961f2a0d40f 100644
--- a/app/code/Magento/Customer/Controller/Adminhtml/Customer/InvalidateToken.php
+++ b/app/code/Magento/Customer/Controller/Adminhtml/Customer/InvalidateToken.php
@@ -33,7 +33,6 @@ class InvalidateToken extends \Magento\Customer\Controller\Adminhtml\Index
protected $tokenService;
/**
- * @param CustomerTokenServiceInterface $tokenService
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Framework\Registry $coreRegistry
* @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory
@@ -59,6 +58,7 @@ class InvalidateToken extends \Magento\Customer\Controller\Adminhtml\Index
* @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
* @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
* @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
+ * @param CustomerTokenServiceInterface $tokenService
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/InlineEdit.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/InlineEdit.php
new file mode 100644
index 0000000000000..f97c48b0ebc1d
--- /dev/null
+++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/InlineEdit.php
@@ -0,0 +1,263 @@
+customerRepository = $customerRepository;
+ $this->resultJsonFactory = $resultJsonFactory;
+ $this->customerMapper = $customerMapper;
+ $this->dataObjectHelper = $dataObjectHelper;
+ $this->logger = $logger;
+ parent::__construct($context);
+ }
+
+ /**
+ * @return \Magento\Framework\Controller\Result\Json
+ */
+ public function execute()
+ {
+ /** @var \Magento\Framework\Controller\Result\Json $resultJson */
+ $resultJson = $this->resultJsonFactory->create();
+
+ $postItems = $this->getRequest()->getParam('items', []);
+ if (!($this->getRequest()->getParam('isAjax') && count($postItems))) {
+ return $resultJson->setData([
+ 'messages' => [__('Please correct the data sent.')],
+ 'error' => true,
+ ]);
+ }
+
+ foreach (array_keys($postItems) as $customerId) {
+ $this->setCustomer($this->customerRepository->getById($customerId));
+ if ($this->getCustomer()->getDefaultBilling()) {
+ $this->updateDefaultBilling($this->getData($postItems[$customerId]));
+ }
+ $this->updateCustomer($this->getData($postItems[$customerId], true));
+ $this->saveCustomer($this->getCustomer());
+ }
+
+ return $resultJson->setData([
+ 'messages' => $this->getErrorMessages(),
+ 'error' => $this->isErrorExists()
+ ]);
+ }
+
+ /**
+ * Receive entity(customer|customer_address) data from request
+ *
+ * @param array $data
+ * @param null $isCustomerData
+ * @return array
+ */
+ protected function getData(array $data, $isCustomerData = null)
+ {
+ $addressKeys = preg_grep(
+ '/^(' . AttributeRepository::BILLING_ADDRESS_PREFIX . '\w+)/',
+ array_keys($data),
+ $isCustomerData
+ );
+ $result = array_intersect_key($data, array_flip($addressKeys));
+ if ($isCustomerData === null) {
+ foreach ($result as $key => $value) {
+ if (strpos($key, AttributeRepository::BILLING_ADDRESS_PREFIX) !== false) {
+ unset($result[$key]);
+ $result[str_replace(AttributeRepository::BILLING_ADDRESS_PREFIX, '', $key)] = $value;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Update customer data
+ *
+ * @param array $data
+ * @return void
+ */
+ protected function updateCustomer(array $data)
+ {
+ $customer = $this->getCustomer();
+ $customerData = array_merge(
+ $this->customerMapper->toFlatArray($customer),
+ $data
+ );
+ $this->dataObjectHelper->populateWithArray(
+ $customer,
+ $customerData,
+ '\Magento\Customer\Api\Data\CustomerInterface'
+ );
+ }
+
+ /**
+ * Update customer address data
+ *
+ * @param array $data
+ * @return void
+ */
+ protected function updateDefaultBilling(array $data)
+ {
+ $addresses = $this->getCustomer()->getAddresses();
+ /** @var \Magento\Customer\Api\Data\AddressInterface $address */
+ foreach ($addresses as $address) {
+ if ($address->isDefaultBilling()) {
+ $this->dataObjectHelper->populateWithArray(
+ $address,
+ $this->processAddressData($data),
+ '\Magento\Customer\Api\Data\AddressInterface'
+ );
+ break;
+ }
+ }
+ }
+
+ /**
+ * Save customer with error catching
+ *
+ * @param CustomerInterface $customer
+ * @return void
+ */
+ protected function saveCustomer(CustomerInterface $customer)
+ {
+ try {
+ $this->customerRepository->save($customer);
+ } catch (\Magento\Framework\Exception\InputException $e) {
+ $this->getMessageManager()->addError($this->getErrorWithCustomerId($e->getMessage()));
+ $this->logger->critical($e);
+ } catch (\Magento\Framework\Exception\LocalizedException $e) {
+ $this->getMessageManager()->addError($this->getErrorWithCustomerId($e->getMessage()));
+ $this->logger->critical($e);
+ } catch (\Exception $e) {
+ $this->getMessageManager()->addError($this->getErrorWithCustomerId('We can\'t save the customer.'));
+ $this->logger->critical($e);
+ }
+ }
+
+ /**
+ * Parse street field
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function processAddressData(array $data)
+ {
+ foreach (['firstname', 'lastname'] as $requiredField) {
+ if (empty($data[$requiredField])) {
+ $data[$requiredField] = $this->getCustomer()->{'get' . ucfirst($requiredField)}();
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Get array with errors
+ *
+ * @return array
+ */
+ protected function getErrorMessages()
+ {
+ $messages = [];
+ foreach ($this->getMessageManager()->getMessages()->getItems() as $error) {
+ $messages[] = $error->getText();
+ }
+ return $messages;
+ }
+
+ /**
+ * Check if errors exists
+ *
+ * @return bool
+ */
+ protected function isErrorExists()
+ {
+ return (bool)$this->getMessageManager()->getMessages(true)->getCount();
+ }
+
+ /**
+ * Set customer
+ *
+ * @param CustomerInterface $customer
+ * @return $this
+ */
+ protected function setCustomer(CustomerInterface $customer)
+ {
+ $this->customer = $customer;
+ return $this;
+ }
+
+ /**
+ * Receive customer
+ *
+ * @return CustomerInterface
+ */
+ protected function getCustomer()
+ {
+ return $this->customer;
+ }
+
+ /**
+ * Add page title to error message
+ *
+ * @param string $errorText
+ * @return string
+ */
+ protected function getErrorWithCustomerId($errorText)
+ {
+ return '[Customer ID: ' . $this->getCustomer()->getId() . '] ' . __($errorText);
+ }
+
+ /**
+ * Customer access rights checking
+ *
+ * @return bool
+ */
+ protected function _isAllowed()
+ {
+ return $this->_authorization->isAllowed('Magento_Customer::manage');
+ }
+}
diff --git a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php
index a0c696bf7b588..45bca42044092 100644
--- a/app/code/Magento/Customer/Model/Resource/CustomerRepository.php
+++ b/app/code/Magento/Customer/Model/Resource/CustomerRepository.php
@@ -184,6 +184,15 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa
$customerModel->setPasswordHash($passwordHash);
}
}
+
+ // If customer email was changed, reset RpToken info
+ if ($prevCustomerData
+ && $prevCustomerData->getEmail() !== $customerModel->getEmail()
+ ) {
+ $customerModel->setRpToken(null);
+ $customerModel->setRpTokenCreatedAt(null);
+ }
+
$this->customerResourceModel->save($customerModel);
$this->customerRegistry->push($customerModel);
$customerId = $customerModel->getId();
diff --git a/app/code/Magento/Customer/Setup/UpgradeData.php b/app/code/Magento/Customer/Setup/UpgradeData.php
index c2eec0798ddab..a33b7751c6885 100644
--- a/app/code/Magento/Customer/Setup/UpgradeData.php
+++ b/app/code/Magento/Customer/Setup/UpgradeData.php
@@ -174,19 +174,7 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface
],
],
];
-
- foreach ($entityAttributes as $entityType => $attributes) {
- foreach ($attributes as $attributeCode => $attributeData) {
- $attribute = $customerSetup->getEavConfig()->getAttribute($entityType, $attributeCode);
- foreach ($attributeData as $key => $value) {
- $attribute->setData($key, $value);
- }
- $attribute->save();
- }
- }
- $indexer = $this->indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID);
- $indexer->reindexAll();
- $this->eavConfig->clear();
+ $this->upgradeAttributes($entityAttributes, $customerSetup);
}
if (version_compare($context->getVersion(), '2.0.2') < 0) {
@@ -197,6 +185,52 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface
$customerSetup->addAttributeOption($option);
}
+ if (version_compare($context->getVersion(), '2.0.3', '<')) {
+ $entityAttributes = [
+ 'customer_address' => [
+ 'region_id' => [
+ 'is_used_in_grid' => false,
+ 'is_visible_in_grid' => false,
+ 'is_filterable_in_grid' => false,
+ 'is_searchable_in_grid' => false,
+ ],
+ 'firstname' => [
+ 'is_used_in_grid' => true,
+ 'is_visible_in_grid' => false,
+ 'is_filterable_in_grid' => false,
+ 'is_searchable_in_grid' => true,
+ ],
+ 'lastname' => [
+ 'is_used_in_grid' => true,
+ 'is_visible_in_grid' => false,
+ 'is_filterable_in_grid' => false,
+ 'is_searchable_in_grid' => true,
+ ],
+ ],
+ ];
+ $this->upgradeAttributes($entityAttributes, $customerSetup);
+ }
+ $indexer = $this->indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID);
+ $indexer->reindexAll();
+ $this->eavConfig->clear();
$setup->endSetup();
}
+
+ /**
+ * @param array $entityAttributes
+ * @param CustomerSetup $customerSetup
+ * @return void
+ */
+ protected function upgradeAttributes(array $entityAttributes, CustomerSetup $customerSetup)
+ {
+ foreach ($entityAttributes as $entityType => $attributes) {
+ foreach ($attributes as $attributeCode => $attributeData) {
+ $attribute = $customerSetup->getEavConfig()->getAttribute($entityType, $attributeCode);
+ foreach ($attributeData as $key => $value) {
+ $attribute->setData($key, $value);
+ }
+ $attribute->save();
+ }
+ }
+ }
}
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php
index 60cf3b1348f7d..9d28b50d55092 100644
--- a/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Account/EditPostTest.php
@@ -3,408 +3,604 @@
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-
namespace Magento\Customer\Test\Unit\Controller\Account;
+use Magento\Customer\Api\AccountManagementInterface;
+use Magento\Customer\Api\CustomerRepositoryInterface;
+use Magento\Customer\Controller\Account\EditPost;
+use Magento\Customer\Model\CustomerExtractor;
+use Magento\Customer\Model\Session;
+use Magento\Framework\App\Action\Context;
+use Magento\Framework\App\Request\Http;
+use Magento\Framework\Controller\Result\Redirect;
+use Magento\Framework\Controller\Result\RedirectFactory;
+use Magento\Framework\Data\Form\FormKey\Validator;
+use Magento\Framework\Message\Collection as MessageCollection;
+use Magento\Framework\Message\ManagerInterface;
+use Magento\Framework\View\Result\PageFactory;
+
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class EditPostTest extends \PHPUnit_Framework_TestCase
{
/**
- * @var \Magento\Framework\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject
+ * @var EditPost
*/
- protected $context;
+ protected $model;
/**
- * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject
+ * @var Context | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $customerSession;
+ protected $context;
/**
- * @var \Magento\Framework\Controller\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject
+ * @var Session | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $resultRedirectFactory;
+ protected $session;
/**
- * @var \Magento\Framework\View\Result\PageFactory|\PHPUnit_Framework_MockObject_MockObject
+ * @var PageFactory | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $resultPageFactory;
+ protected $pageFactory;
/**
- * @var \Magento\Customer\Api\AccountManagementInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var AccountManagementInterface | \PHPUnit_Framework_MockObject_MockObject
*/
protected $customerAccountManagement;
/**
- * @var \Magento\Customer\Api\CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var CustomerRepositoryInterface | \PHPUnit_Framework_MockObject_MockObject
*/
protected $customerRepository;
/**
- * @var \Magento\Framework\Data\Form\FormKey\Validator|\PHPUnit_Framework_MockObject_MockObject
+ * @var Validator | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $formKeyValidator;
+ protected $validator;
/**
- * @var \Magento\Customer\Model\CustomerExtractor|\PHPUnit_Framework_MockObject_MockObject
+ * @var CustomerExtractor | \PHPUnit_Framework_MockObject_MockObject
*/
protected $customerExtractor;
/**
- * @var \Magento\Framework\Controller\Result\Redirect|\PHPUnit_Framework_MockObject_MockObject
+ * @var RedirectFactory | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $redirectResultMock;
+ protected $resultRedirectFactory;
/**
- * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var Redirect | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $response;
+ protected $resultRedirect;
/**
- * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var Http | \PHPUnit_Framework_MockObject_MockObject
*/
protected $request;
/**
- * @var \Magento\TestFramework\Helper\ObjectManager|\PHPUnit_Framework_MockObject_MockObject
+ * @var ManagerInterface | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $objectManager;
-
- /**
- * @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject
- */
- protected $customer;
+ protected $messageManager;
/**
- * @var \Magento\Framework\Message\Manager|\PHPUnit_Framework_MockObject_MockObject
+ * @var MessageCollection | \PHPUnit_Framework_MockObject_MockObject
*/
- protected $messageManager;
+ protected $messageCollection;
- public function setUp()
+ protected function setUp()
{
- $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-
- $this->response = $this->getMock('Magento\Framework\App\ResponseInterface', [], [], '', false);
- $this->request = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false);
-
- $this->messageManager = $this->getMock('Magento\Framework\Message\Manager', [], [], '', false);
-
- $this->resultRedirectFactory = $this->getMock(
- 'Magento\Framework\Controller\Result\RedirectFactory',
- ['create'],
- [],
- '',
- false
- );
-
- $this->context = $this->objectManager->getObject(
- 'Magento\Framework\App\Action\Context',
- [
- 'request' => $this->request,
- 'response' => $this->response,
- 'messageManager' => $this->messageManager,
- 'resultRedirectFactory' => $this->resultRedirectFactory
- ]
- );
-
- $this->redirectResultMock = $this->getMock('Magento\Framework\Controller\Result\Redirect', [], [], '', false);
- $this->customerSession = $this->getMock('Magento\Customer\Model\Session', [], [], '', false);
- $this->resultPageFactory = $this->getMock('Magento\Framework\View\Result\PageFactory', [], [], '', false);
- $this->customerAccountManagement = $this->getMockForAbstractClass(
- 'Magento\Customer\Api\AccountManagementInterface',
- [],
- '',
- false
- );
- $this->customerRepository = $this->getMockForAbstractClass(
- 'Magento\Customer\Api\CustomerRepositoryInterface',
- [],
- '',
- false
- );
- $this->formKeyValidator = $this->getMock('Magento\Framework\Data\Form\FormKey\Validator', [], [], '', false);
- $this->customerExtractor = $this->getMock('Magento\Customer\Model\CustomerExtractor', [], [], '', false);
- $this->customer = $this->getMockForAbstractClass(
- 'Magento\Customer\Api\Data\CustomerInterface',
- [],
- 'dataCustomer',
- false
+ $this->prepareContext();
+
+ $this->session = $this->getMockBuilder('Magento\Customer\Model\Session')
+ ->disableOriginalConstructor()
+ ->setMethods([
+ 'getCustomerId',
+ 'setCustomerFormData',
+ ])
+ ->getMock();
+
+ $this->pageFactory = $this->getMockBuilder('Magento\Framework\View\Result\PageFactory')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->customerAccountManagement = $this->getMockBuilder('Magento\Customer\Api\AccountManagementInterface')
+ ->getMockForAbstractClass();
+
+ $this->customerRepository = $this->getMockBuilder('Magento\Customer\Api\CustomerRepositoryInterface')
+ ->getMockForAbstractClass();
+
+ $this->validator = $this->getMockBuilder('Magento\Framework\Data\Form\FormKey\Validator')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->customerExtractor = $this->getMockBuilder('Magento\Customer\Model\CustomerExtractor')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->model = new EditPost(
+ $this->context,
+ $this->session,
+ $this->pageFactory,
+ $this->customerAccountManagement,
+ $this->customerRepository,
+ $this->validator,
+ $this->customerExtractor
);
}
- /**
- * @return \Magento\Customer\Controller\Account\EditPost
- */
- public function getController()
+ public function testInvalidFormKey()
{
- return $this->objectManager->getObject(
- 'Magento\Customer\Controller\Account\EditPost',
- [
- 'context' => $this->context,
- 'customerSession' => $this->customerSession,
- 'resultRedirectFactory' => $this->resultRedirectFactory,
- 'resultPageFactory' => $this->resultPageFactory,
- 'customerAccountManagement' => $this->customerAccountManagement,
- 'customerRepository' => $this->customerRepository,
- 'formKeyValidator' => $this->formKeyValidator,
- 'customerExtractor' => $this->customerExtractor
- ]
- );
+ $this->validator->expects($this->once())
+ ->method('validate')
+ ->with($this->request)
+ ->willReturn(false);
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('*/*/edit')
+ ->willReturnSelf();
+
+ $this->assertSame($this->resultRedirect, $this->model->execute());
}
- public function testEditPostActionWithInvalidFormKey()
+ public function testNoPostValues()
{
- $this->resultRedirectFactory
- ->expects($this->once())
- ->method('create')
- ->willReturn($this->redirectResultMock);
- $this->formKeyValidator
- ->expects($this->once())
+ $this->validator->expects($this->once())
->method('validate')
+ ->with($this->request)
+ ->willReturn(true);
+
+ $this->request->expects($this->once())
+ ->method('isPost')
->willReturn(false);
- $this->redirectResultMock
- ->expects($this->once())
+
+ $this->resultRedirect->expects($this->once())
->method('setPath')
->with('*/*/edit')
- ->willReturn('http://test.com/customer/account/edit');
+ ->willReturnSelf();
- $this->assertSame($this->redirectResultMock, $this->getController()->execute());
+ $this->assertSame($this->resultRedirect, $this->model->execute());
}
- /**
- * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
- */
- public function testEditPostActionWithAuthenticationExceptionWhenTryingChangePassword()
+ public function testGeneralSave()
{
- $customerId = 24;
- $address = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false);
- $loadedCustomer = $this->getMockForAbstractClass(
- 'Magento\Customer\Api\Data\CustomerInterface',
- [],
- 'loadedCustomer',
- false
- );
+ $customerId = 1;
- $loadedCustomer
- ->expects($this->once())
- ->method('getAddresses')
- ->willReturn([$address, $address]);
+ $address = $this->getMockBuilder('Magento\Customer\Api\Data\AddressInterface')
+ ->getMockForAbstractClass();
- $this->resultRedirectFactory
- ->expects($this->once())
- ->method('create')
- ->willReturn($this->redirectResultMock);
- $this->formKeyValidator
- ->expects($this->once())
+ $currentCustomerMock = $this->getCurrentCustomerMock($address);
+ $newCustomerMock = $this->getNewCustomerMock($customerId, $address);
+
+ $this->validator->expects($this->once())
->method('validate')
+ ->with($this->request)
->willReturn(true);
- $this->request
- ->expects($this->once())
+
+ $this->request->expects($this->once())
->method('isPost')
->willReturn(true);
+ $this->request->expects($this->once())
+ ->method('getParam')
+ ->with('change_password')
+ ->willReturn(false);
- $this->customerSession
- ->expects($this->once())
+ $this->session->expects($this->once())
->method('getCustomerId')
->willReturn($customerId);
- $this->customerExtractor
- ->expects($this->once())
- ->method('extract')
- ->willReturn($this->customer);
- $this->customer
- ->expects($this->once())
- ->method('setId')
- ->with($customerId);
- $this->customer
- ->expects($this->once())
- ->method('getAddresses')
- ->willReturn(null);
- $this->customerRepository
- ->expects($this->exactly(2))
+
+ $this->customerRepository->expects($this->once())
->method('getById')
->with($customerId)
- ->willReturn($loadedCustomer);
- $this->customer
- ->expects($this->once())
- ->method('setAddresses')
- ->with([$address, $address]);
- $this->request
- ->expects($this->once())
+ ->willReturn($currentCustomerMock);
+ $this->customerRepository->expects($this->once())
+ ->method('save')
+ ->with($newCustomerMock)
+ ->willReturnSelf();
+
+ $this->customerExtractor->expects($this->once())
+ ->method('extract')
+ ->with('customer_account_edit', $this->request)
+ ->willReturn($newCustomerMock);
+
+ $this->messageManager->expects($this->once())
+ ->method('getMessages')
+ ->willReturn($this->messageCollection);
+ $this->messageManager->expects($this->once())
+ ->method('addSuccess')
+ ->with(__('You saved the account information.'))
+ ->willReturnSelf();
+
+ $this->messageCollection->expects($this->once())
+ ->method('getCount')
+ ->willReturn(0);
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('customer/account')
+ ->willReturnSelf();
+
+ $this->assertSame($this->resultRedirect, $this->model->execute());
+ }
+
+ /**
+ * @param string $currentPassword
+ * @param string $newPassword
+ * @param string $confirmationPassword
+ * @param [] $errors
+ *
+ * @dataProvider changePasswordDataProvider
+ */
+ public function testChangePassword(
+ $currentPassword,
+ $newPassword,
+ $confirmationPassword,
+ $errors
+ ) {
+ $customerId = 1;
+ $customerEmail = 'user1@example.com';
+
+ $address = $this->getMockBuilder('Magento\Customer\Api\Data\AddressInterface')
+ ->getMockForAbstractClass();
+
+ $currentCustomerMock = $this->getCurrentCustomerMock($address);
+ $currentCustomerMock->expects($this->once())
+ ->method('getEmail')
+ ->willReturn($customerEmail);
+
+ $newCustomerMock = $this->getNewCustomerMock($customerId, $address);
+
+ $this->validator->expects($this->once())
+ ->method('validate')
+ ->with($this->request)
+ ->willReturn(true);
+
+ $this->request->expects($this->once())
+ ->method('isPost')
+ ->willReturn(true);
+ $this->request->expects($this->once())
->method('getParam')
->with('change_password')
->willReturn(true);
-
- $this->request
- ->expects($this->at(2))
- ->method('getPost')
- ->with('current_password', null)
- ->willReturn(123);
- $this->request
- ->expects($this->at(3))
- ->method('getPost')
- ->with('password', null)
- ->willReturn(321);
- $this->request
- ->expects($this->at(4))
+ $this->request->expects($this->any())
+ ->method('getPostValue')
+ ->willReturn(true);
+ $this->request->expects($this->exactly(3))
->method('getPost')
- ->with('password_confirmation', null)
- ->willReturn(321);
-
- $this->customerAccountManagement
- ->expects($this->once())
- ->method('changePassword')
- ->willThrowException(new \Magento\Framework\Exception\AuthenticationException(__('Error')));
- $this->messageManager
- ->expects($this->once())
- ->method('addError')
- ->with('Error');
+ ->willReturnMap([
+ ['current_password', null, $currentPassword],
+ ['password', null, $newPassword],
+ ['password_confirmation', null, $confirmationPassword],
+ ]);
- $exception = new \Magento\Framework\Exception\InputException(__('Error'));
- $this->customerRepository
- ->expects($this->once())
+ $this->session->expects($this->once())
+ ->method('getCustomerId')
+ ->willReturn($customerId);
+
+ // Prepare errors processing
+ if ($errors['counter'] > 0) {
+ $this->mockChangePasswordErrors($currentPassword, $newPassword, $errors, $customerEmail);
+ } else {
+ $this->customerAccountManagement->expects($this->once())
+ ->method('changePassword')
+ ->with($customerEmail, $currentPassword, $newPassword)
+ ->willReturnSelf();
+
+ $this->messageManager->expects($this->once())
+ ->method('addSuccess')
+ ->with(__('You saved the account information.'))
+ ->willReturnSelf();
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('customer/account')
+ ->willReturnSelf();
+ }
+
+ $this->customerRepository->expects($this->once())
+ ->method('getById')
+ ->with($customerId)
+ ->willReturn($currentCustomerMock);
+ $this->customerRepository->expects($this->once())
->method('save')
- ->willThrowException($exception);
- $this->messageManager
- ->expects($this->once())
- ->method('addException')
- ->with($exception, 'Invalid input');
- $this->request
- ->expects($this->once())
- ->method('getPostValue')
- ->willReturn([]);
+ ->with($newCustomerMock)
+ ->willReturnSelf();
- $messageCollection = $this->getMock('Magento\Framework\Message\Collection', [], [], '', false);
- $messageCollection
- ->expects($this->once())
- ->method('getCount')
- ->willReturn(3);
- $this->messageManager
- ->expects($this->once())
+ $this->customerExtractor->expects($this->once())
+ ->method('extract')
+ ->with('customer_account_edit', $this->request)
+ ->willReturn($newCustomerMock);
+
+ $this->messageManager->expects($this->once())
->method('getMessages')
- ->willReturn($messageCollection);
- $this->customerSession
- ->expects($this->once())
- ->method('__call')
- ->with('setCustomerFormData', [[]]);
-
- $this->redirectResultMock
- ->expects($this->once())
- ->method('setPath')
- ->with('*/*/edit')
- ->willReturn('http://test.com/customer/account/edit');
+ ->willReturn($this->messageCollection);
- $this->assertSame($this->redirectResultMock, $this->getController()->execute());
+ $this->messageCollection->expects($this->once())
+ ->method('getCount')
+ ->willReturn($errors['counter']);
+
+
+ $this->assertSame($this->resultRedirect, $this->model->execute());
}
/**
- * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * @return array
*/
- public function testEditPostActionWithoutErrors()
+ public function changePasswordDataProvider()
{
- $customerId = 24;
- $address = $this->getMockForAbstractClass('Magento\Customer\Api\Data\AddressInterface', [], '', false);
- $loadedCustomer = $this->getMockForAbstractClass(
- 'Magento\Customer\Api\Data\CustomerInterface',
- [],
- 'loadedCustomer',
- false
- );
+ return [
+ [
+ 'current_password' => '',
+ 'new_password' => '',
+ 'confirmation_password' => '',
+ 'errors' => [
+ 'counter' => 1,
+ 'message' => __('Please enter new password.'),
+ ],
+ ],
+ [
+ 'current_password' => '',
+ 'new_password' => 'user2@example.com',
+ 'confirmation_password' => 'user3@example.com',
+ 'errors' => [
+ 'counter' => 1,
+ 'message' => __('Confirm your new password.'),
+ ],
+ ],
+ [
+ 'current_password' => 'user1@example.com',
+ 'new_password' => 'user2@example.com',
+ 'confirmation_password' => 'user2@example.com',
+ 'errors' => [
+ 'counter' => 0,
+ 'message' => '',
+ ],
+ ],
+ [
+ 'current_password' => 'user1@example.com',
+ 'new_password' => 'user2@example.com',
+ 'confirmation_password' => 'user2@example.com',
+ 'errors' => [
+ 'counter' => 1,
+ 'message' => 'AuthenticationException',
+ 'exception' => '\Magento\Framework\Exception\AuthenticationException',
+ ],
+ ],
+ [
+ 'current_password' => 'user1@example.com',
+ 'new_password' => 'user2@example.com',
+ 'confirmation_password' => 'user2@example.com',
+ 'errors' => [
+ 'counter' => 1,
+ 'message' => 'Exception',
+ 'exception' => '\Exception',
+ ],
+ ],
+ ];
+ }
- $loadedCustomer
- ->expects($this->once())
- ->method('getAddresses')
- ->willReturn([$address, $address]);
+ /**
+ * @param int $counter
+ * @param string $message
+ * @param string $exception
+ *
+ * @dataProvider exceptionDataProvider
+ */
+ public function testGeneralException(
+ $counter,
+ $message,
+ $exception
+ ) {
+ $customerId = 1;
- $this->resultRedirectFactory
- ->expects($this->once())
- ->method('create')
- ->willReturn($this->redirectResultMock);
- $this->formKeyValidator
- ->expects($this->once())
+ $address = $this->getMockBuilder('Magento\Customer\Api\Data\AddressInterface')
+ ->getMockForAbstractClass();
+
+ $currentCustomerMock = $this->getCurrentCustomerMock($address);
+ $newCustomerMock = $this->getNewCustomerMock($customerId, $address);
+
+ $exception = new $exception(__($message));
+
+ $this->validator->expects($this->once())
->method('validate')
+ ->with($this->request)
->willReturn(true);
- $this->request
- ->expects($this->once())
+
+ $this->request->expects($this->once())
->method('isPost')
->willReturn(true);
+ $this->request->expects($this->once())
+ ->method('getParam')
+ ->with('change_password')
+ ->willReturn(false);
+ $this->request->expects($this->any())
+ ->method('getPostValue')
+ ->willReturn(true);
- $this->customerSession
- ->expects($this->once())
+ $this->session->expects($this->once())
->method('getCustomerId')
->willReturn($customerId);
- $this->customerExtractor
- ->expects($this->once())
+ $this->session->expects($this->once())
+ ->method('setCustomerFormData')
+ ->with(true)
+ ->willReturnSelf();
+
+ $this->customerRepository->expects($this->once())
+ ->method('getById')
+ ->with($customerId)
+ ->willReturn($currentCustomerMock);
+ $this->customerRepository->expects($this->once())
+ ->method('save')
+ ->with($newCustomerMock)
+ ->willThrowException($exception);
+
+ $this->customerExtractor->expects($this->once())
->method('extract')
- ->willReturn($this->customer);
- $this->customer
- ->expects($this->once())
+ ->with('customer_account_edit', $this->request)
+ ->willReturn($newCustomerMock);
+
+ $this->messageManager->expects($this->once())
+ ->method('getMessages')
+ ->willReturn($this->messageCollection);
+
+ $this->messageCollection->expects($this->once())
+ ->method('getCount')
+ ->willReturn($counter);
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('*/*/edit')
+ ->willReturnSelf();
+
+ $this->assertSame($this->resultRedirect, $this->model->execute());
+ }
+
+ /**
+ * @return array
+ */
+ public function exceptionDataProvider()
+ {
+ return [
+ [
+ 'counter' => 1,
+ 'message' => 'AuthenticationException',
+ 'exception' => '\Magento\Framework\Exception\AuthenticationException',
+ ],
+ [
+ 'counter' => 1,
+ 'message' => 'InputException',
+ 'exception' => '\Magento\Framework\Exception\InputException',
+ ],
+ [
+ 'counter' => 1,
+ 'message' => 'Exception',
+ 'exception' => '\Exception',
+ ],
+ ];
+ }
+
+ protected function prepareContext()
+ {
+ $this->context = $this->getMockBuilder('Magento\Framework\App\Action\Context')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->resultRedirectFactory = $this->getMockBuilder('Magento\Framework\Controller\Result\RedirectFactory')
+ ->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+
+ $this->resultRedirect = $this->getMockBuilder('Magento\Framework\Controller\Result\Redirect')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->request = $this->getMockBuilder('Magento\Framework\App\Request\Http')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->messageManager = $this->getMockBuilder('Magento\Framework\Message\ManagerInterface')
+ ->getMockForAbstractClass();
+
+ $this->messageCollection = $this->getMockBuilder('Magento\Framework\Message\Collection')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->context->expects($this->any())
+ ->method('getResultRedirectFactory')
+ ->willReturn($this->resultRedirectFactory);
+
+ $this->context->expects($this->any())
+ ->method('getRequest')
+ ->willReturn($this->request);
+
+ $this->context->expects($this->any())
+ ->method('getMessageManager')
+ ->willReturn($this->messageManager);
+
+ $this->resultRedirectFactory->expects($this->any())
+ ->method('create')
+ ->willReturn($this->resultRedirect);
+ }
+
+ /**
+ * @param int $customerId
+ * @param \PHPUnit_Framework_MockObject_MockObject $address
+ * @return \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected function getNewCustomerMock($customerId, $address)
+ {
+ $newCustomerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
+ ->getMockForAbstractClass();
+
+ $newCustomerMock->expects($this->once())
->method('setId')
- ->with($customerId);
- $this->customer
- ->expects($this->once())
+ ->with($customerId)
+ ->willReturnSelf();
+ $newCustomerMock->expects($this->once())
->method('getAddresses')
->willReturn(null);
- $this->customerRepository
- ->expects($this->exactly(2))
- ->method('getById')
- ->with($customerId)
- ->willReturn($loadedCustomer);
- $this->customer
- ->expects($this->once())
+ $newCustomerMock->expects($this->once())
->method('setAddresses')
- ->with([$address, $address]);
- $this->request
- ->expects($this->once())
- ->method('getParam')
- ->with('change_password')
- ->willReturn(true);
+ ->with([$address])
+ ->willReturn(null);
- $this->request
- ->expects($this->at(2))
- ->method('getPost')
- ->with('current_password', null)
- ->willReturn(123);
- $this->request
- ->expects($this->at(3))
- ->method('getPost')
- ->with('password', null)
- ->willReturn(321);
- $this->request
- ->expects($this->at(4))
- ->method('getPost')
- ->with('password_confirmation', null)
- ->willReturn(321);
+ return $newCustomerMock;
+ }
- $this->customerAccountManagement
- ->expects($this->once())
- ->method('changePassword');
+ /**
+ * @param \PHPUnit_Framework_MockObject_MockObject $address
+ * @return \PHPUnit_Framework_MockObject_MockObject
+ */
+ protected function getCurrentCustomerMock($address)
+ {
+ $currentCustomerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
+ ->getMockForAbstractClass();
- $this->customerRepository
- ->expects($this->once())
- ->method('save');
+ $currentCustomerMock->expects($this->once())
+ ->method('getAddresses')
+ ->willReturn([$address]);
- $messageCollection = $this->getMock('Magento\Framework\Message\Collection', [], [], '', false);
- $messageCollection
- ->expects($this->once())
- ->method('getCount')
- ->willReturn(0);
- $this->messageManager
- ->expects($this->once())
- ->method('getMessages')
- ->willReturn($messageCollection);
+ return $currentCustomerMock;
+ }
- $this->messageManager
- ->expects($this->once())
- ->method('addSuccess')
- ->with('You saved the account information.');
+ /**
+ * @param string $currentPassword
+ * @param string $newPassword
+ * @param [] $errors
+ * @param string $customerEmail
+ * @return void
+ */
+ protected function mockChangePasswordErrors($currentPassword, $newPassword, $errors, $customerEmail)
+ {
+ if (!empty($errors['exception'])) {
+ $exception = new $errors['exception'](__($errors['message']));
+
+ $this->customerAccountManagement->expects($this->once())
+ ->method('changePassword')
+ ->with($customerEmail, $currentPassword, $newPassword)
+ ->willThrowException($exception);
+
+ $this->messageManager->expects($this->any())
+ ->method('addException')
+ ->with($exception, __('Something went wrong while changing the password.'))
+ ->willReturnSelf();
+ }
+
+ $this->session->expects($this->once())
+ ->method('setCustomerFormData')
+ ->with(true)
+ ->willReturnSelf();
+
+ $this->messageManager->expects($this->any())
+ ->method('addError')
+ ->with($errors['message'])
+ ->willReturnSelf();
- $this->redirectResultMock
- ->expects($this->once())
+ $this->resultRedirect->expects($this->once())
->method('setPath')
- ->with('customer/account')
- ->willReturn('http://test.com/customer/account/edit');
-
- $this->assertSame($this->redirectResultMock, $this->getController()->execute());
+ ->with('*/*/edit')
+ ->willReturnSelf();
}
}
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/ForgotPasswordPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/ForgotPasswordPostTest.php
new file mode 100644
index 0000000000000..747c12e9c1c45
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Account/ForgotPasswordPostTest.php
@@ -0,0 +1,264 @@
+prepareContext();
+
+ $this->session = $this->getMockBuilder('Magento\Customer\Model\Session')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->pageFactory = $this->getMockBuilder('Magento\Framework\View\Result\PageFactory')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->accountManagement = $this->getMockBuilder('Magento\Customer\Api\AccountManagementInterface')
+ ->getMockForAbstractClass();
+
+ $this->escaper = $this->getMockBuilder('Magento\Framework\Escaper')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->controller = new ForgotPasswordPost(
+ $this->context,
+ $this->session,
+ $this->pageFactory,
+ $this->accountManagement,
+ $this->escaper
+ );
+ }
+
+ public function testExecuteEmptyEmail()
+ {
+ $this->request->expects($this->once())
+ ->method('getPost')
+ ->with('email')
+ ->willReturn(null);
+
+ $this->messageManager->expects($this->once())
+ ->method('addErrorMessage')
+ ->with(__('Please enter your email.'))
+ ->willReturnSelf();
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('*/*/forgotpassword')
+ ->willReturnSelf();
+
+ $this->assertSame($this->resultRedirect, $this->controller->execute());
+ }
+
+ public function testExecute()
+ {
+ $email = 'user1@example.com';
+
+ $this->request->expects($this->once())
+ ->method('getPost')
+ ->with('email')
+ ->willReturn($email);
+
+ $this->accountManagement->expects($this->once())
+ ->method('initiatePasswordReset')
+ ->with($email, AccountManagement::EMAIL_RESET)
+ ->willReturnSelf();
+
+ $this->escaper->expects($this->once())
+ ->method('escapeHtml')
+ ->with($email)
+ ->willReturn($email);
+
+ $message = __(
+ 'If there is an account associated with %1 you will receive an email with a link to reset your password.',
+ $email
+ );
+ $this->messageManager->expects($this->once())
+ ->method('addSuccessMessage')
+ ->with($message)
+ ->willReturnSelf();
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('*/*/')
+ ->willReturnSelf();
+
+ $this->controller->execute();
+ }
+
+ public function testExecuteNoSuchEntityException()
+ {
+ $email = 'user1@example.com';
+
+ $this->request->expects($this->once())
+ ->method('getPost')
+ ->with('email')
+ ->willReturn($email);
+
+ $this->accountManagement->expects($this->once())
+ ->method('initiatePasswordReset')
+ ->with($email, AccountManagement::EMAIL_RESET)
+ ->willThrowException(new NoSuchEntityException(__('NoSuchEntityException')));
+
+ $this->escaper->expects($this->once())
+ ->method('escapeHtml')
+ ->with($email)
+ ->willReturn($email);
+
+ $message = __(
+ 'If there is an account associated with %1 you will receive an email with a link to reset your password.',
+ $email
+ );
+ $this->messageManager->expects($this->once())
+ ->method('addSuccessMessage')
+ ->with($message)
+ ->willReturnSelf();
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('*/*/')
+ ->willReturnSelf();
+
+ $this->controller->execute();
+ }
+
+ public function testExecuteException()
+ {
+ $email = 'user1@example.com';
+ $exception = new \Exception(__('Exception'));
+
+ $this->request->expects($this->once())
+ ->method('getPost')
+ ->with('email')
+ ->willReturn($email);
+
+ $this->accountManagement->expects($this->once())
+ ->method('initiatePasswordReset')
+ ->with($email, AccountManagement::EMAIL_RESET)
+ ->willThrowException($exception);
+
+ $this->messageManager->expects($this->once())
+ ->method('addExceptionMessage')
+ ->with($exception, __('We\'re unable to send the password reset email.'))
+ ->willReturnSelf();
+
+ $this->resultRedirect->expects($this->once())
+ ->method('setPath')
+ ->with('*/*/forgotpassword')
+ ->willReturnSelf();
+
+ $this->controller->execute();
+ }
+
+ protected function prepareContext()
+ {
+ $this->resultRedirect = $this->getMockBuilder('Magento\Framework\Controller\Result\Redirect')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->resultRedirectFactory = $this->getMockBuilder('Magento\Framework\Controller\Result\RedirectFactory')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->context = $this->getMockBuilder('Magento\Framework\App\Action\Context')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->request = $this->getMockBuilder('Magento\Framework\App\Request\Http')
+ ->disableOriginalConstructor()
+ ->setMethods([
+ 'getPost',
+ ])
+ ->getMock();
+
+ $this->messageManager = $this->getMockBuilder('Magento\Framework\Message\ManagerInterface')
+ ->getMockForAbstractClass();
+
+ $this->resultRedirectFactory->expects($this->any())
+ ->method('create')
+ ->willReturn($this->resultRedirect);
+
+ $this->context->expects($this->any())
+ ->method('getResultRedirectFactory')
+ ->willReturn($this->resultRedirectFactory);
+
+ $this->context->expects($this->any())
+ ->method('getRequest')
+ ->willReturn($this->request);
+
+ $this->context->expects($this->any())
+ ->method('getMessageManager')
+ ->willReturn($this->messageManager);
+ }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/InlineEditTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/InlineEditTest.php
new file mode 100644
index 0000000000000..e806e30201346
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/InlineEditTest.php
@@ -0,0 +1,332 @@
+request = $this->getMockForAbstractClass('Magento\Framework\App\RequestInterface', [], '', false);
+ $this->messageManager = $this->getMockForAbstractClass(
+ 'Magento\Framework\Message\ManagerInterface',
+ [],
+ '',
+ false
+ );
+ $this->customerData = $this->getMockForAbstractClass(
+ 'Magento\Customer\Api\Data\CustomerInterface',
+ [],
+ '',
+ false
+ );
+ $this->address = $this->getMockForAbstractClass(
+ 'Magento\Customer\Api\Data\AddressInterface',
+ [],
+ 'address',
+ false
+ );
+ $this->addressMapper = $this->getMock('Magento\Customer\Model\Address\Mapper', [], [], '', false);
+ $this->customerMapper = $this->getMock('Magento\Customer\Model\Customer\Mapper', [], [], '', false);
+ $this->resultJsonFactory = $this->getMock(
+ 'Magento\Framework\Controller\Result\JsonFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+ $this->resultJson = $this->getMock('Magento\Framework\Controller\Result\Json', [], [], '', false);
+ $this->customerRepository = $this->getMockForAbstractClass(
+ 'Magento\Customer\Api\CustomerRepositoryInterface',
+ [],
+ '',
+ false
+ );
+ $this->dataObjectHelper = $this->getMock('Magento\Framework\Api\DataObjectHelper', [], [], '', false);
+ $this->addressDataFactory = $this->getMock(
+ 'Magento\Customer\Api\Data\AddressInterfaceFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+ $this->addressRepository = $this->getMockForAbstractClass(
+ 'Magento\Customer\Api\AddressRepositoryInterface',
+ [],
+ '',
+ false
+ );
+ $this->messageCollection = $this->getMock('Magento\Framework\Message\Collection', [], [], '', false);
+ $this->message = $this->getMockForAbstractClass(
+ 'Magento\Framework\Message\MessageInterface',
+ [],
+ '',
+ false
+ );
+ $this->logger = $this->getMockForAbstractClass('Psr\Log\LoggerInterface', [], '', false);
+
+ $this->context = $objectManager->getObject(
+ 'Magento\Backend\App\Action\Context',
+ [
+ 'request' => $this->request,
+ 'messageManager' => $this->messageManager,
+ ]
+ );
+ $this->controller = $objectManager->getObject(
+ 'Magento\Customer\Controller\Adminhtml\Index\InlineEdit',
+ [
+ 'context' => $this->context,
+ 'resultJsonFactory' => $this->resultJsonFactory,
+ 'customerRepository' => $this->customerRepository,
+ 'addressMapper' => $this->addressMapper,
+ 'customerMapper' => $this->customerMapper,
+ 'dataObjectHelper' => $this->dataObjectHelper,
+ 'addressDataFactory' => $this->addressDataFactory,
+ 'addressRepository' => $this->addressRepository,
+ 'logger' => $this->logger,
+ ]
+ );
+
+ $this->items = [
+ 14 => [
+ 'email' => 'test@test.ua',
+ 'billing_postcode' => '07294',
+ ]
+ ];
+ }
+
+ protected function prepareMocksForTesting($populateSequence = 0)
+ {
+ $this->resultJsonFactory->expects($this->once())
+ ->method('create')
+ ->willReturn($this->resultJson);
+ $this->request->expects($this->at(0))
+ ->method('getParam')
+ ->with('items', [])
+ ->willReturn($this->items);
+ $this->request->expects($this->at(1))
+ ->method('getParam')
+ ->with('isAjax')
+ ->willReturn(true);
+ $this->customerRepository->expects($this->once())
+ ->method('getById')
+ ->with(14)
+ ->willReturn($this->customerData);
+ $this->customerMapper->expects($this->once())
+ ->method('toFlatArray')
+ ->with($this->customerData)
+ ->willReturn(['name' => 'Firstname Lastname']);
+ $this->dataObjectHelper->expects($this->at($populateSequence))
+ ->method('populateWithArray')
+ ->with(
+ $this->customerData,
+ [
+ 'name' => 'Firstname Lastname',
+ 'email' => 'test@test.ua',
+ ],
+ '\Magento\Customer\Api\Data\CustomerInterface'
+ );
+ $this->customerData->expects($this->any())
+ ->method('getId')
+ ->willReturn(12);
+ }
+
+ protected function prepareMocksForUpdateDefaultBilling()
+ {
+ $this->prepareMocksForProcessAddressData();
+ $addressData = [
+ 'postcode' => '07294',
+ 'firstname' => 'Firstname',
+ 'lastname' => 'Lastname',
+ ];
+ $this->customerData->expects($this->once())
+ ->method('getAddresses')
+ ->willReturn([$this->address]);
+ $this->address->expects($this->once())
+ ->method('isDefaultBilling')
+ ->willReturn(true);
+ $this->dataObjectHelper->expects($this->at(0))
+ ->method('populateWithArray')
+ ->with(
+ $this->address,
+ $addressData,
+ '\Magento\Customer\Api\Data\AddressInterface'
+ );
+ }
+
+ protected function prepareMocksForProcessAddressData()
+ {
+ $this->customerData->expects($this->once())
+ ->method('getFirstname')
+ ->willReturn('Firstname');
+ $this->customerData->expects($this->once())
+ ->method('getLastname')
+ ->willReturn('Lastname');
+ }
+
+ protected function prepareMocksForErrorMessagesProcessing()
+ {
+ $this->messageManager->expects($this->atLeastOnce())
+ ->method('getMessages')
+ ->willReturn($this->messageCollection);
+ $this->messageCollection->expects($this->once())
+ ->method('getItems')
+ ->willReturn([$this->message]);
+ $this->messageCollection->expects($this->once())
+ ->method('getCount')
+ ->willReturn(1);
+ $this->message->expects($this->once())
+ ->method('getText')
+ ->willReturn('Error text');
+ $this->resultJson->expects($this->once())
+ ->method('setData')
+ ->with([
+ 'messages' => ['Error text'],
+ 'error' => true,
+ ])
+ ->willReturnSelf();
+ }
+
+ public function testExecuteWithUpdateBilling()
+ {
+ $this->prepareMocksForTesting(1);
+ $this->customerData->expects($this->once())
+ ->method('getDefaultBilling')
+ ->willReturn(23);
+ $this->prepareMocksForUpdateDefaultBilling();
+ $this->customerRepository->expects($this->once())
+ ->method('save')
+ ->with($this->customerData);
+ $this->prepareMocksForErrorMessagesProcessing();
+ $this->assertSame($this->resultJson, $this->controller->execute());
+ }
+
+ public function testExecuteWithoutItems()
+ {
+ $this->resultJsonFactory->expects($this->once())
+ ->method('create')
+ ->willReturn($this->resultJson);
+ $this->request->expects($this->at(0))
+ ->method('getParam')
+ ->with('items', [])
+ ->willReturn([]);
+ $this->request->expects($this->at(1))
+ ->method('getParam')
+ ->with('isAjax')
+ ->willReturn(false);
+ $this->resultJson
+ ->expects($this->once())
+ ->method('setData')
+ ->with([
+ 'messages' => [__('Please correct the data sent.')],
+ 'error' => true,
+ ])
+ ->willReturnSelf();
+ $this->assertSame($this->resultJson, $this->controller->execute());
+ }
+
+ public function testExecuteLocalizedException()
+ {
+ $exception = new \Magento\Framework\Exception\LocalizedException(__('Exception message'));
+ $this->prepareMocksForTesting();
+ $this->customerData->expects($this->once())
+ ->method('getDefaultBilling')
+ ->willReturn(false);
+ $this->customerRepository->expects($this->once())
+ ->method('save')
+ ->with($this->customerData)
+ ->willThrowException($exception);
+ $this->messageManager->expects($this->once())
+ ->method('addError')
+ ->with('[Customer ID: 12] Exception message');
+ $this->logger->expects($this->once())
+ ->method('critical')
+ ->with($exception);
+
+ $this->prepareMocksForErrorMessagesProcessing();
+ $this->assertSame($this->resultJson, $this->controller->execute());
+ }
+
+ public function testExecuteException()
+ {
+ $exception = new \Exception('Exception message');
+ $this->prepareMocksForTesting();
+ $this->customerData->expects($this->once())
+ ->method('getDefaultBilling')
+ ->willReturn(false);
+ $this->customerRepository->expects($this->once())
+ ->method('save')
+ ->with($this->customerData)
+ ->willThrowException($exception);
+ $this->messageManager->expects($this->once())
+ ->method('addError')
+ ->with('[Customer ID: 12] We can\'t save the customer.');
+ $this->logger->expects($this->once())
+ ->method('critical')
+ ->with($exception);
+
+ $this->prepareMocksForErrorMessagesProcessing();
+ $this->assertSame($this->resultJson, $this->controller->execute());
+ }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php
index b33d35c8f4c14..d5fc01b379051 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php
@@ -7,6 +7,7 @@
use Magento\Customer\Model\AccountManagement;
use Magento\Framework\App\Area;
+use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
use Magento\Store\Model\ScopeInterface;
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Resource/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/Resource/CustomerRepositoryTest.php
index 98ecda6bc26b2..9461c4b04d8db 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Resource/CustomerRepositoryTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Resource/CustomerRepositoryTest.php
@@ -381,12 +381,20 @@ public function testSave()
$customerSecureData->expects($this->once())
->method('getPasswordHash')
->willReturn('passwordHash');
- $customerModel->expects($this->once())
+
+ $customerModel->expects($this->exactly(2))
->method('setRpToken')
- ->with('rpToken');
- $customerModel->expects($this->once())
+ ->willReturnMap([
+ ['rpToken', $customerModel],
+ [null, $customerModel],
+ ]);
+ $customerModel->expects($this->exactly(2))
->method('setRpTokenCreatedAt')
- ->with('rpTokenCreatedAt');
+ ->willReturnMap([
+ ['rpTokenCreatedAt', $customerModel],
+ [null, $customerModel],
+ ]);
+
$customerModel->expects($this->once())
->method('setPasswordHash')
->with('passwordHash');
diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/ColumnFactoryTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/ColumnFactoryTest.php
index 4b0d7626492ef..dafcfefdc384c 100644
--- a/app/code/Magento/Customer/Test/Unit/Ui/Component/ColumnFactoryTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/ColumnFactoryTest.php
@@ -24,6 +24,9 @@ class ColumnFactoryTest extends \PHPUnit_Framework_TestCase
/** @var \Magento\Ui\Component\Listing\Columns\ColumnInterface|\PHPUnit_Framework_MockObject_MockObject */
protected $column;
+ /** @var \Magento\Customer\Ui\Component\Listing\Column\InlineEditUpdater|\PHPUnit_Framework_MockObject_MockObject */
+ protected $inlineEditUpdater;
+
/** @var ColumnFactory */
protected $columnFactory;
@@ -61,7 +64,13 @@ public function setUp()
false
);
- $this->columnFactory = new ColumnFactory($this->componentFactory);
+ $this->inlineEditUpdater = $this->getMockBuilder(
+ 'Magento\Customer\Ui\Component\Listing\Column\InlineEditUpdater'
+ )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->columnFactory = new ColumnFactory($this->componentFactory, $this->inlineEditUpdater);
}
public function testCreate()
@@ -89,7 +98,7 @@ public function testCreate()
];
$attributeData = [
'attribute_code' => 'billing_attribute_code',
- 'frontend_input' => 'frontend-input',
+ 'frontend_input' => 'text',
'frontend_label' => 'Label',
'backend_type' => 'backend-type',
'options' => [
@@ -102,8 +111,13 @@ public function testCreate()
'is_visible_in_grid' => true,
'is_filterable_in_grid' => true,
'is_searchable_in_grid' => true,
+ 'entity_type_code' => 'customer',
+ 'validation_rules' => [],
+ 'required' => false,
];
-
+ $this->inlineEditUpdater->expects($this->once())
+ ->method('applyEditing')
+ ->with($this->column, 'text', []);
$this->componentFactory->expects($this->once())
->method('create')
->with($columnName, 'column', $config)
diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/AttributeRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/AttributeRepositoryTest.php
index fcd5ff19400e9..8443aac4204c1 100644
--- a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/AttributeRepositoryTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/AttributeRepositoryTest.php
@@ -118,6 +118,12 @@ public function testGetList()
$this->attribute->expects($this->once())
->method('getIsVisibleInGrid')
->willReturn(true);
+ $this->attribute->expects($this->once())
+ ->method('getValidationRules')
+ ->willReturn([]);
+ $this->attribute->expects($this->once())
+ ->method('isRequired')
+ ->willReturn(false);
$this->option->expects($this->once())
->method('getLabel')
->willReturn('Label');
@@ -145,6 +151,9 @@ public function testGetList()
'is_visible_in_grid' => true,
'is_filterable_in_grid' => true,
'is_searchable_in_grid' => true,
+ 'validation_rules' => [],
+ 'required'=> false,
+ 'entity_type_code' => 'customer_address',
]
],
$this->component->getList()
diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/InlineEditUpdaterTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/InlineEditUpdaterTest.php
new file mode 100644
index 0000000000000..21afae3e481c3
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/InlineEditUpdaterTest.php
@@ -0,0 +1,77 @@
+validationRules = $this->getMockBuilder('Magento\Customer\Ui\Component\Listing\Column\ValidationRules')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->validationRule = $this->getMockBuilder('Magento\Customer\Api\Data\ValidationRuleInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->column = $this->getMockBuilder('Magento\Framework\View\Element\UiComponentInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->component = new InlineEditUpdater($this->validationRules);
+ }
+
+ public function testApplyEditing()
+ {
+ $this->column->expects($this->once())
+ ->method('getConfiguration')
+ ->willReturn([
+ 'dataType' => 'text',
+ 'visible' => true,
+ ]);
+ $this->validationRules->expects($this->once())
+ ->method('getValidationRules')
+ ->with(true, [$this->validationRule])
+ ->willReturn([
+ 'validate-email' => true,
+ 'required-entry' => true
+ ]);
+ $this->column->expects($this->once())
+ ->method('setData')
+ ->with(
+ 'config',
+ [
+ 'dataType' => 'text',
+ 'visible' => true,
+ 'editor' => [
+ 'editorType' => 'text',
+ 'validation' => [
+ 'validate-email' => true,
+ 'required-entry' => true,
+ ]
+ ]
+ ]
+ );
+
+ $this->component->applyEditing($this->column, 'text', [$this->validationRule], true);
+ }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/ValidationRulesTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/ValidationRulesTest.php
new file mode 100644
index 0000000000000..e65e6b903e1c0
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/ValidationRulesTest.php
@@ -0,0 +1,67 @@
+validationRules = $this->getMockBuilder('Magento\Customer\Ui\Component\Listing\Column\ValidationRules')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->validationRule = $this->getMockBuilder('Magento\Customer\Api\Data\ValidationRuleInterface')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->validationRules = new ValidationRules();
+ }
+
+ public function testGetValidationRules()
+ {
+ $expectsRules = [
+ 'required-entry' => true,
+ 'validate-number' => true,
+ ];
+ $this->validationRule->expects($this->atLeastOnce())
+ ->method('getName')
+ ->willReturn('input_validation');
+ $this->validationRule->expects($this->atLeastOnce())
+ ->method('getValue')
+ ->willReturn('numeric');
+
+ $this->assertEquals(
+ $expectsRules,
+ $this->validationRules->getValidationRules(
+ true,
+ [
+ $this->validationRule,
+ new \Magento\Framework\DataObject(),
+ ]
+ )
+ );
+ }
+
+ public function testGetValidationRulesWithOnlyRequiredRule()
+ {
+ $expectsRules = [
+ 'required-entry' => true,
+ ];
+ $this->assertEquals(
+ $expectsRules,
+ $this->validationRules->getValidationRules(true, [])
+ );
+ }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/ColumnsTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/ColumnsTest.php
index 92ec5d4082f3e..fbdfdf3ff4798 100644
--- a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/ColumnsTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/ColumnsTest.php
@@ -24,6 +24,9 @@ class ColumnsTest extends \PHPUnit_Framework_TestCase
/** @var \Magento\Ui\Component\Listing\Columns\ColumnInterface|\PHPUnit_Framework_MockObject_MockObject */
protected $column;
+ /** @var \Magento\Customer\Ui\Component\Listing\Column\InlineEditUpdater|\PHPUnit_Framework_MockObject_MockObject */
+ protected $inlineEditUpdater;
+
/** @var Columns */
protected $component;
@@ -63,10 +66,16 @@ public function setUp()
false
);
+ $this->inlineEditUpdater = $this->getMockBuilder(
+ 'Magento\Customer\Ui\Component\Listing\Column\InlineEditUpdater'
+ )->disableOriginalConstructor()
+ ->getMock();
+
$this->component = new Columns(
$this->context,
$this->columnFactory,
- $this->attributeRepository
+ $this->attributeRepository,
+ $this->inlineEditUpdater
);
}
@@ -93,6 +102,9 @@ public function testPrepareWithAddColumn()
'is_visible_in_grid' => true,
'is_filterable_in_grid' => true,
'is_searchable_in_grid' => true,
+ 'validation_rules' => [],
+ 'required'=> false,
+ 'entity_type_code' => 'customer_address',
]
]
);
@@ -111,7 +123,7 @@ public function testPrepareWithUpdateColumn()
$backendType = 'backend-type';
$attributeData = [
'attribute_code' => 'billing_attribute_code',
- 'frontend_input' => 'frontend-input',
+ 'frontend_input' => 'text',
'frontend_label' => 'frontend-label',
'backend_type' => 'backend-type',
'options' => [
@@ -124,6 +136,9 @@ public function testPrepareWithUpdateColumn()
'is_visible_in_grid' => true,
'is_filterable_in_grid' => true,
'is_searchable_in_grid' => true,
+ 'validation_rules' => [],
+ 'required'=> false,
+ 'entity_type_code' => 'customer',
];
$this->attributeRepository->expects($this->atLeastOnce())
@@ -138,7 +153,20 @@ public function testPrepareWithUpdateColumn()
->method('getData')
->with('config')
->willReturn([]);
- $this->column->expects($this->once())
+ $this->column->expects($this->at(3))
+ ->method('setData')
+ ->with(
+ 'config',
+ [
+ 'options' => [
+ [
+ 'label' => 'Label',
+ 'value' => 'Value'
+ ]
+ ]
+ ]
+ );
+ $this->column->expects($this->at(5))
->method('setData')
->with(
'config',
@@ -159,7 +187,7 @@ public function testPrepareWithUpdateStaticColumn()
$backendType = 'static';
$attributeData = [
'attribute_code' => 'billing_attribute_code',
- 'frontend_input' => 'frontend-input',
+ 'frontend_input' => 'text',
'frontend_label' => 'frontend-label',
'backend_type' => $backendType,
'options' => [
@@ -172,7 +200,13 @@ public function testPrepareWithUpdateStaticColumn()
'is_visible_in_grid' => true,
'is_filterable_in_grid' => true,
'is_searchable_in_grid' => true,
+ 'validation_rules' => [],
+ 'required'=> false,
+ 'entity_type_code' => 'customer',
];
+ $this->inlineEditUpdater->expects($this->once())
+ ->method('applyEditing')
+ ->with($this->column, 'text', [], false);
$this->attributeRepository->expects($this->atLeastOnce())
->method('getList')
@@ -185,12 +219,29 @@ public function testPrepareWithUpdateStaticColumn()
$this->column->expects($this->atLeastOnce())
->method('getData')
->with('config')
- ->willReturn([]);
- $this->column->expects($this->once())
+ ->willReturn([
+ 'editor' => 'text'
+ ]);
+ $this->column->expects($this->at(3))
+ ->method('setData')
+ ->with(
+ 'config',
+ [
+ 'editor' => 'text',
+ 'options' => [
+ [
+ 'label' => 'Label',
+ 'value' => 'Value'
+ ]
+ ]
+ ]
+ );
+ $this->column->expects($this->at(6))
->method('setData')
->with(
'config',
[
+ 'editor' => 'text',
'visible' => true
]
);
diff --git a/app/code/Magento/Customer/Ui/Component/ColumnFactory.php b/app/code/Magento/Customer/Ui/Component/ColumnFactory.php
index 59a6fca610d28..e25b1105ea2ef 100644
--- a/app/code/Magento/Customer/Ui/Component/ColumnFactory.php
+++ b/app/code/Magento/Customer/Ui/Component/ColumnFactory.php
@@ -6,41 +6,44 @@
namespace Magento\Customer\Ui\Component;
use Magento\Customer\Api\Data\AttributeMetadataInterface as AttributeMetadata;
+use Magento\Customer\Ui\Component\Listing\Column\InlineEditUpdater;
+use Magento\Customer\Api\CustomerMetadataInterface;
class ColumnFactory
{
- /**
- * @var \Magento\Framework\View\Element\UiComponentFactory
- */
+ /** @var \Magento\Framework\View\Element\UiComponentFactory */
protected $componentFactory;
- /**
- * @var array
- */
+ /** @var InlineEditUpdater */
+ protected $inlineEditUpdater;
+
+ /** @var array */
protected $jsComponentMap = [
'text' => 'Magento_Ui/js/grid/columns/column',
+ 'select' => 'Magento_Ui/js/grid/columns/select',
'date' => 'Magento_Ui/js/grid/columns/date',
];
- /**
- * @var array
- */
+ /** @var array */
protected $dataTypeMap = [
'default' => 'text',
'text' => 'text',
- 'boolean' => 'text',
- 'select' => 'text',
+ 'boolean' => 'select',
+ 'select' => 'select',
'multiselect' => 'text',
'date' => 'date',
];
/**
* @param \Magento\Framework\View\Element\UiComponentFactory $componentFactory
+ * @param InlineEditUpdater $inlineEditor
*/
public function __construct(
- \Magento\Framework\View\Element\UiComponentFactory $componentFactory
+ \Magento\Framework\View\Element\UiComponentFactory $componentFactory,
+ InlineEditUpdater $inlineEditor
) {
$this->componentFactory = $componentFactory;
+ $this->inlineEditUpdater = $inlineEditor;
}
/**
@@ -58,6 +61,9 @@ public function create(array $attributeData, $columnName, $context, array $confi
'align' => 'left',
'visible' => (bool)$attributeData[AttributeMetadata::IS_VISIBLE_IN_GRID],
], $config);
+ if (count($attributeData[AttributeMetadata::OPTIONS]) && !isset($config[AttributeMetadata::OPTIONS])) {
+ $config[AttributeMetadata::OPTIONS] = $attributeData[AttributeMetadata::OPTIONS];
+ }
if ($attributeData[AttributeMetadata::OPTIONS]) {
$config['options'] = $attributeData[AttributeMetadata::OPTIONS];
@@ -71,7 +77,14 @@ public function create(array $attributeData, $columnName, $context, array $confi
],
'context' => $context,
];
- return $this->componentFactory->create($columnName, 'column', $arguments);
+ $column = $this->componentFactory->create($columnName, 'column', $arguments);
+ $this->inlineEditUpdater->applyEditing(
+ $column,
+ $attributeData[AttributeMetadata::FRONTEND_INPUT],
+ $attributeData[AttributeMetadata::VALIDATION_RULES],
+ $attributeData[AttributeMetadata::REQUIRED]
+ );
+ return $column;
}
/**
diff --git a/app/code/Magento/Customer/Ui/Component/Listing/AttributeRepository.php b/app/code/Magento/Customer/Ui/Component/Listing/AttributeRepository.php
index 294fa32b3e872..5238b24ec8c0d 100644
--- a/app/code/Magento/Customer/Ui/Component/Listing/AttributeRepository.php
+++ b/app/code/Magento/Customer/Ui/Component/Listing/AttributeRepository.php
@@ -105,17 +105,26 @@ protected function getListForEntity(array $metadata, $entityTypeCode, MetadataMa
AttributeMetadataInterface::IS_VISIBLE_IN_GRID => $attribute->getIsVisibleInGrid(),
AttributeMetadataInterface::IS_FILTERABLE_IN_GRID => $management->canBeFilterableInGrid($attribute),
AttributeMetadataInterface::IS_SEARCHABLE_IN_GRID => $management->canBeSearchableInGrid($attribute),
+ AttributeMetadataInterface::VALIDATION_RULES => $attribute->getValidationRules(),
+ AttributeMetadataInterface::REQUIRED => $attribute->isRequired(),
+ 'entity_type_code' => $entityTypeCode,
];
}
return $attributes;
}
+ /**
+ * Convert options to array
+ *
+ * @param array $options
+ * @return array
+ */
protected function getOptionArray(array $options)
{
/** @var \Magento\Customer\Api\Data\OptionInterface $option */
foreach ($options as &$option) {
- $option = ['label' => $option->getLabel(), 'value' => $option->getValue()];
+ $option = ['label' => (string)$option->getLabel(), 'value' => $option->getValue()];
}
return $options;
}
diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Column/InlineEditUpdater.php b/app/code/Magento/Customer/Ui/Component/Listing/Column/InlineEditUpdater.php
new file mode 100644
index 0000000000000..31b3bbab0a67a
--- /dev/null
+++ b/app/code/Magento/Customer/Ui/Component/Listing/Column/InlineEditUpdater.php
@@ -0,0 +1,73 @@
+validationRules = $validationRules;
+ }
+
+ /**
+ * Add editor config
+ *
+ * @param UiComponentInterface $column
+ * @param string $frontendInput
+ * @param array $validationRules
+ * @param bool|false $isRequired
+ * @return UiComponentInterface
+ */
+ public function applyEditing(
+ UiComponentInterface $column,
+ $frontendInput,
+ array $validationRules,
+ $isRequired = false
+ ) {
+ if (in_array($frontendInput, $this->editableFields)) {
+ $config = $column->getConfiguration();
+
+ $editorType = $config['dataType'];
+ if (isset($config['editor']) && is_string($config['editor'])) {
+ $editorType = $config['editor'];
+ }
+ if (!(isset($config['editor']) && isset($config['editor']['editorType']))) {
+ $config['editor'] = [
+ 'editorType' => $editorType
+ ];
+ }
+
+ $validationRules = $this->validationRules->getValidationRules($isRequired, $validationRules);
+ if (!empty($config['editor']['validation'])) {
+ $validationRules = array_merge($config['editor']['validation'], $validationRules);
+ }
+ $config['editor']['validation'] = $validationRules;
+ $column->setData('config', $config);
+ }
+ return $column;
+ }
+}
diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Column/ValidationRules.php b/app/code/Magento/Customer/Ui/Component/Listing/Column/ValidationRules.php
new file mode 100644
index 0000000000000..a2e66be259d0f
--- /dev/null
+++ b/app/code/Magento/Customer/Ui/Component/Listing/Column/ValidationRules.php
@@ -0,0 +1,77 @@
+ 'validate-alpha',
+ 'numeric' => 'validate-number',
+ 'alphanumeric' => 'validate-alphanum',
+ 'url' => 'validate-url',
+ 'email' => 'validate-email',
+ ];
+
+ /**
+ * Return list of validation rules with their value
+ *
+ * @param boolean $isRequired
+ * @param array $validationRules
+ * @return array
+ */
+ public function getValidationRules($isRequired, $validationRules)
+ {
+ $rules = [];
+ if ($isRequired) {
+ $rules['required-entry'] = true;
+ }
+ if (empty($validationRules)) {
+ return $rules;
+ }
+ /** @var ValidationRuleInterface $rule */
+ foreach ($validationRules as $rule) {
+ if (!$rule instanceof ValidationRuleInterface) {
+ continue;
+ }
+ $validationClass = $this->getValidationClass($rule);
+ if ($validationClass) {
+ $rules[$validationClass] = $this->getRuleValue($rule);
+ }
+ }
+
+ return $rules;
+ }
+
+ /**
+ * Return validation class based on rule name or value
+ *
+ * @param ValidationRuleInterface $rule
+ * @return string
+ */
+ protected function getValidationClass(ValidationRuleInterface $rule)
+ {
+ $key = $rule->getName() == 'input_validation' ? $rule->getValue() : $rule->getName();
+ return isset($this->inputValidationMap[$key])
+ ? $this->inputValidationMap[$key]
+ : $key;
+ }
+
+ /**
+ * Return rule value
+ *
+ * @param ValidationRuleInterface $rule
+ * @return bool|string
+ */
+ protected function getRuleValue(ValidationRuleInterface $rule)
+ {
+ return $rule->getName() != 'input_validation' ? $rule->getValue() : true;
+ }
+}
diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Columns.php b/app/code/Magento/Customer/Ui/Component/Listing/Columns.php
index 2f74af7f6bd16..36b2f42d3b020 100644
--- a/app/code/Magento/Customer/Ui/Component/Listing/Columns.php
+++ b/app/code/Magento/Customer/Ui/Component/Listing/Columns.php
@@ -8,23 +8,26 @@
use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Customer\Ui\Component\ColumnFactory;
use Magento\Customer\Api\Data\AttributeMetadataInterface as AttributeMetadata;
+use Magento\Framework\View\Element\UiComponentInterface;
+use Magento\Customer\Ui\Component\Listing\Column\InlineEditUpdater;
+use Magento\Customer\Api\CustomerMetadataInterface;
class Columns extends \Magento\Ui\Component\Listing\Columns
{
- /**
- * @var int
- */
+ /** @var int */
protected $columnSortOrder;
- /**
- * @var AttributeRepository
- */
+ /** @var AttributeRepository */
protected $attributeRepository;
+ /** @var InlineEditUpdater */
+ protected $inlineEditUpdater;
+
/**
* @param ContextInterface $context
* @param ColumnFactory $columnFactory
* @param AttributeRepository $attributeRepository
+ * @param InlineEditUpdater $inlineEditor
* @param array $components
* @param array $data
*/
@@ -32,12 +35,14 @@ public function __construct(
ContextInterface $context,
ColumnFactory $columnFactory,
AttributeRepository $attributeRepository,
+ InlineEditUpdater $inlineEditor,
array $components = [],
array $data = []
) {
parent::__construct($context, $components, $data);
$this->columnFactory = $columnFactory;
$this->attributeRepository = $attributeRepository;
+ $this->inlineEditUpdater = $inlineEditor;
}
/**
@@ -111,6 +116,7 @@ public function addColumn(array $attributeData, $columnName)
public function updateColumn(array $attributeData, $newAttributeCode)
{
$component = $this->components[$attributeData[AttributeMetadata::ATTRIBUTE_CODE]];
+ $this->addOptions($component, $attributeData);
if ($attributeData[AttributeMetadata::BACKEND_TYPE] != 'static') {
if ($attributeData[AttributeMetadata::IS_USED_IN_GRID]) {
@@ -119,19 +125,47 @@ public function updateColumn(array $attributeData, $newAttributeCode)
[
'name' => $newAttributeCode,
'dataType' => $attributeData[AttributeMetadata::BACKEND_TYPE],
- 'visible' => $attributeData[AttributeMetadata::IS_VISIBLE_IN_GRID]
+ 'visible' => (bool)$attributeData[AttributeMetadata::IS_VISIBLE_IN_GRID]
]
);
$component->setData('config', $config);
}
} else {
+ if ($attributeData['entity_type_code'] == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER
+ && !empty($component->getData('config')['editor'])
+ ) {
+ $this->inlineEditUpdater->applyEditing(
+ $component,
+ $attributeData[AttributeMetadata::FRONTEND_INPUT],
+ $attributeData[AttributeMetadata::VALIDATION_RULES],
+ $attributeData[AttributeMetadata::REQUIRED]
+ );
+ }
$component->setData(
'config',
array_merge(
$component->getData('config'),
- ['visible' => $attributeData[AttributeMetadata::IS_VISIBLE_IN_GRID]]
+ ['visible' => (bool)$attributeData[AttributeMetadata::IS_VISIBLE_IN_GRID]]
)
);
}
}
+
+ /**
+ * Add options to component
+ *
+ * @param UiComponentInterface $component
+ * @param array $attributeData
+ * @return void
+ */
+ public function addOptions(UiComponentInterface $component, array $attributeData)
+ {
+ $config = $component->getData('config');
+ if (count($attributeData[AttributeMetadata::OPTIONS]) && !isset($config[AttributeMetadata::OPTIONS])) {
+ $component->setData(
+ 'config',
+ array_merge($config, [AttributeMetadata::OPTIONS => $attributeData[AttributeMetadata::OPTIONS]])
+ );
+ }
+ }
}
diff --git a/app/code/Magento/Customer/etc/indexer.xml b/app/code/Magento/Customer/etc/indexer.xml
index 093bb0b559fe3..d7aa80a12f7b5 100644
--- a/app/code/Magento/Customer/etc/indexer.xml
+++ b/app/code/Magento/Customer/etc/indexer.xml
@@ -35,11 +35,12 @@
provider="Magento\Customer\Model\Indexer\Address\AttributeProvider">
+
+
-
diff --git a/app/code/Magento/Customer/etc/module.xml b/app/code/Magento/Customer/etc/module.xml
index c6d9cd6440a39..251ffe9e53fb0 100644
--- a/app/code/Magento/Customer/etc/module.xml
+++ b/app/code/Magento/Customer/etc/module.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml
index d73c3a4b1b7c9..bb0a4f029a1d9 100644
--- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml
+++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml
@@ -307,6 +307,18 @@
+
+
+ -
+
- edit
+ - Edit
+ -
+
- customer_listing.customer_listing.customer_columns_editor
+ - editSelected
+
+
+
+
@@ -328,13 +340,23 @@
- customer_listing.customer_listing.listing_top.bookmarks
- current
+ -
+
- customer_listing.customer_listing.customer_columns.ids
+ - true
+ - entity_id
+ -
+
- customer/index/inlineEdit
+ - /path/to
+ - false
+
+
-
-
-
- customer_listing.customer_listing.customer_columns.actions
- - applyAction
+ - customer_listing.customer_listing.customer_columns_editor
+ - startEdit
-
-
- edit
- - ${ $.$data.rowIndex }
+ - ${ $.$data.rowIndex }
+ - true
- true
@@ -393,6 +415,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- text
- left
@@ -401,14 +424,17 @@
-
+
-
-
- Magento_Ui/js/grid/columns/column
+ - Magento_Ui/js/grid/columns/select
-
+
-
+
- select
+
- true
- - text
+ - select
- left
- Group
- 50
@@ -421,6 +447,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- text
- left
@@ -435,6 +462,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- text
- left
@@ -443,13 +471,13 @@
-
+
-
-
- Magento_Ui/js/grid/columns/column
+ - Magento_Ui/js/grid/columns/select
-
-
- text
+ - select
- left
- Country
- 80
@@ -484,13 +512,16 @@
-
+
-
-
- Magento_Ui/js/grid/columns/date
+ - Magento_Ui/js/grid/columns/select
-
-
- text
+ -
+
- select
+
+ - select
- left
- Web Site
- 110
@@ -576,6 +607,7 @@
- Magento_Ui/js/grid/columns/date
-
+
- date
- true
- false
- date
@@ -591,6 +623,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- false
- text
@@ -600,14 +633,15 @@
-
+
-
-
- Magento_Ui/js/grid/columns/column
+ - Magento_Ui/js/grid/columns/select
-
+
- select
- false
- - text
+ - select
- left
- Gender
- 190
@@ -634,6 +668,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- false
- text
@@ -649,6 +684,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- false
- text
@@ -664,6 +700,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- false
- text
@@ -679,6 +716,7 @@
- Magento_Ui/js/grid/columns/column
-
+
- text
- true
- false
- text
@@ -688,6 +726,38 @@
+
+
+ -
+
- Magento_Ui/js/grid/columns/column
+
+ -
+
- text
+ - true
+ - false
+ - text
+ - left
+ - Billing Firstname
+ - 250
+
+
+
+
+
+ -
+
- Magento_Ui/js/grid/columns/column
+
+ -
+
- text
+ - true
+ - false
+ - text
+ - left
+ - Billing Lastname
+ - 260
+
+
+
-
diff --git a/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php b/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php
index df00c55a6955e..87b29e5e6867e 100644
--- a/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php
+++ b/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php
@@ -6,6 +6,7 @@
namespace Magento\CustomerImportExport\Model\Import;
use Magento\CustomerImportExport\Model\Resource\Import\Customer\Storage;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
/**
* Import entity abstract customer model
@@ -23,6 +24,11 @@ abstract class AbstractCustomer extends \Magento\ImportExport\Model\Import\Entit
const COLUMN_EMAIL = '_email';
+ const COLUMN_DEFAULT_BILLING = 'default_billing';
+
+ const COLUMN_DEFAULT_SHIPPING = 'default_shipping';
+
+
/**#@-*/
/**#@+
@@ -49,7 +55,8 @@ abstract class AbstractCustomer extends \Magento\ImportExport\Model\Import\Entit
*
* @var string[]
*/
- protected $_ignoredAttributes = ['website_id', 'store_id', 'default_billing', 'default_shipping'];
+ protected $_ignoredAttributes = ['website_id', 'store_id',
+ self::COLUMN_DEFAULT_BILLING, self::COLUMN_DEFAULT_SHIPPING];
/**
* Customer collection wrapper
@@ -63,6 +70,13 @@ abstract class AbstractCustomer extends \Magento\ImportExport\Model\Import\Entit
*/
protected $_storageFactory;
+ /**
+ * If we should check column names
+ *
+ * @var bool
+ */
+ protected $needColumnCheck = true;
+
/**
* {@inheritdoc}
*/
@@ -74,6 +88,7 @@ abstract class AbstractCustomer extends \Magento\ImportExport\Model\Import\Entit
* @param \Magento\ImportExport\Model\ImportFactory $importFactory
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Framework\App\Resource $resource
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\ImportExport\Model\Export\Factory $collectionFactory
* @param \Magento\Eav\Model\Config $eavConfig
@@ -87,6 +102,7 @@ public function __construct(
\Magento\ImportExport\Model\ImportFactory $importFactory,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
\Magento\Framework\App\Resource $resource,
+ ProcessingErrorAggregatorInterface $errorAggregator,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\ImportExport\Model\Export\Factory $collectionFactory,
\Magento\Eav\Model\Config $eavConfig,
@@ -100,6 +116,7 @@ public function __construct(
$importFactory,
$resourceHelper,
$resource,
+ $errorAggregator,
$storeManager,
$collectionFactory,
$eavConfig,
@@ -168,7 +185,7 @@ public function validateRow(array $rowData, $rowNumber)
{
if (isset($this->_validatedRows[$rowNumber])) {
// check that row is already validated
- return !isset($this->_invalidRows[$rowNumber]);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNumber);
}
$this->_validatedRows[$rowNumber] = true;
$this->_processedEntitiesCount++;
@@ -178,7 +195,7 @@ public function validateRow(array $rowData, $rowNumber)
$this->_validateRowForDelete($rowData, $rowNumber);
}
- return !isset($this->_invalidRows[$rowNumber]);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNumber);
}
/**
@@ -222,7 +239,7 @@ protected function _checkUniqueKey(array $rowData, $rowNumber)
$this->addRowError(static::ERROR_INVALID_WEBSITE, $rowNumber, static::COLUMN_WEBSITE);
}
}
- return !isset($this->_invalidRows[$rowNumber]);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNumber);
}
/**
diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php
index d0eef32fc186a..712e13fd0268d 100644
--- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php
+++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php
@@ -5,6 +5,8 @@
*/
namespace Magento\CustomerImportExport\Model\Import;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
+
/**
* @SuppressWarnings(PHPMD.TooManyFields)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -212,12 +214,29 @@ class Address extends AbstractCustomer
*/
protected $dateTime;
+ /**
+ * Customer attributes
+ *
+ * @var string[]
+ */
+ protected $_customerAttributes = [];
+
+ /**
+ * Valid column names
+ *
+ * @array
+ */
+ protected $validColumnNames = [
+ "region_id", "vat_is_valid", "vat_request_date", "vat_request_id", "vat_request_success"
+ ];
+
/**
* @param \Magento\Framework\Stdlib\StringUtils $string
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\ImportExport\Model\ImportFactory $importFactory
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Framework\App\Resource $resource
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\ImportExport\Model\Export\Factory $collectionFactory
* @param \Magento\Eav\Model\Config $eavConfig
@@ -238,6 +257,7 @@ public function __construct(
\Magento\ImportExport\Model\ImportFactory $importFactory,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
\Magento\Framework\App\Resource $resource,
+ ProcessingErrorAggregatorInterface $errorAggregator,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\ImportExport\Model\Export\Factory $collectionFactory,
\Magento\Eav\Model\Config $eavConfig,
@@ -268,6 +288,7 @@ public function __construct(
$importFactory,
$resourceHelper,
$resource,
+ $errorAggregator,
$storeManager,
$collectionFactory,
$eavConfig,
@@ -374,6 +395,7 @@ protected function _initCountryRegions()
*
* @abstract
* @return boolean
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
protected function _importData()
{
@@ -387,7 +409,11 @@ protected function _importData()
foreach ($bunch as $rowNumber => $rowData) {
// check row data
- if (!$this->validateRow($rowData, $rowNumber)) {
+ if ($this->_isOptionalAddressEmpty($rowData) || !$this->validateRow($rowData, $rowNumber)) {
+ continue;
+ }
+ if ($this->getErrorAggregator()->hasToBeTerminated()) {
+ $this->getErrorAggregator()->addRowToSkip($rowNumber);
continue;
}
@@ -405,6 +431,7 @@ protected function _importData()
$deleteRowIds[] = $rowData[self::COLUMN_ADDRESS_ID];
}
}
+ $this->updateItemsCounterStats($newRows, $updateRows, $deleteRowIds);
$this->_saveAddressEntities(
$newRows,
@@ -648,6 +675,32 @@ public static function getDefaultAddressAttributeMapping()
return self::$_defaultAddressAttributeMapping;
}
+ /**
+ * check if address for import is empty (for customer composite mode)
+ *
+ * @param array $rowData
+ * @return array
+ */
+ protected function _isOptionalAddressEmpty(array $rowData)
+ {
+ if (empty($this->_customerAttributes)) {
+ return false;
+ }
+ unset(
+ $rowData[Customer::COLUMN_WEBSITE],
+ $rowData[Customer::COLUMN_STORE],
+ $rowData['_email']
+ );
+
+ foreach ($rowData as $key => $value) {
+ if (!in_array($key, $this->_customerAttributes) && !empty($value)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* Validate row for add/update action
*
@@ -755,4 +808,16 @@ protected function _checkRowDuplicate($customerId, $addressId)
return false;
}
}
+
+ /**
+ * set customer attributes
+ *
+ * @param array $customerAttributes
+ * @return $this
+ */
+ public function setCustomerAttributes($customerAttributes)
+ {
+ $this->_customerAttributes = $customerAttributes;
+ return $this;
+ }
}
diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
index a92fb906bd264..f980fb1eaca3e 100644
--- a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
+++ b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
@@ -5,6 +5,8 @@
*/
namespace Magento\CustomerImportExport\Model\Import;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
+
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
@@ -25,6 +27,8 @@ class Customer extends AbstractCustomer
const COLUMN_STORE = '_store';
+ const COLUMN_PASSWORD = 'password';
+
/**#@-*/
/**#@+
@@ -117,12 +121,47 @@ class Customer extends AbstractCustomer
*/
protected $masterAttributeCode = 'email';
+ /**
+ * Valid column names
+ *
+ * @array
+ */
+ protected $validColumnNames = [
+ self::COLUMN_DEFAULT_BILLING,
+ self::COLUMN_DEFAULT_SHIPPING,
+ self::COLUMN_PASSWORD,
+ ];
+
+ /**
+ * Customer fields in file
+ */
+ public $customerFields = [
+ 'group_id',
+ 'store_id',
+ 'updated_at',
+ 'created_at',
+ 'created_in',
+ 'prefix',
+ 'firstname',
+ 'middlename',
+ 'lastname',
+ 'suffix',
+ 'dob',
+ 'password_hash',
+ 'taxvat',
+ 'confirmation',
+ 'gender',
+ 'rp_token',
+ 'rp_token_created_at',
+ ];
+
/**
* @param \Magento\Framework\Stdlib\StringUtils $string
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\ImportExport\Model\ImportFactory $importFactory
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Framework\App\Resource $resource
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\ImportExport\Model\Export\Factory $collectionFactory
* @param \Magento\Eav\Model\Config $eavConfig
@@ -138,6 +177,7 @@ public function __construct(
\Magento\ImportExport\Model\ImportFactory $importFactory,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
\Magento\Framework\App\Resource $resource,
+ ProcessingErrorAggregatorInterface $errorAggregator,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\ImportExport\Model\Export\Factory $collectionFactory,
\Magento\Eav\Model\Config $eavConfig,
@@ -163,6 +203,7 @@ public function __construct(
$importFactory,
$resourceHelper,
$resource,
+ $errorAggregator,
$storeManager,
$collectionFactory,
$eavConfig,
@@ -196,6 +237,11 @@ public function __construct(
$this->_initStores(true)->_initAttributes();
+ $this->validColumnNames = array_merge(
+ $this->validColumnNames,
+ $this->customerFields
+ );
+
$this->_customerModel = $customerFactory->create();
/** @var $customerResource \Magento\Customer\Model\Resource\Customer */
$customerResource = $this->_customerModel->getResource();
@@ -215,30 +261,11 @@ protected function _saveCustomerEntities(array $entitiesToCreate, array $entitie
$this->_connection->insertMultiple($this->_entityTable, $entitiesToCreate);
}
- $customerFields = [
- 'group_id',
- 'store_id',
- 'updated_at',
- 'created_at',
- 'created_in',
- 'prefix',
- 'firstname',
- 'middlename',
- 'lastname',
- 'suffix',
- 'dob',
- 'password_hash',
- 'taxvat',
- 'confirmation',
- 'gender',
- 'rp_token',
- 'rp_token_created_at',
- ];
if ($entitiesToUpdate) {
$this->_connection->insertOnDuplicate(
$this->_entityTable,
$entitiesToUpdate,
- $customerFields
+ $this->customerFields
);
}
@@ -395,6 +422,7 @@ protected function _prepareDataForUpdate(array $rowData)
*
* @return bool
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.NPathComplexity)
*/
protected function _importData()
{
@@ -408,6 +436,10 @@ protected function _importData()
if (!$this->validateRow($rowData, $rowNumber)) {
continue;
}
+ if ($this->getErrorAggregator()->hasToBeTerminated()) {
+ $this->getErrorAggregator()->addRowToSkip($rowNumber);
+ continue;
+ }
if ($this->getBehavior($rowData) == \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE) {
$entitiesToDelete[] = $this->_getCustomerId(
@@ -429,6 +461,7 @@ protected function _importData()
}
}
}
+ $this->updateItemsCounterStats($entitiesToCreate, $entitiesToUpdate, $entitiesToDelete);
/**
* Save prepared data
*/
diff --git a/app/code/Magento/CustomerImportExport/Model/Import/CustomerComposite.php b/app/code/Magento/CustomerImportExport/Model/Import/CustomerComposite.php
index 5ab9b3e042b13..cd9e70e7fe225 100644
--- a/app/code/Magento/CustomerImportExport/Model/Import/CustomerComposite.php
+++ b/app/code/Magento/CustomerImportExport/Model/Import/CustomerComposite.php
@@ -5,6 +5,8 @@
*/
namespace Magento\CustomerImportExport\Model\Import;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
+
/**
* Import entity customer combined model
*
@@ -123,6 +125,24 @@ class CustomerComposite extends \Magento\ImportExport\Model\Import\AbstractEntit
*/
protected $_dataSourceModels;
+ /**
+ * If we should check column names
+ *
+ * @var bool
+ */
+ protected $needColumnCheck = true;
+
+ /**
+ * Valid column names
+ *
+ * @array
+ */
+ protected $validColumnNames = [
+ Customer::COLUMN_DEFAULT_BILLING,
+ Customer::COLUMN_DEFAULT_SHIPPING,
+ Customer::COLUMN_PASSWORD,
+ ];
+
/**
* {@inheritdoc}
*/
@@ -134,10 +154,12 @@ class CustomerComposite extends \Magento\ImportExport\Model\Import\AbstractEntit
* @param \Magento\ImportExport\Model\ImportFactory $importFactory
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Framework\App\Resource $resource
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param \Magento\CustomerImportExport\Model\Resource\Import\CustomerComposite\DataFactory $dataFactory
* @param \Magento\CustomerImportExport\Model\Import\CustomerFactory $customerFactory
* @param \Magento\CustomerImportExport\Model\Import\AddressFactory $addressFactory
* @param array $data
+ * @throws \Magento\Framework\Exception\LocalizedException
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
@@ -147,12 +169,13 @@ public function __construct(
\Magento\ImportExport\Model\ImportFactory $importFactory,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
\Magento\Framework\App\Resource $resource,
+ ProcessingErrorAggregatorInterface $errorAggregator,
\Magento\CustomerImportExport\Model\Resource\Import\CustomerComposite\DataFactory $dataFactory,
\Magento\CustomerImportExport\Model\Import\CustomerFactory $customerFactory,
\Magento\CustomerImportExport\Model\Import\AddressFactory $addressFactory,
array $data = []
) {
- parent::__construct($string, $scopeConfig, $importFactory, $resourceHelper, $resource, $data);
+ parent::__construct($string, $scopeConfig, $importFactory, $resourceHelper, $resource, $errorAggregator, $data);
$this->addMessageTemplate(
self::ERROR_ROW_IS_ORPHAN,
@@ -201,6 +224,13 @@ public function __construct(
}
$this->_initAddressAttributes();
+ $this->validColumnNames = array_merge(
+ $this->validColumnNames,
+ $this->_customerAttributes,
+ $this->_addressAttributes,
+ $this->_customerEntity->customerFields
+ );
+
// next customer id
if (isset($data['next_customer_id'])) {
$this->_nextCustomerId = $data['next_customer_id'];
@@ -248,7 +278,7 @@ protected function _importData()
{
$result = $this->_customerEntity->importData();
if ($this->getBehavior() != \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE) {
- return $result && $this->_addressEntity->importData();
+ return $result && $this->_addressEntity->setCustomerAttributes($this->_customerAttributes)->importData();
}
return $result;
@@ -417,53 +447,6 @@ public function setSource(\Magento\ImportExport\Model\Import\AbstractSource $sou
return parent::setSource($source);
}
- /**
- * Returns error information grouped by error types and translated (if possible)
- *
- * @return array
- */
- public function getErrorMessages()
- {
- $errors = $this->_customerEntity->getErrorMessages();
- $addressErrors = $this->_addressEntity->getErrorMessages();
- foreach ($addressErrors as $message => $rowNumbers) {
- if (isset($errors[$message])) {
- foreach ($rowNumbers as $rowNumber) {
- $errors[$message][] = $rowNumber;
- }
- $errors[$message] = array_unique($errors[$message]);
- } else {
- $errors[$message] = $rowNumbers;
- }
- }
-
- return array_merge($errors, parent::getErrorMessages());
- }
-
- /**
- * Returns error counter value
- *
- * @return int
- */
- public function getErrorsCount()
- {
- return $this->_customerEntity->getErrorsCount() +
- $this->_addressEntity->getErrorsCount() +
- parent::getErrorsCount();
- }
-
- /**
- * Returns invalid rows count
- *
- * @return int
- */
- public function getInvalidRowsCount()
- {
- return $this->_customerEntity->getInvalidRowsCount() +
- $this->_addressEntity->getInvalidRowsCount() +
- parent::getInvalidRowsCount();
- }
-
/**
* Returns number of checked entities
*
diff --git a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AbstractCustomerTest.php b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AbstractCustomerTest.php
index ce747c47d4ea1..64a4161c3625c 100644
--- a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AbstractCustomerTest.php
+++ b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AbstractCustomerTest.php
@@ -11,7 +11,7 @@
use Magento\CustomerImportExport\Model\Import\AbstractCustomer;
-class AbstractCustomerTest extends \PHPUnit_Framework_TestCase
+class AbstractCustomerTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
* Abstract customer export model
@@ -77,8 +77,15 @@ protected function _getModelMock()
$modelMock = $this->getMockBuilder('Magento\CustomerImportExport\Model\Import\AbstractCustomer')
->disableOriginalConstructor()
- ->setMethods(['_getCustomerCollection', '_validateRowForUpdate', '_validateRowForDelete'])
- ->getMockForAbstractClass();
+ ->setMethods(
+ [
+ 'getErrorAggregator',
+ '_getCustomerCollection',
+ '_validateRowForUpdate',
+ '_validateRowForDelete'
+ ]
+ )->getMockForAbstractClass();
+ $modelMock->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
$property = new \ReflectionProperty($modelMock, '_websiteCodeToId');
$property->setAccessible(true);
@@ -165,6 +172,7 @@ public function checkUniqueKeyDataProvider()
* @param array $rowData
* @param array $errors
* @param boolean $isValid
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function testCheckUniqueKey(array $rowData, array $errors, $isValid = false)
{
@@ -179,7 +187,6 @@ public function testCheckUniqueKey(array $rowData, array $errors, $isValid = fal
} else {
$this->assertFalse($checkUniqueKey->invoke($this->_model, $rowData, 0));
}
- $this->assertAttributeEquals($errors, '_errors', $this->_model);
}
public function testValidateRowForUpdate()
diff --git a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AddressTest.php b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AddressTest.php
index 5234e871462d8..5aa8f1c34cb05 100644
--- a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AddressTest.php
+++ b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/AddressTest.php
@@ -105,6 +105,12 @@ class AddressTest extends \PHPUnit_Framework_TestCase
*/
protected $_objectManagerMock;
+ /**
+ * @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface
+ * |\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $errorAggregator;
+
/**
* Init entity adapter model
*/
@@ -120,6 +126,13 @@ protected function setUp()
->method('getWebsites')
->will($this->returnCallback([$this, 'getWebsites']));
$this->_model = $this->_getModelMock();
+ $this->errorAggregator = $this->getMock(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator',
+ ['hasToBeTerminated'],
+ [],
+ '',
+ false
+ );
}
/**
@@ -351,7 +364,8 @@ protected function _getModelMockForTestImportDataWithCustomBehaviour()
'_saveAddressAttributes',
'_saveCustomerDefaults',
'_deleteAddressEntities',
- '_mergeEntityAttributes'
+ '_mergeEntityAttributes',
+ 'getErrorAggregator'
],
[],
'',
@@ -384,6 +398,9 @@ protected function _getModelMockForTestImportDataWithCustomBehaviour()
// mock expects for entity adapter
$modelMock->expects($this->any())->method('validateRow')->will($this->returnValue(true));
+ $modelMock->expects($this->any())
+ ->method('getErrorAggregator')
+ ->will($this->returnValue($this->errorAggregator));
$modelMock->expects($this->any())->method('_prepareDataForUpdate')->will($this->returnValue($updateResult));
@@ -426,6 +443,13 @@ protected function _getModelMock()
$this->getMock('Magento\ImportExport\Model\ImportFactory', [], [], '', false),
$this->getMock('Magento\ImportExport\Model\Resource\Helper', [], [], '', false),
$this->getMock('Magento\Framework\App\Resource', [], [], '', false),
+ $this->getMock(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface',
+ [],
+ [],
+ '',
+ false
+ ),
$this->_storeManager,
$this->getMock('Magento\ImportExport\Model\Export\Factory', [], [], '', false),
$this->getMock('Magento\Eav\Model\Config', [], [], '', false),
@@ -440,13 +464,7 @@ protected function _getModelMock()
$this->getMock('Magento\Directory\Model\Resource\Region\CollectionFactory', [], [], '', false),
$this->getMock('Magento\Customer\Model\CustomerFactory', [], [], '', false),
$this->getMock('Magento\Customer\Model\Resource\Address\CollectionFactory', [], [], '', false),
- $this->getMock(
- 'Magento\Customer\Model\Resource\Address\Attribute\CollectionFactory',
- [],
- [],
- '',
- false
- ),
+ $this->getMock('Magento\Customer\Model\Resource\Address\Attribute\CollectionFactory', [], [], '', false),
new \Magento\Framework\Stdlib\DateTime(),
$this->_getModelDependencies()
);
@@ -476,30 +494,6 @@ public function validateRowForUpdateDataProvider()
'$errors' => [],
'$isValid' => true,
],
- 'no customer' => [
- '$rowData' => include __DIR__ . '/_files/row_data_address_update_no_customer.php',
- '$errors' => [
- Address::ERROR_CUSTOMER_NOT_FOUND => [
- [1, null],
- ],
- ],
- ],
- 'absent required attribute' => [
- '$rowData' => include __DIR__ . '/_files/row_data_address_update_absent_required_attribute.php',
- '$errors' => [
- Address::ERROR_VALUE_IS_REQUIRED => [
- [1, Address::COLUMN_COUNTRY_ID],
- ],
- ],
- ],
- 'invalid region' => [
- '$rowData' => include __DIR__ . '/_files/row_data_address_update_invalid_region.php',
- '$errors' => [
- Address::ERROR_INVALID_REGION => [
- [1, Address::COLUMN_REGION],
- ],
- ],
- ]
];
}
@@ -516,30 +510,6 @@ public function validateRowForDeleteDataProvider()
'$errors' => [],
'$isValid' => true,
],
- 'empty address id' => [
- '$rowData' => include __DIR__ . '/_files/row_data_address_delete_empty_address_id.php',
- '$errors' => [
- Address::ERROR_ADDRESS_ID_IS_EMPTY => [
- [1, null],
- ],
- ],
- ],
- 'invalid address' => [
- '$rowData' => include __DIR__ . '/_files/row_data_address_delete_address_not_found.php',
- '$errors' => [
- Address::ERROR_ADDRESS_NOT_FOUND => [
- [1, null],
- ],
- ],
- ],
- 'no customer' => [
- '$rowData' => include __DIR__ . '/_files/row_data_address_delete_no_customer.php',
- '$errors' => [
- Address::ERROR_CUSTOMER_NOT_FOUND => [
- [1, null],
- ],
- ],
- ]
];
}
@@ -549,6 +519,7 @@ public function validateRowForDeleteDataProvider()
* @param array $rowData
* @param array $errors
* @param boolean $isValid
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function testValidateRowForUpdate(array $rowData, array $errors, $isValid = false)
{
@@ -559,7 +530,6 @@ public function testValidateRowForUpdate(array $rowData, array $errors, $isValid
} else {
$this->assertFalse($this->_model->validateRow($rowData, 0));
}
- $this->assertAttributeEquals($errors, '_errors', $this->_model);
}
/**
@@ -575,7 +545,7 @@ public function testValidateRowForUpdateDuplicateRows()
$this->_model->setParameters(['behavior' => $behavior]);
- $secondRow = $firstRow = [
+ $firstRow = [
'_website' => 'website1',
'_email' => 'test1@email.com',
'_entity_id' => '1',
@@ -601,16 +571,7 @@ public function testValidateRowForUpdateDuplicateRows()
'_address_default_billing_' => '1',
'_address_default_shipping_' => '1',
];
- $secondRow['postcode'] = '90210';
-
- $errors = [
- Address::ERROR_DUPLICATE_PK => [[2, null]],
- ];
-
$this->assertTrue($this->_model->validateRow($firstRow, 0));
- $this->assertFalse($this->_model->validateRow($secondRow, 1));
-
- $this->assertAttributeEquals($errors, '_errors', $this->_model);
}
/**
@@ -622,6 +583,7 @@ public function testValidateRowForUpdateDuplicateRows()
* @param array $rowData
* @param array $errors
* @param boolean $isValid
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function testValidateRowForDelete(array $rowData, array $errors, $isValid = false)
{
@@ -632,7 +594,6 @@ public function testValidateRowForDelete(array $rowData, array $errors, $isValid
} else {
$this->assertFalse($this->_model->validateRow($rowData, 0));
}
- $this->assertAttributeEquals($errors, '_errors', $this->_model);
}
/**
diff --git a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerCompositeTest.php b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerCompositeTest.php
index 085a36afdb834..a66a1bb84af1d 100644
--- a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerCompositeTest.php
+++ b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerCompositeTest.php
@@ -59,12 +59,12 @@ class CustomerCompositeTest extends \PHPUnit_Framework_TestCase
protected $_dataFactory;
/**
- * @var CustomerFactory
+ * @var \Magento\CustomerImportExport\Model\Import\CustomerFactory
*/
protected $_customerFactory;
/**
- * @var AddressFactory
+ * @var \Magento\CustomerImportExport\Model\Import\AddressFactory
*/
protected $_addressFactory;
@@ -73,6 +73,23 @@ class CustomerCompositeTest extends \PHPUnit_Framework_TestCase
*/
protected $_scopeConfigMock;
+ /**
+ * @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface
+ * |\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $errorAggregator;
+
+ /**
+ * @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError $newError
+ */
+ protected $error;
+
+ /**
+ * @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorFactory
+ * |\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $errorFactory;
+
/**
* Expected prepared data after method CustomerComposite::_prepareRowForDb
*
@@ -151,6 +168,33 @@ protected function setUp()
false
);
+ $this->errorFactory = $this->getMock(
+ '\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+
+ $this->error = $this->getMock(
+ '\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError',
+ ['init'],
+ [],
+ '',
+ false
+ );
+
+ $this->errorFactory->expects($this->any())->method('create')->will($this->returnValue($this->error));
+ $this->error->expects($this->any())->method('init')->will($this->returnValue(true));
+
+ $this->errorAggregator = $this->getMock(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator',
+ ['hasToBeTerminated'],
+ [$this->errorFactory],
+ '',
+ true
+ );
+
$this->_scopeConfigMock = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
}
@@ -166,6 +210,7 @@ protected function _createModelMock($data)
$this->_importFactory,
$this->_resourceHelper,
$this->_resource,
+ $this->errorAggregator,
$this->_dataFactory,
$this->_customerFactory,
$this->_addressFactory,
@@ -542,24 +587,6 @@ public function getRowDataProvider()
'$expectedErrors' => [],
'$behavior' => Import::BEHAVIOR_APPEND,
],
- 'customer and addresses row with filed validation, append behavior' => [
- '$rows' => [
- [
- Customer::COLUMN_EMAIL => 'test@test.com',
- Customer::COLUMN_WEBSITE => 'admin',
- Address::COLUMN_ADDRESS_ID => null,
- ],
- [
- Customer::COLUMN_EMAIL => '',
- Customer::COLUMN_WEBSITE => '',
- Address::COLUMN_ADDRESS_ID => 1
- ],
- ],
- '$calls' => ['customerValidationCalls' => 1, 'addressValidationCalls' => 0],
- '$validationReturn' => false,
- '$expectedErrors' => ['Orphan rows that will be skipped due default row errors'],
- '$behavior' => Import::BEHAVIOR_APPEND,
- ]
];
}
@@ -623,42 +650,6 @@ public function testSetSource()
$modelUnderTest->setSource($source);
}
- public function testGetErrorMessages()
- {
- $errorMessages = [
- 'Required field' => [1, 2, 3],
- 'Bad password' => [1],
- 'Wrong website' => [1, 2],
- ];
- $customerEntity = $this->_getCustomerEntityMock();
- $customerEntity->expects($this->once())->method('getErrorMessages')->will($this->returnValue($errorMessages));
-
- $errorMessages = ['Required field' => [2, 3, 4, 5], 'Wrong address' => [1, 2]];
- $addressEntity = $this->_getAddressEntityMock();
- $addressEntity->expects($this->once())->method('getErrorMessages')->will($this->returnValue($errorMessages));
-
- $data = $this->_getModelDependencies();
- $data['customer_entity'] = $customerEntity;
- $data['address_entity'] = $addressEntity;
-
- $modelUnderTest = $this->_createModelMock($data);
-
- $modelUnderTest->addRowError('Bad password', 1);
-
- $expectedErrors = [
- 'Required field' => [1, 2, 3, 4, 5],
- 'Bad password' => [2],
- 'Wrong website' => [1, 2],
- 'Wrong address' => [1, 2],
- ];
-
- $actualErrors = $modelUnderTest->getErrorMessages();
- foreach ($expectedErrors as $error => $rows) {
- $this->assertArrayHasKey($error, $actualErrors);
- $this->assertSame($rows, array_values($actualErrors[$error]));
- }
- }
-
public function testPrepareRowForDb()
{
$modelUnderTest = $this->_getModelMockForPrepareRowForDb();
@@ -764,26 +755,6 @@ public function testImportData($behavior, $customerImport, $addressImport, $resu
}
}
- public function testGetErrorsCount()
- {
- $customerReturnData = 1;
- $addressReturnData = 2;
- $model = $this->_getModelForGetterTest('getErrorsCount', $customerReturnData, $addressReturnData);
- $model->addRowError(CustomerComposite::ERROR_ROW_IS_ORPHAN, 1);
-
- $this->assertEquals($customerReturnData + $addressReturnData + 1, $model->getErrorsCount());
- }
-
- public function testGetInvalidRowsCount()
- {
- $customerReturnData = 3;
- $addressReturnData = 2;
- $model = $this->_getModelForGetterTest('getInvalidRowsCount', $customerReturnData, $addressReturnData);
- $model->addRowError(CustomerComposite::ERROR_ROW_IS_ORPHAN, 1);
-
- $this->assertEquals($customerReturnData + $addressReturnData + 1, $model->getInvalidRowsCount());
- }
-
public function testGetProcessedEntitiesCount()
{
$customerReturnData = 3;
diff --git a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerTest.php b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerTest.php
index 82a6a12863992..d59e5cc96dc35 100644
--- a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerTest.php
+++ b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Import/CustomerTest.php
@@ -91,9 +91,18 @@ protected function _getModelMockForTestImportDataWithCustomBehaviour()
'_saveCustomerEntities',
'_saveCustomerAttributes',
'_deleteCustomerEntities',
+ 'getErrorAggregator',
])
->getMock();
+ $errorAggregator = $this->getMock(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator',
+ ['hasToBeTerminated'],
+ [],
+ '',
+ false
+ );
+
$availableBehaviors = new \ReflectionProperty($modelMock, '_availableBehaviors');
$availableBehaviors->setAccessible(true);
$availableBehaviors->setValue($modelMock, $this->_availableBehaviors);
@@ -145,6 +154,10 @@ protected function _getModelMockForTestImportDataWithCustomBehaviour()
->method('_deleteCustomerEntities')
->will($this->returnCallback([$this, 'validateDeleteCustomerEntities']));
+ $modelMock->expects($this->any())
+ ->method('getErrorAggregator')
+ ->will($this->returnValue($errorAggregator));
+
return $modelMock;
}
diff --git a/app/code/Magento/Developer/Console/Command/CssDeployCommand.php b/app/code/Magento/Developer/Console/Command/CssDeployCommand.php
index 27f5c8658ca02..4abf04b34f01f 100644
--- a/app/code/Magento/Developer/Console/Command/CssDeployCommand.php
+++ b/app/code/Magento/Developer/Console/Command/CssDeployCommand.php
@@ -219,22 +219,23 @@ protected function execute(InputInterface $input, OutputInterface $output)
]
);
+ $rootDir = $this->filesystem->getDirectoryWrite(DirectoryList::ROOT);
$sourceFile = $this->assetSource->findSource($asset);
- $content = \file_get_contents($sourceFile);
+ $relativePath = $rootDir->getRelativePath($sourceFile);
+ $content = $rootDir->readFile($relativePath);
$chain = $this->chainFactory->create(
[
'asset' => $asset,
'origContent' => $content,
'origContentType' => $asset->getContentType(),
- 'origAssetPath' => $asset->getFilePath()
+ 'origAssetPath' => $relativePath
]
);
$processedCoreFile = $sourceFileGenerator->generateFileTree($chain);
$targetDir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
- $rootDir = $this->filesystem->getDirectoryWrite(DirectoryList::ROOT);
$source = $rootDir->getRelativePath($processedCoreFile);
$destination = $asset->getPath();
$rootDir->copyFile($source, $destination, $targetDir);
diff --git a/app/code/Magento/Developer/Model/Config/Backend/AllowedIps.php b/app/code/Magento/Developer/Model/Config/Backend/AllowedIps.php
index 49be834c93dfd..234d2e6707f0b 100644
--- a/app/code/Magento/Developer/Model/Config/Backend/AllowedIps.php
+++ b/app/code/Magento/Developer/Model/Config/Backend/AllowedIps.php
@@ -17,6 +17,13 @@ class AllowedIps extends \Magento\Framework\App\Config\Value
*/
private $messageManager;
+ /**
+ * Escaper
+ *
+ * @var \Magento\Framework\Escaper
+ */
+ protected $escaper;
+
/**
* Constructor
*
@@ -24,6 +31,7 @@ class AllowedIps extends \Magento\Framework\App\Config\Value
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\App\Config\ScopeConfigInterface $config
* @param \Magento\Framework\Message\ManagerInterface $messageManager
+ * @param \Magento\Framework\Escaper $escaper
* @param \Magento\Framework\Model\Resource\AbstractResource $resource
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
* @param array $data
@@ -33,11 +41,13 @@ public function __construct(
\Magento\Framework\Registry $registry,
\Magento\Framework\App\Config\ScopeConfigInterface $config,
\Magento\Framework\Message\ManagerInterface $messageManager,
+ \Magento\Framework\Escaper $escaper,
\Magento\Framework\Model\Resource\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
) {
$this->messageManager = $messageManager;
+ $this->escaper = $escaper;
parent::__construct($context, $registry, $config, $resource, $resourceCollection, $data);
}
@@ -48,7 +58,7 @@ public function __construct(
*/
public function beforeSave()
{
- $allowedIpsRaw = $this->getValue();
+ $allowedIpsRaw = $this->escaper->escapeHtml($this->getValue());
$noticeMsgArray = [];
$allowedIpsArray = [];
diff --git a/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php b/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php
index 5d49f932b72c4..d274aa003133d 100644
--- a/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php
+++ b/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php
@@ -113,6 +113,8 @@ public function testExecute()
->method('create')
->with('less')
->willReturn($this->getMock('Magento\Framework\View\Asset\SourceFileGeneratorInterface'));
+ $asset = $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface');
+ $asset->expects($this->once())->method('getContentType')->willReturn('type');
$this->assetRepo->expects($this->once())
->method('createAsset')
->with(
@@ -123,18 +125,28 @@ public function testExecute()
'locale' => 'en_US'
]
)
- ->willReturn(
- $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface')
- );
+ ->willReturn($asset);
$this->assetSource->expects($this->once())->method('findSource')->willReturn('/dev/null');
- $this->chainFactory->expects($this->once())->method('create')->willReturn(
- $this->getMock('Magento\Framework\View\Asset\PreProcessor\Chain', [], [], '', false)
- );
+ $this->chainFactory->expects($this->once())
+ ->method('create')
+ ->with(
+ [
+ 'asset' => $asset,
+ 'origContent' => 'content',
+ 'origContentType' => 'type',
+ 'origAssetPath' => 'relative/path',
+ ]
+ )
+ ->willReturn($this->getMock('Magento\Framework\View\Asset\PreProcessor\Chain', [], [], '', false));
- $this->filesystem->expects($this->atLeastOnce())->method('getDirectoryWrite')->willReturn(
+ $rootDir = $this->getMock('\Magento\Framework\Filesystem\Directory\WriteInterface', [], [], '', false);
+ $this->filesystem->expects($this->at(0))->method('getDirectoryWrite')->willReturn($rootDir);
+ $this->filesystem->expects($this->at(1))->method('getDirectoryWrite')->willReturn(
$this->getMock('\Magento\Framework\Filesystem\Directory\WriteInterface', [], [], '', false)
);
+ $rootDir->expects($this->atLeastOnce())->method('getRelativePath')->willReturn('relative/path');
+ $rootDir->expects($this->once())->method('readFile')->willReturn('content');
$this->validator->expects($this->once())->method('isValid')->with('en_US')->willReturn(true);
diff --git a/app/code/Magento/Developer/Test/Unit/Model/Config/Backend/AllowedIpsTest.php b/app/code/Magento/Developer/Test/Unit/Model/Config/Backend/AllowedIpsTest.php
index bd6b0714c0cb4..e42646559a77b 100644
--- a/app/code/Magento/Developer/Test/Unit/Model/Config/Backend/AllowedIpsTest.php
+++ b/app/code/Magento/Developer/Test/Unit/Model/Config/Backend/AllowedIpsTest.php
@@ -30,11 +30,12 @@ protected function setUp()
->willReturn($eventMangerMock);
$objectManagerHelper = new ObjectManagerHelper($this);
-
+ $escaper = $objectManagerHelper->getObject('\Magento\Framework\Escaper');
$this->model = $objectManagerHelper->getObject(
'Magento\Developer\Model\Config\Backend\AllowedIps',
[
'context' => $contextMock,
+ 'escaper' => $escaper,
]
);
}
diff --git a/app/code/Magento/Directory/Test/Unit/Block/CurrencyTest.php b/app/code/Magento/Directory/Test/Unit/Block/CurrencyTest.php
index 598dfb6777f5f..b20375ee93740 100644
--- a/app/code/Magento/Directory/Test/Unit/Block/CurrencyTest.php
+++ b/app/code/Magento/Directory/Test/Unit/Block/CurrencyTest.php
@@ -26,8 +26,8 @@ class CurrencyTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
$this->urlBuilder = $this->getMock(
- '\Magento\Framework\UrlInterface\Proxy',
- ['getUrl'],
+ '\Magento\Framework\UrlInterface',
+ [],
[],
'',
false
diff --git a/app/code/Magento/Directory/etc/zip_codes.xml b/app/code/Magento/Directory/etc/zip_codes.xml
index dfca9b740fa03..1c9a840a69633 100644
--- a/app/code/Magento/Directory/etc/zip_codes.xml
+++ b/app/code/Magento/Directory/etc/zip_codes.xml
@@ -455,12 +455,12 @@
- ^[a-zA-Z]{2}[0-9]{2}\s[0-9]{1}[a-zA-Z]{2}$
- ^[a-zA-Z]{1}[0-9]{1}[a-zA-Z]{1}\s[0-9]{1}[a-zA-Z]{2}$
- ^[a-zA-Z]{2}[0-9]{1}\s[0-9]{1}[a-zA-Z]{2}$
- ^[a-zA-Z]{2}[0-9]{1}[a-zA-Z]{1}\s[0-9]{1}[a-zA-Z]{2}$
- ^[a-zA-Z]{1}[0-9]{2}\s[0-9]{1}[a-zA-Z]{2}$
- ^[a-zA-Z]{1}[0-9]{1}\s[0-9]{1}[a-zA-Z]{2}$
+ ^[a-zA-Z]{2}[0-9]{2}\s?[0-9]{1}[a-zA-Z]{2}$
+ ^[a-zA-Z]{1}[0-9]{1}[a-zA-Z]{1}\s?[0-9]{1}[a-zA-Z]{2}$
+ ^[a-zA-Z]{2}[0-9]{1}\s?[0-9]{1}[a-zA-Z]{2}$
+ ^[a-zA-Z]{2}[0-9]{1}[a-zA-Z]{1}\s?[0-9]{1}[a-zA-Z]{2}$
+ ^[a-zA-Z]{1}[0-9]{2}\s?[0-9]{1}[a-zA-Z]{2}$
+ ^[a-zA-Z]{1}[0-9]{1}\s?[0-9]{1}[a-zA-Z]{2}$
diff --git a/app/code/Magento/DownloadableImportExport/Helper/Data.php b/app/code/Magento/DownloadableImportExport/Helper/Data.php
new file mode 100644
index 0000000000000..04a31a817300e
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/Helper/Data.php
@@ -0,0 +1,98 @@
+fileHelper = $fileHelper;
+ $this->fileUploader = $uploaderFactory->create();
+ $this->fileUploader->init();
+ $this->fileUploader->setAllowedExtensions($this->getAllowedExtensions());
+ $this->fileUploader->removeValidateCallback('catalog_product_image');
+ $this->connection = $resource->getConnection('write');
+ $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+ }
+
+ /**
+ * Returns an object for upload a media files
+ *
+ * @param string $type
+ * @param array $parameters
+ * @return \Magento\CatalogImportExport\Model\Import\Uploader
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function getUploader($type, $parameters)
+ {
+ $dirConfig = DirectoryList::getDefaultConfig();
+ $dirAddon = $dirConfig[DirectoryList::MEDIA][DirectoryList::PATH];
+
+ $DS = DIRECTORY_SEPARATOR;
+
+ if (!empty($parameters[\Magento\ImportExport\Model\Import::FIELD_NAME_IMG_FILE_DIR])) {
+ $tmpPath = $parameters[\Magento\ImportExport\Model\Import::FIELD_NAME_IMG_FILE_DIR];
+ } else {
+ $tmpPath = $dirAddon . $DS . $this->mediaDirectory->getRelativePath('import');
+ }
+
+ if (!$this->fileUploader->setTmpDir($tmpPath)) {
+ throw new \Magento\Framework\Exception\LocalizedException(
+ __('File directory \'%1\' is not readable.', $tmpPath)
+ );
+ }
+ $destinationDir = "downloadable/files/" . $type;
+ $destinationPath = $dirAddon . $DS . $this->mediaDirectory->getRelativePath($destinationDir);
+
+ $this->mediaDirectory->create($destinationDir);
+ if (!$this->fileUploader->setDestDir($destinationPath)) {
+ throw new \Magento\Framework\Exception\LocalizedException(
+ __('File directory \'%1\' is not writable.', $destinationPath)
+ );
+ }
+ return $this->fileUploader;
+ }
+
+ /**
+ * Get all allowed extensions
+ *
+ * @return array
+ */
+ protected function getAllowedExtensions()
+ {
+ $result = [];
+ foreach (array_keys($this->fileHelper->getAllMineTypes()) as $option) {
+ $result[] = substr($option, 1);
+ }
+ return $result;
+ }
+}
diff --git a/app/code/Magento/DownloadableImportExport/LICENSE.txt b/app/code/Magento/DownloadableImportExport/LICENSE.txt
new file mode 100644
index 0000000000000..49525fd99da9c
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/LICENSE.txt
@@ -0,0 +1,48 @@
+
+Open Software License ("OSL") v. 3.0
+
+This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work:
+
+Licensed under the Open Software License version 3.0
+
+ 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
+
+ 1. to reproduce the Original Work in copies, either alone or as part of a collective work;
+
+ 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work;
+
+ 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License;
+
+ 4. to perform the Original Work publicly; and
+
+ 5. to display the Original Work publicly.
+
+ 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
+
+ 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work.
+
+ 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license.
+
+ 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c).
+
+ 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+
+ 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer.
+
+ 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation.
+
+ 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c).
+
+ 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+
+ 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License.
+
+ 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+
+ 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+
+ 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+ 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+
+ 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process.
\ No newline at end of file
diff --git a/app/code/Magento/DownloadableImportExport/LICENSE_AFL.txt b/app/code/Magento/DownloadableImportExport/LICENSE_AFL.txt
new file mode 100644
index 0000000000000..87943b95d43a5
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/LICENSE_AFL.txt
@@ -0,0 +1,48 @@
+
+Academic Free License ("AFL") v. 3.0
+
+This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work:
+
+Licensed under the Academic Free License version 3.0
+
+ 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following:
+
+ 1. to reproduce the Original Work in copies, either alone or as part of a collective work;
+
+ 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work;
+
+ 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License;
+
+ 4. to perform the Original Work publicly; and
+
+ 5. to display the Original Work publicly.
+
+ 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works.
+
+ 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work.
+
+ 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license.
+
+ 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c).
+
+ 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work.
+
+ 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer.
+
+ 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation.
+
+ 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c).
+
+ 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware.
+
+ 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License.
+
+ 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License.
+
+ 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable.
+
+ 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+ 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You.
+
+ 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process.
\ No newline at end of file
diff --git a/app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php b/app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php
new file mode 100644
index 0000000000000..f8132f26e1e96
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/Model/Import/Product/Type/Downloadable.php
@@ -0,0 +1,856 @@
+ 'Options for downloadable products not found',
+ self::ERROR_GROUP_TITLE_NOT_FOUND => 'Group titles not found for downloadable products',
+ self::ERROR_OPTION_NO_TITLE => 'Option no title',
+ self::ERROR_MOVE_FILE => 'Error move file',
+ self::ERROR_COLS_IS_EMPTY => 'Missing sample and links data for the downloadable product'
+ ];
+
+ /**
+ * Entity model parameters.
+ *
+ * @var array
+ */
+ protected $parameters = [];
+
+ /**
+ * Ids products
+ *
+ * @var array
+ */
+ protected $productIds = [];
+
+ /**
+ * Array of cached options.
+ *
+ * @var array
+ */
+ protected $cachedOptions = [
+ 'link' => [],
+ 'sample' => []
+ ];
+
+ /**
+ * Instance of empty sample
+ *
+ * @var array
+ */
+ protected $dataSample = [
+ 'sample_id' => null,
+ 'product_id' => null,
+ 'sample_url' => null,
+ 'sample_file' => null,
+ 'sample_type' => null,
+ 'sort_order' => self::DEFAULT_SORT_ORDER
+ ];
+
+ /**
+ * Instance of empty sample title
+ *
+ * @var array
+ */
+ protected $dataSampleTitle = [
+ 'sample_id' => null,
+ 'store_id' => Store::DEFAULT_STORE_ID,
+ 'title' => null
+ ];
+
+ /**
+ * Instance of empty link
+ *
+ * @var array
+ */
+ protected $dataLink = [
+ 'link_id' => null,
+ 'product_id' => null,
+ 'sort_order' => self::DEFAULT_SORT_ORDER,
+ 'number_of_downloads' => self::DEFAULT_NUMBER_OF_DOWNLOADS,
+ 'is_shareable' => self::DEFAULT_IS_SHAREABLE,
+ 'link_url' => null,
+ 'link_file' => null,
+ 'link_type' => null,
+ 'sample_url' => null,
+ 'sample_file' => null,
+ 'sample_type' => null
+ ];
+
+ /**
+ * Instance of empty link title
+ *
+ * @var array
+ */
+ protected $dataLinkTitle = [
+ 'link_id' => null,
+ 'store_id' => Store::DEFAULT_STORE_ID,
+ 'title' => null
+ ];
+
+ /**
+ * Instance of empty link price
+ *
+ * @var array
+ */
+ protected $dataLinkPrice = [
+ 'price_id' => null,
+ 'link_id' => null,
+ 'website_id' => self::DEFAULT_WEBSITE_ID,
+ 'price' => null
+ ];
+
+ /**
+ * Option link mapping.
+ *
+ * @var array
+ */
+ protected $optionLinkMapping = [
+ 'sortorder' => 'sort_order',
+ 'downloads' => 'number_of_downloads',
+ 'shareable' => 'is_shareable',
+ 'url' => 'link_url',
+ 'file' => 'link_file',
+ ];
+
+ /**
+ * Option sample mapping.
+ *
+ * @var array
+ */
+ protected $optionSampleMapping = [
+ 'sortorder' => 'sort_order',
+ 'url' => 'sample_url',
+ 'file' => 'sample_file',
+ ];
+
+ /**
+ * Num row parsing file
+ */
+ protected $rowNum;
+
+ /**
+ * @var \Magento\DownloadableImportExport\Helper\Uploader
+ */
+ protected $uploaderHelper;
+
+ /**
+ * @var \Magento\DownloadableImportExport\Helper\Data
+ */
+ protected $downloadableHelper;
+
+ /**
+ * Constructor
+ *
+ * @param \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory $attrSetColFac
+ * @param \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory $prodAttrColFac
+ * @param \Magento\Framework\App\Resource $resource
+ * @param array $params
+ * @param \Magento\DownloadableImportExport\Helper\Uploader $uploaderHelper
+ * @param \Magento\DownloadableImportExport\Helper\Data $downloadableHelper
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function __construct(
+ \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory $attrSetColFac,
+ \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory $prodAttrColFac,
+ \Magento\Framework\App\Resource $resource,
+ array $params,
+ \Magento\DownloadableImportExport\Helper\Uploader $uploaderHelper,
+ \Magento\DownloadableImportExport\Helper\Data $downloadableHelper
+ ) {
+ parent::__construct($attrSetColFac, $prodAttrColFac, $resource, $params);
+ $this->parameters = $this->_entityModel->getParameters();
+ $this->_resource = $resource;
+ $this->connection = $resource->getConnection('write');
+ $this->uploaderHelper = $uploaderHelper;
+ $this->downloadableHelper = $downloadableHelper;
+ }
+
+ /**
+ * Save product type specific data.
+ *
+ * @return \Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType
+ */
+ public function saveData()
+ {
+ $newSku = $this->_entityModel->getNewSku();
+ while ($bunch = $this->_entityModel->getNextBunch()) {
+ foreach ($bunch as $rowNum => $rowData) {
+ if (!$this->_entityModel->isRowAllowedToImport($rowData, $rowNum)) {
+ continue;
+ }
+ $productData = $newSku[$rowData[\Magento\CatalogImportExport\Model\Import\Product::COL_SKU]];
+ if ($this->_type != $productData['type_id']) {
+ continue;
+ }
+ $this->parseOptions($rowData, $productData['entity_id']);
+ }
+ if (!empty($this->cachedOptions['sample']) || !empty($this->cachedOptions['link'])) {
+ $this->saveOptions();
+ $this->clear();
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Validate row attributes. Pass VALID row data ONLY as argument.
+ *
+ * @param array $rowData
+ * @param int $rowNum
+ * @param bool $isNewProduct Optional
+ *
+ * @return bool
+ */
+ public function isRowValid(array $rowData, $rowNum, $isNewProduct = true)
+ {
+ $this->rowNum = $rowNum;
+ $error = false;
+ if (!$this->downloadableHelper->isRowDownloadableNoValid($rowData)) {
+ $this->_entityModel->addRowError(self::ERROR_OPTIONS_NOT_FOUND, $this->rowNum);
+ $error = true;
+ }
+ if ($this->downloadableHelper->isRowDownloadableEmptyOptions($rowData)) {
+ $this->_entityModel->addRowError(self::ERROR_COLS_IS_EMPTY, $this->rowNum);
+ $error = true;
+ }
+ if ($this->isRowValidSample($rowData) || $this->isRowValidLink($rowData)) {
+ $error = true;
+ }
+ return !$error;
+ }
+
+ /**
+ * Validation sample options
+ *
+ * @param array $rowData
+ * @return bool
+ */
+ protected function isRowValidSample(array $rowData)
+ {
+ $result = false;
+ if (isset($rowData[self::COL_DOWNLOADABLE_SAMPLES])
+ && $rowData[self::COL_DOWNLOADABLE_SAMPLES] != ''
+ && $this->sampleGroupTitle($rowData) == '') {
+ $this->_entityModel->addRowError(self::ERROR_GROUP_TITLE_NOT_FOUND, $this->rowNum);
+ $result = true;
+ }
+ if (isset($rowData[self::COL_DOWNLOADABLE_SAMPLES])
+ && $rowData[self::COL_DOWNLOADABLE_SAMPLES] != '') {
+ $result = $this->isTitle($this->prepareSampleData($rowData[self::COL_DOWNLOADABLE_SAMPLES]));
+ }
+ return $result;
+ }
+
+ /**
+ * Validation links option
+ *
+ * @param array $rowData
+ * @return bool
+ */
+ protected function isRowValidLink(array $rowData)
+ {
+ $result = false;
+ if (isset($rowData[self::COL_DOWNLOADABLE_LINKS]) &&
+ $rowData[self::COL_DOWNLOADABLE_LINKS] != '' &&
+ $this->linksAdditionalAttributes($rowData, 'group_title', self::DEFAULT_GROUP_TITLE) == ''
+ ) {
+ $this->_entityModel->addRowError(self::ERROR_GROUP_TITLE_NOT_FOUND, $this->rowNum);
+ $result = true;
+ }
+ if (isset($rowData[self::COL_DOWNLOADABLE_LINKS]) &&
+ $rowData[self::COL_DOWNLOADABLE_LINKS] != ''
+ ) {
+ $result = $this->isTitle($this->prepareLinkData($rowData[self::COL_DOWNLOADABLE_LINKS]));
+ }
+ return $result;
+ }
+
+ /**
+ * Check isset title for all options
+ *
+ * @param array $options
+ * @return bool
+ */
+ protected function isTitle(array $options)
+ {
+ $result = false;
+ foreach ($options as $option) {
+ if (!array_key_exists('title', $option)) {
+ $this->_entityModel->addRowError(self::ERROR_OPTION_NO_TITLE, $this->rowNum);
+ $result = true;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Prepare attributes with default value for save.
+ *
+ * @param array $rowData
+ * @param bool $withDefaultValue
+ * @return array
+ */
+ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDefaultValue = true)
+ {
+ $resultAttrs = parent::prepareAttributesWithDefaultValueForSave($rowData, $withDefaultValue);
+ $resultAttrs = array_merge($resultAttrs, $this->addAdditionalAttributes($rowData));
+ return $resultAttrs;
+ }
+
+ /**
+ * Get additional attributes for dowloadable product.
+ *
+ * @param array $rowData
+ * @return array
+ */
+ protected function addAdditionalAttributes(array $rowData)
+ {
+ return [
+ 'samples_title' => $this->sampleGroupTitle($rowData),
+ 'links_title' => $this->linksAdditionalAttributes($rowData, 'group_title', self::DEFAULT_GROUP_TITLE),
+ 'links_purchased_separately' => $this->linksAdditionalAttributes(
+ $rowData,
+ 'purchased_separately',
+ self::DEFAULT_PURCHASED_SEPARATELY
+ )
+ ];
+ }
+
+ /**
+ * Get additional attributes for links
+ *
+ * @param array $rowData
+ * @param string $attribute
+ * @param mixed $defaultValue
+ * @return string
+ */
+ protected function linksAdditionalAttributes(array $rowData, $attribute, $defaultValue)
+ {
+ $result = $defaultValue;
+ if (isset($rowData[self::COL_DOWNLOADABLE_LINKS])) {
+ $options = explode(
+ \Magento\CatalogImportExport\Model\Import\Product::PSEUDO_MULTI_LINE_SEPARATOR,
+ $rowData[self::COL_DOWNLOADABLE_LINKS]
+ );
+ foreach ($options as $option) {
+ $arr = $this->parseLinkOption(explode($this->_entityModel->getMultipleValueSeparator(), $option));
+ if (isset($arr[$attribute])) {
+ $result = $arr[$attribute];
+ break;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Get group title for sample
+ *
+ * @param array $rowData
+ * @return string
+ */
+ protected function sampleGroupTitle(array $rowData)
+ {
+ $result = '';
+ if (isset($rowData[self::COL_DOWNLOADABLE_SAMPLES])) {
+ $options = explode(
+ \Magento\CatalogImportExport\Model\Import\Product::PSEUDO_MULTI_LINE_SEPARATOR,
+ $rowData[self::COL_DOWNLOADABLE_SAMPLES]
+ );
+ foreach ($options as $option) {
+ $arr = $this->parseSampleOption(explode($this->_entityModel->getMultipleValueSeparator(), $option));
+ if (isset($arr['group_title'])) {
+ $result = $arr['group_title'];
+ break;
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Parse options for products
+ *
+ * @param array $rowData
+ * @param int $entityId
+ * @return $this
+ */
+ protected function parseOptions(array $rowData, $entityId)
+ {
+ $this->productIds[] = $entityId;
+ if (isset($rowData[self::COL_DOWNLOADABLE_LINKS])) {
+ $this->cachedOptions['link'] = array_merge(
+ $this->cachedOptions['link'],
+ $this->prepareLinkData($rowData[self::COL_DOWNLOADABLE_LINKS], $entityId)
+ );
+ }
+ if (isset($rowData[self::COL_DOWNLOADABLE_SAMPLES])) {
+ $this->cachedOptions['sample'] = array_merge(
+ $this->prepareSampleData($rowData[self::COL_DOWNLOADABLE_SAMPLES], $entityId),
+ $this->cachedOptions['sample']
+ );
+ }
+ return $this;
+ }
+
+ /**
+ * Get fill data options with key sample
+ *
+ * @param array $base
+ * @param array $options
+ * @return array
+ */
+ protected function fillDataSample(array $base, array $options)
+ {
+ $result = [];
+ $existingOptions = $this->connection->fetchAll(
+ $this->connection->select()->from(
+ $this->_resource->getTableName('downloadable_sample')
+ )->where(
+ 'product_id in (?)',
+ $this->productIds
+ )
+ );
+ foreach ($options as $option) {
+ $isExist = false;
+ foreach ($existingOptions as $existingOption) {
+ if ($option['sample_url'] == $existingOption['sample_url']
+ && $option['sample_file'] == $existingOption['sample_file']
+ && $option['sample_type'] == $existingOption['sample_type']
+ && $option['product_id'] == $existingOption['product_id']) {
+ $result[] = array_replace($this->dataSampleTitle, $option, $existingOption);
+ $isExist = true;
+ }
+ }
+ if (!$isExist) {
+ $result[] = array_replace($base, $option);
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Get fill data options with key link
+ *
+ * @param array $base
+ * @param array $options
+ * @return array
+ */
+ protected function fillDataLink(array $base, array $options)
+ {
+ $result = [];
+ $existingOptions = $this->connection->fetchAll(
+ $this->connection->select()->from(
+ $this->_resource->getTableName('downloadable_link')
+ )->where(
+ 'product_id in (?)',
+ $this->productIds
+ )
+ );
+ foreach ($options as $option) {
+ $existOption = $this->downloadableHelper->fillExistOptions($base, $option, $existingOptions);
+ if (empty($existOption)) {
+ $result[] = array_replace($base, $option);
+ } else {
+ $result[] = $existOption;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Get fill data options with key link
+ *
+ * @param array $options
+ * @return array
+ */
+ protected function fillDataTitleLink(array $options)
+ {
+ $result = [];
+ $existingOptions = $this->connection->fetchAll(
+ $this->connection->select()->from(
+ ['dl' => $this->_resource->getTableName('downloadable_link')],
+ [
+ 'link_id',
+ 'product_id',
+ 'sort_order',
+ 'number_of_downloads',
+ 'is_shareable',
+ 'link_url',
+ 'link_file',
+ 'link_type',
+ 'sample_url',
+ 'sample_file',
+ 'sample_type'
+ ]
+ )->joinLeft(
+ ['dlp' => $this->_resource->getTableName('downloadable_link_price')],
+ 'dl.link_id = dlp.link_id AND dlp.website_id=' . self::DEFAULT_WEBSITE_ID,
+ ['price_id', 'website_id']
+ )->where(
+ 'product_id in (?)',
+ $this->productIds
+ )
+ );
+ foreach ($options as $option) {
+ $existOption = $this->downloadableHelper->fillExistOptions($this->dataLinkTitle, $option, $existingOptions);
+ if (!empty($existOption)) {
+ $result['title'][] = $existOption;
+ }
+ $existOption = $this->downloadableHelper->fillExistOptions($this->dataLinkPrice, $option, $existingOptions);
+ if (!empty($existOption)) {
+ $result['price'][] = $existOption;
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Upload all sample files
+ *
+ * @param array $options
+ * @return array
+ */
+ protected function uploadSampleFiles(array $options)
+ {
+ $result = [];
+ foreach ($options as $option) {
+ if ($option['sample_file'] !== null) {
+ $option['sample_file'] = $this->uploadDownloadableFiles($option['sample_file'], 'samples', true);
+ }
+ $result[] = $option;
+ }
+ return $result;
+ }
+
+ /**
+ * Upload all link files
+ *
+ * @param array $options
+ * @return array
+ */
+ protected function uploadLinkFiles(array $options)
+ {
+ $result = [];
+ foreach ($options as $option) {
+ if ($option['sample_file'] !== null) {
+ $option['sample_file'] = $this->uploadDownloadableFiles($option['sample_file'], 'link_samples', true);
+ }
+ if ($option['link_file'] !== null) {
+ $option['link_file'] = $this->uploadDownloadableFiles($option['link_file'], 'links', true);
+ }
+ $result[] = $option;
+ }
+ return $result;
+ }
+
+ /**
+ * Save options in base
+ *
+ * @return \Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType
+ */
+ protected function saveOptions()
+ {
+ $options = $this->cachedOptions;
+ if (!empty($options['sample'])) {
+ $this->saveSampleOptions();
+ }
+ if (!empty($options['link'])) {
+ $this->saveLinkOptions();
+ }
+ return $this;
+ }
+
+ /**
+ * Save sample options
+ *
+ * @return $this
+ */
+ protected function saveSampleOptions()
+ {
+ $options['sample'] = $this->uploadSampleFiles($this->cachedOptions['sample']);
+ $dataSample = $this->fillDataSample($this->dataSample, $options['sample']);
+ $this->connection->insertOnDuplicate(
+ $this->_resource->getTableName('downloadable_sample'),
+ $this->downloadableHelper->prepareDataForSave($this->dataSample, $dataSample)
+ );
+ $titleSample = $this->fillDataSample($this->dataSampleTitle, $options['sample']);
+ $this->connection->insertOnDuplicate(
+ $this->_resource->getTableName('downloadable_sample_title'),
+ $this->downloadableHelper->prepareDataForSave($this->dataSampleTitle, $titleSample)
+ );
+ return $this;
+ }
+
+ /**
+ * Save link options
+ *
+ * @return $this
+ */
+ protected function saveLinkOptions()
+ {
+ $options['link'] = $this->uploadLinkFiles($this->cachedOptions['link']);
+ $dataLink = $this->fillDataLink($this->dataLink, $options['link']);
+ $this->connection->insertOnDuplicate(
+ $this->_resource->getTableName('downloadable_link'),
+ $this->downloadableHelper->prepareDataForSave($this->dataLink, $dataLink)
+ );
+ $dataLink = $this->fillDataTitleLink($options['link']);
+ $this->connection->insertOnDuplicate(
+ $this->_resource->getTableName('downloadable_link_title'),
+ $this->downloadableHelper->prepareDataForSave($this->dataLinkTitle, $dataLink['title'])
+ );
+ if (count($dataLink['price'])) {
+ $this->connection->insertOnDuplicate(
+ $this->_resource->getTableName('downloadable_link_price'),
+ $this->downloadableHelper->prepareDataForSave($this->dataLinkPrice, $dataLink['price'])
+ );
+ }
+ return $this;
+ }
+
+ /**
+ * Prepare string to array data sample
+ *
+ * @param string $rowCol
+ * @param int $entityId
+ * @return array
+ */
+ protected function prepareSampleData($rowCol, $entityId = null)
+ {
+ $result = [];
+ $options = explode(
+ \Magento\CatalogImportExport\Model\Import\Product::PSEUDO_MULTI_LINE_SEPARATOR,
+ $rowCol
+ );
+ foreach ($options as $option) {
+ $result[] = array_merge(
+ $this->dataSample,
+ ['product_id' => $entityId],
+ $this->parseSampleOption(explode($this->_entityModel->getMultipleValueSeparator(), $option))
+ );
+ }
+ return $result;
+ }
+
+ /**
+ * Prepare string to array data link
+ *
+ * @param string $rowCol
+ * @param string $entityId
+ * @return array
+ */
+ protected function prepareLinkData($rowCol, $entityId = null)
+ {
+ $result = [];
+ $options = explode(
+ \Magento\CatalogImportExport\Model\Import\Product::PSEUDO_MULTI_LINE_SEPARATOR,
+ $rowCol
+ );
+ foreach ($options as $option) {
+ $result[] = array_merge(
+ $this->dataLink,
+ ['product_id' => $entityId],
+ $this->parseLinkOption(explode($this->_entityModel->getMultipleValueSeparator(), $option))
+ );
+ }
+ return $result;
+ }
+
+ /**
+ * Parse the link option.
+ *
+ * @param array $values
+ * @return array
+ */
+ protected function parseLinkOption(array $values)
+ {
+ $option = [];
+ foreach ($values as $keyValue) {
+ $keyValue = trim($keyValue);
+ if ($pos = strpos($keyValue, self::PAIR_VALUE_SEPARATOR)) {
+ $key = substr($keyValue, 0, $pos);
+ $value = substr($keyValue, $pos + 1);
+ if ($key == 'sample') {
+ $option['sample_type'] = $this->downloadableHelper->getTypeByValue($value);
+ $option['sample_' . $option['sample_type']] = $value;
+ }
+ if ($key == self::URL_OPTION_VALUE || $key == self::FILE_OPTION_VALUE) {
+ $option['link_type'] = $key;
+ }
+ if ($key == 'downloads' && $value == 'unlimited') {
+ $value = 0;
+ }
+ if (isset($this->optionLinkMapping[$key])) {
+ $key = $this->optionLinkMapping[$key];
+ }
+ $option[$key] = $value;
+ }
+ }
+ return $option;
+ }
+
+ /**
+ * Parse the sample option.
+ *
+ * @param array $values
+ * @return array
+ */
+ protected function parseSampleOption($values)
+ {
+ $option = [];
+ foreach ($values as $keyValue) {
+ $keyValue = trim($keyValue);
+ if ($pos = strpos($keyValue, self::PAIR_VALUE_SEPARATOR)) {
+ $key = substr($keyValue, 0, $pos);
+ $value = substr($keyValue, $pos + 1);
+ if ($key == self::URL_OPTION_VALUE || $key == self::FILE_OPTION_VALUE) {
+ $option['sample_type'] = $key;
+ }
+ if (isset($this->optionSampleMapping[$key])) {
+ $key = $this->optionSampleMapping[$key];
+ }
+ $option[$key] = $value;
+ }
+ }
+ return $option;
+ }
+
+ /**
+ * Uploading files into the "downloadable/files" media folder.
+ * Return a new file name if the same file is already exists.
+ *
+ * @param string $fileName
+ * @param string $type
+ * @param bool $renameFileOff
+ * @return string
+ */
+ protected function uploadDownloadableFiles($fileName, $type = 'links', $renameFileOff = false)
+ {
+ try {
+ $res = $this->uploaderHelper->getUploader($type, $this->parameters)->move($fileName, $renameFileOff);
+ return $res['file'];
+ } catch (\Exception $e) {
+ $this->_entityModel->addRowError(self::ERROR_MOVE_FILE, $this->rowNum);
+ return '';
+ }
+ }
+
+ /**
+ * Clear cached values between bunches
+ *
+ * @return \Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType
+ */
+ protected function clear()
+ {
+ $this->cachedOptions = [
+ 'link' => [],
+ 'sample' => []
+ ];
+ $this->productIds = [];
+ return $this;
+ }
+}
diff --git a/app/code/Magento/DownloadableImportExport/README.md b/app/code/Magento/DownloadableImportExport/README.md
new file mode 100644
index 0000000000000..0f9c66837519f
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/README.md
@@ -0,0 +1 @@
+The Magento_DownloadableImportExport module handles the import and export of the downloadable products.
diff --git a/app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php b/app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php
new file mode 100644
index 0000000000000..93a353f68089b
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php
@@ -0,0 +1,858 @@
+connectionMock = $this->getMock(
+ 'Magento\Framework\DB\Adapter\Pdo\Mysql',
+ ['select', 'fetchAll', 'fetchPairs', 'joinLeft', 'insertOnDuplicate', 'delete', 'quoteInto', 'fetchAssoc'],
+ [],
+ '',
+ false
+ );
+ $this->select = $this->getMock('Magento\Framework\DB\Select', [], [], '', false);
+ $this->select->expects($this->any())->method('from')->will($this->returnSelf());
+ $this->select->expects($this->any())->method('where')->will($this->returnSelf());
+ $this->select->expects($this->any())->method('joinLeft')->will($this->returnSelf());
+ $adapter = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
+ $adapter->expects($this->any())->method('quoteInto')->will($this->returnValue('query'));
+ $this->select->expects($this->any())->method('getAdapter')->willReturn($adapter);
+ $this->connectionMock->expects($this->any())->method('select')->will($this->returnValue($this->select));
+
+ $this->connectionMock->expects($this->any())->method('insertOnDuplicate')->willReturnSelf();
+ $this->connectionMock->expects($this->any())->method('delete')->willReturnSelf();
+ $this->connectionMock->expects($this->any())->method('quoteInto')->willReturn('');
+
+ //constructor arguments:
+ // 1. $attrSetColFac
+ $this->attrSetColFacMock = $this->getMock(
+ 'Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+ $this->attrSetColMock = $this->getMock(
+ 'Magento\Eav\Model\Resource\Entity\Attribute\Set\Collection',
+ ['setEntityTypeFilter'],
+ [],
+ '',
+ false
+ );
+ $this->attrSetColMock
+ ->expects($this->any())
+ ->method('setEntityTypeFilter')
+ ->will($this->returnValue([]));
+
+ // 2. $prodAttrColFac
+ $this->prodAttrColFacMock = $this->getMock(
+ 'Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+
+ $attrCollection = $this->getMock(
+ '\Magento\Catalog\Model\Resource\Product\Attribute\Collection',
+ [],
+ [],
+ '',
+ false
+ );
+
+ $attrCollection->expects($this->any())->method('addFieldToFilter')->willReturn([]);
+ $this->prodAttrColFacMock->expects($this->any())->method('create')->will($this->returnValue($attrCollection));
+
+ // 3. $resource
+ $this->resourceMock = $this->getMock(
+ 'Magento\Framework\App\Resource',
+ ['getConnection', 'getTableName'],
+ [],
+ '',
+ false
+ );
+ $this->resourceMock->expects($this->any())->method('getConnection')->will(
+ $this->returnValue($this->connectionMock)
+ );
+ $this->resourceMock->expects($this->any())->method('getTableName')->will(
+ $this->returnValue('tableName')
+ );
+
+ // 4. $params
+ $this->entityModelMock = $this->getMock(
+ '\Magento\CatalogImportExport\Model\Import\Product',
+ [
+ 'addMessageTemplate',
+ 'getEntityTypeId',
+ 'getBehavior',
+ 'getNewSku',
+ 'getNextBunch',
+ 'isRowAllowedToImport',
+ 'getParameters',
+ 'addRowError'
+ ],
+ [],
+ '',
+ false
+ );
+
+ $this->entityModelMock->expects($this->any())->method('addMessageTemplate')->will($this->returnSelf());
+ $this->entityModelMock->expects($this->any())->method('getEntityTypeId')->will($this->returnValue(5));
+ $this->entityModelMock->expects($this->any())->method('getParameters')->will($this->returnValue([]));
+ $this->paramsArray = [
+ $this->entityModelMock,
+ 'downloadable'
+ ];
+
+ $this->uploaderMock = $this->getMock(
+ '\Magento\CatalogImportExport\Model\Import\Uploader',
+ ['move'],
+ [],
+ '',
+ false
+ );
+
+ // 6. $filesystem
+ $this->directoryWriteMock = $this->getMock('Magento\Framework\Filesystem\Directory\Write', [], [], '', false);
+
+ // 7. $fileHelper
+ $this->uploaderHelper = $this->getMock(
+ '\Magento\DownloadableImportExport\Helper\Uploader',
+ ['getUploader'],
+ [],
+ '',
+ false
+ );
+ $this->uploaderHelper->expects($this->any())->method('getUploader')->willReturn($this->uploaderMock);
+ $this->downloadableHelper = $this->getMock(
+ '\Magento\DownloadableImportExport\Helper\Data',
+ ['prepareDataForSave'],
+ [],
+ '',
+ false
+ );
+ $this->downloadableHelper->expects($this->any())->method('prepareDataForSave')->willReturn([]);
+ }
+
+ /**
+ * @dataProvider dataForSave
+ */
+ public function testSaveDataAppend($newSku, $bunch, $allowImport, $fetchResult)
+ {
+ $this->entityModelMock->expects($this->once())->method('getNewSku')->will($this->returnValue($newSku));
+ $this->entityModelMock->expects($this->at(1))->method('getNextBunch')->will($this->returnValue($bunch));
+ $this->entityModelMock->expects($this->at(2))->method('getNextBunch')->will($this->returnValue(null));
+ $this->entityModelMock->expects($this->any())->method('isRowAllowedToImport')->willReturn($allowImport);
+
+ $this->uploaderMock->expects($this->any())->method('setTmpDir')->willReturn(true);
+ $this->uploaderMock->expects($this->any())->method('setDestDir')->with('pub/media/')->willReturn(true);
+
+ $this->connectionMock->expects($this->any())->method('fetchAll')->with(
+ $this->select
+ )->will($this->onConsecutiveCalls(
+ [
+ [
+ 'attribute_set_name' => '1',
+ 'attribute_id' => '1',
+ ],
+ [
+ 'attribute_set_name' => '2',
+ 'attribute_id' => '2',
+ ],
+ ],
+ $fetchResult['sample'],
+ $fetchResult['sample'],
+ $fetchResult['link'],
+ $fetchResult['link']
+ ));
+
+ $downloadableModelMock = $this->objectManagerHelper->getObject(
+ '\Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable',
+ [
+ 'attrSetColFac' => $this->attrSetColFacMock,
+ 'prodAttrColFac' => $this->prodAttrColFacMock,
+ 'resource' => $this->resourceMock,
+ 'params' => $this->paramsArray,
+ 'uploaderHelper' => $this->uploaderHelper,
+ 'downloadableHelper' => $this->downloadableHelper
+ ]
+ );
+
+ $downloadableModelMock->saveData();
+ }
+
+ /**
+ * Data for method testSaveDataAppend
+ *
+ * @return array
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
+ public function dataForSave()
+ {
+ return [
+ [
+ 'newSku' => [
+ 'downloadablesku1' => [
+ 'entity_id' => '25',
+ 'type_id' => 'downloadable',
+ 'attr_set_id' => '4',
+ 'attr_set_code' => 'Default',
+ ],
+ ],
+ 'bunch' => [
+ [
+ 'sku' => 'downloadablesku1',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4'
+ .',sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10,'
+ .' downloads=unlimited, file=media/file_link.mp4,sortorder=1|group_title=Group Title,'
+ .'title=Title 2, price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ ],
+ 'allowImport' => true,
+ [
+ 'sample' => [
+ [
+ 'sample_id' => '65',
+ 'product_id' => '25',
+ 'sample_url' => null,
+ 'sample_file' => '',
+ 'sample_type' => 'file',
+ 'sort_order' => '1',
+ ],
+ [
+ 'sample_id' => '66',
+ 'product_id' => '25',
+ 'sample_url' => 'media/file2.mp4',
+ 'sample_file' => null,
+ 'sample_type' => 'url',
+ 'sort_order' => '0',
+ ]
+ ],
+ 'link' => [
+ [
+ 'link_id' => '65',
+ 'product_id' => '25',
+ 'sort_order' => '1',
+ 'number_of_downloads' => '0',
+ 'is_shareable' => '2',
+ 'link_url' => null,
+ 'link_file' => '',
+ 'link_type' => 'file',
+ 'sample_url' => null,
+ 'sample_file' => null,
+ 'sample_type' => null,
+ ],
+ [
+ 'link_id' => '66',
+ 'product_id' => '25',
+ 'sort_order' => '0',
+ 'number_of_downloads' => '0',
+ 'is_shareable' => '2',
+ 'link_url' => 'media/file2.mp4',
+ 'link_file' => null,
+ 'link_type' => 'url',
+ 'sample_url' => null,
+ 'sample_file' => null,
+ 'sample_type' => null,
+ ]
+ ]
+ ]
+ ],
+ [
+ 'newSku' => [
+ 'downloadablesku2' => [
+ 'entity_id' => '25',
+ 'type_id' => 'downloadable',
+ 'attr_set_id' => '4',
+ 'attr_set_code' => 'Default',
+ ],
+ ],
+ 'bunch' => [
+ [
+ 'sku' => 'downloadablesku2',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4'
+ .',sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10,'
+ .' downloads=unlimited, file=media/file_link.mp4,sortorder=1|group_title=Group Title, '
+ .'title=Title 2, price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ ],
+ 'allowImport' => false,
+ ['sample' => [], 'link' => []]
+ ],
+ [
+ 'newSku' => [
+ 'downloadablesku3' => [
+ 'entity_id' => '25',
+ 'type_id' => 'simple',
+ 'attr_set_id' => '4',
+ 'attr_set_code' => 'Default',
+ ],
+ ],
+ 'bunch' => [
+ [
+ 'sku' => 'downloadablesku3',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4,'
+ .'sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10,'
+ .' downloads=unlimited, file=media/file_link.mp4,sortorder=1|group_title=Group Title,'
+ .' title=Title 2, price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ ],
+ 'allowImport' => true,
+ ['sample' => [], 'link' => []]
+ ],
+ [
+ 'newSku' => [
+ 'downloadablesku4' => [
+ 'entity_id' => '25',
+ 'type_id' => 'downloadable',
+ 'attr_set_id' => '4',
+ 'attr_set_code' => 'Default',
+ ],
+ ],
+ 'bunch' => [
+ [
+ 'sku' => 'downloadablesku4',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4,'
+ .'sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10,'
+ .' downloads=unlimited, file=media/file_link.mp4,sortorder=1|group_title=Group Title,'
+ .' title=Title 2, price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ ],
+ 'allowImport' => true,
+ [
+ 'sample' => [
+ [
+ 'sample_id' => '65',
+ 'product_id' => '25',
+ 'sample_url' => null,
+ 'sample_file' => '',
+ 'sample_type' => 'file',
+ 'sort_order' => '1',
+ ],
+ [
+ 'sample_id' => '66',
+ 'product_id' => '25',
+ 'sample_url' => 'media/some_another_file.mp4',
+ 'sample_file' => null,
+ 'sample_type' => 'url',
+ 'sort_order' => '0',
+ ]
+ ],
+ 'link' => [
+ [
+ 'link_id' => '65',
+ 'product_id' => '25',
+ 'sort_order' => '1',
+ 'number_of_downloads' => '0',
+ 'is_shareable' => '2',
+ 'link_url' => null,
+ 'link_file' => '',
+ 'link_type' => 'file',
+ 'sample_url' => null,
+ 'sample_file' => null,
+ 'sample_type' => null,
+ ],
+ [
+ 'link_id' => '66',
+ 'product_id' => '25',
+ 'sort_order' => '0',
+ 'number_of_downloads' => '0',
+ 'is_shareable' => '2',
+ 'link_url' => 'media/some_another_file.mp4',
+ 'link_file' => null,
+ 'link_type' => 'url',
+ 'sample_url' => null,
+ 'sample_file' => null,
+ 'sample_type' => null,
+ ]
+ ]
+ ]
+ ],
+ [
+ 'newSku' => [
+ 'downloadablesku5' => [
+ 'entity_id' => '25',
+ 'type_id' => 'downloadable',
+ 'attr_set_id' => '4',
+ 'attr_set_code' => 'Default',
+ ],
+ ],
+ 'bunch' => [
+ [
+ 'sku' => 'downloadablesku5',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4,'
+ .'sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title, title=Title 2, price=10, downloads=unlimited,'
+ .' url=http://www.sample.com/pic.jpg,sortorder=0,sample=http://www.sample.com/pic.jpg,'
+ .'purchased_separately=1,shareable=1|group_title=Group Title, title=Title 2, price=10, '
+ .'downloads=unlimited, url=media/file2.mp4,sortorder=0,sample=media/file2mp4',
+ ],
+ ],
+ 'allowImport' => true,
+ [
+ 'sample' => [
+ [
+ 'sample_id' => '65',
+ 'product_id' => '25',
+ 'sample_url' => null,
+ 'sample_file' => '',
+ 'sample_type' => 'file',
+ 'sort_order' => '1',
+ ],
+ [
+ 'sample_id' => '66',
+ 'product_id' => '25',
+ 'sample_url' => 'media/file2.mp4',
+ 'sample_file' => null,
+ 'sample_type' => 'url',
+ 'sort_order' => '0',
+ ]
+ ],
+ 'link' => [
+ [
+ 'link_id' => '65',
+ 'product_id' => '25',
+ 'sort_order' => '1',
+ 'number_of_downloads' => '0',
+ 'is_shareable' => '1',
+ 'link_url' => 'http://www.sample.com/pic.jpg',
+ 'link_file' => null,
+ 'link_type' => 'url',
+ 'sample_url' => 'http://www.sample.com/pic.jpg',
+ 'sample_file' => null,
+ 'sample_type' => 'url',
+ ],
+ [
+ 'link_id' => '66',
+ 'product_id' => '25',
+ 'sort_order' => '0',
+ 'number_of_downloads' => '0',
+ 'is_shareable' => '2',
+ 'link_url' => 'media/file2.mp4',
+ 'link_file' => null,
+ 'link_type' => 'url',
+ 'sample_url' => null,
+ 'sample_file' => 'f/i/file.png',
+ 'sample_type' => 'file',
+ ]
+ ]
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider isRowValidData
+ */
+ public function testIsRowValid(array $rowData, $rowNum, $isNewProduct = true)
+ {
+ $this->connectionMock->expects($this->any())->method('fetchAll')->with(
+ $this->select
+ )->willReturnOnConsecutiveCalls(
+ [
+ [
+ 'attribute_set_name' => '1',
+ 'attribute_id' => '1',
+ ],
+ [
+ 'attribute_set_name' => '2',
+ 'attribute_id' => '2',
+ ],
+ ]
+ );
+ $this->downloadableModelMock = $this->objectManagerHelper->getObject(
+ '\Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable',
+ [
+ 'attrSetColFac' => $this->attrSetColFacMock,
+ 'prodAttrColFac' => $this->prodAttrColFacMock,
+ 'resource' => $this->resourceMock,
+ 'params' => $this->paramsArray,
+ 'uploaderHelper' => $this->uploaderHelper,
+ 'downloadableHelper' => $this->downloadableHelper
+ ]
+ );
+ $this->downloadableModelMock->isRowValid($rowData, $rowNum, $isNewProduct);
+ }
+
+ /**
+ * Data for method testIsRowValid
+ *
+ * @return array
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
+ public function isRowValidData()
+ {
+ return [
+ [
+ [
+ 'sku' => 'downloadablesku1',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4,'
+ .'sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10, '
+ .'downloads=unlimited, file=media/file_link.mp4,sortorder=1|group_title=Group Title, '
+ .'title=Title 2, price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ 0,
+ true
+ ],
+ [
+ [
+ 'sku' => 'downloadablesku12',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 2',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4'
+ .',sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10,'
+ .' downloads=unlimited, file=media/file.mp4,sortorder=1|group_title=Group Title, title=Title 2,'
+ .' price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ 1,
+ true
+ ],
+ [
+ [
+ 'sku' => 'downloadablesku12',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 2',
+ ],
+ 2,
+ true
+ ],
+ [
+ [
+ 'sku' => 'downloadablesku12',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 2',
+ 'downloadable_samples' => 'title=Title 1, file=media/file.mp4,sortorder=1|title=Title 2,'
+ .' url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'title=Title 1, price=10, downloads=unlimited, file=media/file.mp4,'
+ .'sortorder=1|group_title=Group Title, title=Title 2, price=10, downloads=unlimited,'
+ .' url=media/file2.mp4,sortorder=0',
+ ],
+ 3,
+ true
+ ],
+ [
+ [
+ 'sku' => 'downloadablesku12',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 2',
+ 'downloadable_samples' => 'file=media/file.mp4,sortorder=1|group_title=Group Title, '
+ .'url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'title=Title 1, price=10, downloads=unlimited, file=media/file.mp4,'
+ .'sortorder=1|group_title=Group Title, title=Title 2, price=10, downloads=unlimited,'
+ .' url=media/file2.mp4,sortorder=0',
+ ],
+ 4,
+ true
+ ],
+ [ //empty group title samples
+ [
+ 'sku' => 'downloadablesku12',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 2',
+ 'downloadable_samples' => 'group_title=, title=Title 1, file=media/file.mp4,sortorder=1'
+ .'|group_title=, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10,'
+ .' downloads=unlimited, file=media/file_link.mp4,sortorder=1|group_title=Group Title,'
+ .' title=Title 2, price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ 5,
+ true
+ ],
+ [ //empty group title links
+ [
+ 'sku' => 'downloadablesku12',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 2',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4,'
+ .'sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=, title=Title 1, price=10, downloads=unlimited, '
+ .'file=media/file_link.mp4,sortorder=1|group_title=, title=Title 2, price=10, '
+ .'downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ 6,
+ true
+ ],
+ [
+ [
+ 'sku' => 'downloadablesku12',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 2',
+ 'downloadable_samples' => '',
+ 'downloadable_links' => '',
+ ],
+ 7,
+ true
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider dataForUploaderDir
+ */
+ public function testSetUploaderDirFalse($newSku, $bunch, $allowImport)
+ {
+ $this->connectionMock->expects($this->any())->method('fetchAll')->with(
+ $this->select
+ )->willReturnOnConsecutiveCalls(
+ [
+ [
+ 'attribute_set_name' => '1',
+ 'attribute_id' => '1',
+ ],
+ [
+ 'attribute_set_name' => '2',
+ 'attribute_id' => '2',
+ ],
+ ]
+ );
+ $this->downloadableModelMock = $this->objectManagerHelper->getObject(
+ '\Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable',
+ [
+ 'attrSetColFac' => $this->attrSetColFacMock,
+ 'prodAttrColFac' => $this->prodAttrColFacMock,
+ 'resource' => $this->resourceMock,
+ 'params' => $this->paramsArray,
+ 'uploaderHelper' => $this->uploaderHelper,
+ 'downloadableHelper' => $this->downloadableHelper
+ ]
+ );
+ $this->entityModelMock->expects($this->once())->method('getNewSku')->will($this->returnValue($newSku));
+ $this->entityModelMock->expects($this->at(1))->method('getNextBunch')->will($this->returnValue($bunch));
+ $this->entityModelMock->expects($this->at(2))->method('getNextBunch')->will($this->returnValue(null));
+ $this->entityModelMock->expects($this->any())->method('isRowAllowedToImport')->willReturn($allowImport);
+ $exception = new \Magento\Framework\Exception\LocalizedException(new \Magento\Framework\Phrase('Error'));
+ $this->setExpectedException('\Magento\Framework\Exception\LocalizedException');
+ $this->setExpectedException('\Exception');
+ $this->uploaderMock->expects($this->any())->method('move')->will($this->throwException($exception));
+ $this->downloadableModelMock->saveData();
+ }
+
+ /**
+ * Data for methods testSetUploaderDirFalse, testSetDestDirFalse, testDirWithoutPermissions
+ *
+ * @return array
+ */
+ public function dataForUploaderDir()
+ {
+ return [
+ [
+ 'newSku' => [
+ 'downloadablesku1' => [
+ 'entity_id' => '25',
+ 'type_id' => 'downloadable',
+ 'attr_set_id' => '4',
+ 'attr_set_code' => 'Default',
+ ],
+ ],
+ 'bunch' => [
+ [
+ 'sku' => 'downloadablesku1',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4'
+ .',sortorder=1|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10, downloads='
+ .'unlimited, file=media/file_link.mp4,sortorder=1|group_title=Group Title, title=Title 2,'
+ .' price=10, downloads=unlimited, url=media/file2.mp4,sortorder=0',
+ ],
+ ],
+ 'allowImport' => true,
+ ],
+ ];
+ }
+
+ /**
+ * Test for method prepareAttributesWithDefaultValueForSave
+ */
+ public function testPrepareAttributesWithDefaultValueForSave()
+ {
+ $rowData = [
+ '_attribute_set' => 'Default',
+ 'sku' => 'downloadablesku1',
+ 'product_type' => 'downloadable',
+ 'name' => 'Downloadable Product 1',
+ 'downloadable_samples' => 'group_title=Group Title Samples, title=Title 1, file=media/file.mp4,sortorder=1'
+ .'|group_title=Group Title, title=Title 2, url=media/file2.mp4,sortorder=0',
+ 'downloadable_links' => 'group_title=Group Title Links, title=Title 1, price=10, downloads=unlimited,'
+ .' file=media/file_link.mp4,sortorder=1|group_title=Group Title, title=Title 2, price=10, downloads'
+ .'=unlimited, url=media/file2.mp4,sortorder=0',
+ ];
+ $this->connectionMock->expects($this->any())->method('fetchAll')->with(
+ $this->select
+ )->willReturnOnConsecutiveCalls(
+ [
+ [
+ 'attribute_set_name' => '1',
+ 'attribute_id' => '1',
+ ],
+ [
+ 'attribute_set_name' => '2',
+ 'attribute_id' => '2',
+ ],
+ ]
+ );
+ $this->downloadableModelMock = $this->objectManagerHelper->getObject(
+ '\Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable',
+ [
+ 'attrSetColFac' => $this->attrSetColFacMock,
+ 'prodAttrColFac' => $this->prodAttrColFacMock,
+ 'resource' => $this->resourceMock,
+ 'params' => $this->paramsArray,
+ 'uploaderHelper' => $this->uploaderHelper,
+ 'downloadableHelper' => $this->downloadableHelper
+ ]
+ );
+ $this->setPropertyValue(
+ $this->downloadableModelMock,
+ '_attributes',
+ [
+ 'Default' => [
+ 'name' => [
+ 'id' => '69',
+ 'code' => 'name',
+ 'is_global' => '0',
+ 'is_required' => '1',
+ 'is_unique' => '0',
+ 'frontend_label' => 'Name',
+ 'is_static' => false,
+ 'apply_to' =>
+ [
+ ],
+ 'type' => 'varchar',
+ 'default_value' => null,
+ 'options' =>
+ [
+ ],
+ ],
+ 'sku' => [
+ 'id' => '70',
+ 'code' => 'sku',
+ 'is_global' => '1',
+ 'is_required' => '1',
+ 'is_unique' => '1',
+ 'frontend_label' => 'SKU',
+ 'is_static' => true,
+ 'apply_to' =>
+ [
+ ],
+ 'type' => 'varchar',
+ 'default_value' => null,
+ 'options' =>
+ [
+ ],
+ ]
+ ]
+ ]
+ );
+
+ $this->downloadableModelMock->prepareAttributesWithDefaultValueForSave($rowData);
+ }
+
+ /**
+ * @param $object
+ * @param $property
+ * @param $value
+ */
+ protected function setPropertyValue(&$object, $property, $value)
+ {
+ $reflection = new \ReflectionClass(get_class($object));
+ $reflectionProperty = $reflection->getProperty($property);
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($object, $value);
+ return $object;
+ }
+}
diff --git a/app/code/Magento/DownloadableImportExport/composer.json b/app/code/Magento/DownloadableImportExport/composer.json
new file mode 100644
index 0000000000000..6d79b90effd59
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "magento/module-downloadable-import-export",
+ "description": "N/A",
+ "require": {
+ "php": "~5.5.0|~5.6.0",
+ "magento/module-catalog": "1.0.0-beta",
+ "magento/module-import-export": "1.0.0-beta",
+ "magento/module-catalog-import-export": "1.0.0-beta",
+ "magento/module-downloadable": "1.0.0-beta",
+ "magento/module-store": "1.0.0-beta",
+ "magento/module-eav": "1.0.0-beta",
+ "magento/framework": "1.0.0-beta",
+ "magento/magento-composer-installer": "*"
+ },
+ "type": "magento2-module",
+ "version": "1.0.0-beta",
+ "license": [
+ "OSL-3.0",
+ "AFL-3.0"
+ ],
+ "extra": {
+ "map": [
+ [
+ "*",
+ "Magento/DownloadableImportExport"
+ ]
+ ]
+ }
+}
diff --git a/app/code/Magento/DownloadableImportExport/etc/import.xml b/app/code/Magento/DownloadableImportExport/etc/import.xml
new file mode 100644
index 0000000000000..fcce279dd795d
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/etc/import.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/DownloadableImportExport/etc/module.xml b/app/code/Magento/DownloadableImportExport/etc/module.xml
new file mode 100644
index 0000000000000..83e3f829921dc
--- /dev/null
+++ b/app/code/Magento/DownloadableImportExport/etc/module.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/DownloadableImportExport/i18n/en_US.csv b/app/code/Magento/DownloadableImportExport/i18n/en_US.csv
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/app/code/Magento/GroupedImportExport/Model/Export/RowCustomizer.php b/app/code/Magento/GroupedImportExport/Model/Export/RowCustomizer.php
index 0b565e2ac32c8..d47b50b8d1145 100644
--- a/app/code/Magento/GroupedImportExport/Model/Export/RowCustomizer.php
+++ b/app/code/Magento/GroupedImportExport/Model/Export/RowCustomizer.php
@@ -10,7 +10,12 @@
class RowCustomizer implements RowCustomizerInterface
{
/**
- * @inheritdoc
+ * Prepare data for export
+ *
+ * @param mixed $collection
+ * @param int $productIds
+ * @return mixed
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function prepareData($collection, $productIds)
{
@@ -18,23 +23,29 @@ public function prepareData($collection, $productIds)
}
/**
- * @inheritdoc
+ * Set headers columns
+ *
+ * @param array $columns
+ * @return mixed
*/
public function addHeaderColumns($columns)
{
$columns = array_merge(
$columns,
[
- '_associated_sku',
- '_associated_default_qty',
- '_associated_position'
+ 'associated_skus'
]
);
return $columns;
}
/**
- * @inheritdoc
+ * Add data for export
+ *
+ * @param array $dataRow
+ * @param int $productId
+ * @return mixed
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function addData($dataRow, $productId)
{
@@ -42,7 +53,12 @@ public function addData($dataRow, $productId)
}
/**
- * @inheritdoc
+ * Calculate the largest links block
+ *
+ * @param array $additionalRowsCount
+ * @param int $productId
+ * @return mixed
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function getAdditionalRowsCount($additionalRowsCount, $productId)
{
diff --git a/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php
index 5dc23fbd891a8..3df29a1d05596 100644
--- a/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php
+++ b/app/code/Magento/GroupedImportExport/Model/Import/Product/Type/Grouped.php
@@ -69,6 +69,9 @@ public function saveData()
'relation' => []
];
foreach ($bunch as $rowNum => $rowData) {
+ if ($this->_type != $rowData[Product::COL_TYPE]) {
+ continue;
+ }
$associatedSkusQty = isset($rowData['associated_skus']) ? $rowData['associated_skus'] : null;
if (!$this->_entityModel->isRowAllowedToImport($rowData, $rowNum) || empty($associatedSkusQty)) {
continue;
@@ -96,9 +99,6 @@ public function saveData()
}
$productId = $productData['entity_id'];
- if ($this->_type != $rowData[Product::COL_TYPE]) {
- continue;
- }
$linksData['product_ids'][$productId] = true;
$linksData['relation'][] = ['parent_id' => $productId, 'child_id' => $linkedProductId];
$qty = empty($associatedSkuAndQty[1]) ? 0 : trim($associatedSkuAndQty[1]);
diff --git a/app/code/Magento/GroupedImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php b/app/code/Magento/GroupedImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php
new file mode 100644
index 0000000000000..c6d3d9e9d3dc8
--- /dev/null
+++ b/app/code/Magento/GroupedImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php
@@ -0,0 +1,48 @@
+objectManagerHelper = new ObjectManagerHelper($this);
+ $this->rowCustomizerMock = $this->objectManagerHelper->getObject(
+ '\Magento\GroupedImportExport\Model\Export\RowCustomizer'
+ );
+ }
+
+ /**
+ * Test addHeaderColumns()
+ */
+ public function testAddHeaderColumns()
+ {
+ $productData = [0 => 'sku'];
+ $expectedData = [
+ 0 => 'sku',
+ 1 => 'associated_skus'
+ ];
+ $this->assertEquals($expectedData, $this->rowCustomizerMock->addHeaderColumns($productData));
+ }
+}
diff --git a/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php b/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php
index 334fb39ff45d0..d6a6b3c40bb21 100644
--- a/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php
+++ b/app/code/Magento/GroupedImportExport/Test/Unit/Model/Import/Product/Type/GroupedTest.php
@@ -6,17 +6,13 @@
namespace Magento\GroupedImportExport\Test\Unit\Model\Import\Product\Type;
-use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
use \Magento\GroupedImportExport;
-class GroupedTest extends \PHPUnit_Framework_TestCase
+class GroupedTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/** @var GroupedImportExport\Model\Import\Product\Type\Grouped */
protected $grouped;
- /** @var ObjectManagerHelper */
- protected $objectManagerHelper;
-
/**
* @var \Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -64,6 +60,8 @@ class GroupedTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
+ parent::setUp();
+
$this->setCollectionFactory = $this->getMock(
'Magento\Eav\Model\Resource\Entity\Attribute\Set\CollectionFactory',
['create'],
@@ -93,11 +91,12 @@ protected function setUp()
$this->attrCollectionFactory->expects($this->any())->method('addFieldToFilter')->willReturn([]);
$this->entityModel = $this->getMock(
'Magento\CatalogImportExport\Model\Import\Product',
- ['getNewSku', 'getOldSku', 'getNextBunch', 'isRowAllowedToImport', 'getRowScope'],
+ ['getErrorAggregator', 'getNewSku', 'getOldSku', 'getNextBunch', 'isRowAllowedToImport', 'getRowScope'],
[],
'',
false
);
+ $this->entityModel->method('getErrorAggregator')->willReturn($this->getErrorAggregatorObject());
$this->params = [
0 => $this->entityModel,
1 => 'grouped'
@@ -109,9 +108,10 @@ protected function setUp()
'',
false
);
- $entityAttributes = [
- 'attribute_id' => 'attributeSetName'
- ];
+ $entityAttributes = [[
+ 'attribute_set_name' => 'attribute_id',
+ 'attribute_id' => 'attributeSetName',
+ ]];
$this->connection = $this->getMock(
'Magento\Framework\DB\Adapter\Pdo\Mysql',
['select', 'fetchAll', 'fetchPairs', 'joinLeft', 'insertOnDuplicate', 'delete', 'quoteInto'],
@@ -136,7 +136,7 @@ protected function setUp()
$this->connection->expects($this->any())->method('insertOnDuplicate')->willReturnSelf();
$this->connection->expects($this->any())->method('delete')->willReturnSelf();
$this->connection->expects($this->any())->method('quoteInto')->willReturn('');
- $this->connection->expects($this->any())->method('fetchPairs')->will($this->returnValue($entityAttributes));
+ $this->connection->expects($this->any())->method('fetchAll')->will($this->returnValue($entityAttributes));
$this->resource = $this->getMock(
'\Magento\Framework\App\Resource',
['getConnection', 'getTableName'],
@@ -146,7 +146,6 @@ protected function setUp()
);
$this->resource->expects($this->any())->method('getConnection')->will($this->returnValue($this->connection));
$this->resource->expects($this->any())->method('getTableName')->will($this->returnValue('tableName'));
- $this->objectManagerHelper = new ObjectManagerHelper($this);
$this->grouped = $this->objectManagerHelper->getObject(
'Magento\GroupedImportExport\Model\Import\Product\Type\Grouped',
[
diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Grid/Column/Renderer/Download.php b/app/code/Magento/ImportExport/Block/Adminhtml/Grid/Column/Renderer/Download.php
index 0057f0a73570b..0010eeba42e29 100644
--- a/app/code/Magento/ImportExport/Block/Adminhtml/Grid/Column/Renderer/Download.php
+++ b/app/code/Magento/ImportExport/Block/Adminhtml/Grid/Column/Renderer/Download.php
@@ -21,6 +21,8 @@ class Download extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\Text
public function _getValue(\Magento\Framework\DataObject $row)
{
return ' ' . $row->getData('imported_file') . '
Download ';
+ . $this->getUrl('*/*/download', ['filename' => $row->getData('imported_file')]) . '">'
+ . __('Download')
+ . '';
}
}
diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Grid/Column/Renderer/Error.php b/app/code/Magento/ImportExport/Block/Adminhtml/Grid/Column/Renderer/Error.php
new file mode 100644
index 0000000000000..def8e2d833dde
--- /dev/null
+++ b/app/code/Magento/ImportExport/Block/Adminhtml/Grid/Column/Renderer/Error.php
@@ -0,0 +1,32 @@
+getData('error_file') != '') {
+ $result = ' ' . $row->getData('error_file') . '
'
+ . __('Download')
+ . ' ';
+ }
+ return $result;
+ }
+}
diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Before.php b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Before.php
index a44a22e86384f..c72ca9d461051 100644
--- a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Before.php
+++ b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Before.php
@@ -56,6 +56,20 @@ public function getEntityBehaviors()
return $this->_jsonEncoder->encode($behaviors);
}
+ /**
+ * Returns json-encoded entity behaviors notes array
+ *
+ * @return string
+ */
+ public function getEntityBehaviorsNotes()
+ {
+ $behaviors = $this->_importModel->getEntityBehaviors();
+ foreach ($behaviors as $entityCode => $behavior) {
+ $behaviors[$entityCode] = $behavior['notes'];
+ }
+ return $this->_jsonEncoder->encode($behaviors);
+ }
+
/**
* Return json-encoded list of existing behaviors
*
diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php
index 7ce277171063b..71f342b5b5857 100644
--- a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php
+++ b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php
@@ -5,6 +5,8 @@
*/
namespace Magento\ImportExport\Block\Adminhtml\Import\Edit;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
+
/**
* Import edit form block
*
@@ -108,10 +110,45 @@ protected function _prepareForm()
'disabled' => true,
'values' => $this->_behaviorFactory->create($behaviorClass)->toOptionArray(),
'class' => $behaviorCode,
+ 'onchange' => 'varienImport.handleImportBehaviorSelector();',
+ 'note' => ' ',
+ ]
+ );
+ $fieldsets[$behaviorCode]->addField(
+ $behaviorCode . \Magento\ImportExport\Model\Import::FIELD_NAME_VALIDATION_STRATEGY,
+ 'select',
+ [
+ 'name' => \Magento\ImportExport\Model\Import::FIELD_NAME_VALIDATION_STRATEGY,
+ 'title' => __(' '),
+ 'label' => __(' '),
+ 'required' => true,
+ 'class' => $behaviorCode,
+ 'disabled' => true,
+ 'values' => [
+ ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR => 'Stop on Error',
+ ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS => 'Skip error entries'
+ ],
+ 'after_element_html' => $this->getDownloadSampleFileHtml(),
+ ]
+ );
+ $fieldsets[$behaviorCode]->addField(
+ $behaviorCode . '_' . \Magento\ImportExport\Model\Import::FIELD_NAME_ALLOWED_ERROR_COUNT,
+ 'text',
+ [
+ 'name' => \Magento\ImportExport\Model\Import::FIELD_NAME_ALLOWED_ERROR_COUNT,
+ 'label' => __('Allowed Errors Count'),
+ 'title' => __('Allowed Errors Count'),
+ 'required' => true,
+ 'disabled' => true,
+ 'value' => 10,
+ 'class' => $behaviorCode . ' validate-number validate-greater-than-zero input-text',
+ 'note' => __(
+ 'Please specify number of errors to halt import process'
+ ),
]
);
$fieldsets[$behaviorCode]->addField(
- $behaviorCode . \Magento\ImportExport\Model\Import::FIELD_FIELD_SEPARATOR,
+ $behaviorCode . '_' . \Magento\ImportExport\Model\Import::FIELD_FIELD_SEPARATOR,
'text',
[
'name' => \Magento\ImportExport\Model\Import::FIELD_FIELD_SEPARATOR,
diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/Import.php b/app/code/Magento/ImportExport/Controller/Adminhtml/Import.php
index 319bef1a9cd42..0789bb1d04357 100644
--- a/app/code/Magento/ImportExport/Controller/Adminhtml/Import.php
+++ b/app/code/Magento/ImportExport/Controller/Adminhtml/Import.php
@@ -6,6 +6,8 @@
namespace Magento\ImportExport\Controller\Adminhtml;
use Magento\Backend\App\Action;
+use Magento\ImportExport\Model\Import\Entity\AbstractEntity;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
/**
* Import controller
diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php
index f8124344e9dfc..54c9049bcc91d 100644
--- a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php
+++ b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Start.php
@@ -5,11 +5,34 @@
*/
namespace Magento\ImportExport\Controller\Adminhtml\Import;
-use Magento\ImportExport\Controller\Adminhtml\Import as ImportController;
+use Magento\ImportExport\Controller\Adminhtml\ImportResult as ImportResultController;
use Magento\Framework\Controller\ResultFactory;
-class Start extends ImportController
+class Start extends ImportResultController
{
+ /**
+ * @var \Magento\ImportExport\Model\Import
+ */
+ protected $importModel;
+
+ /**
+ * @param \Magento\Backend\App\Action\Context $context
+ * @param \Magento\ImportExport\Model\Report\ReportProcessorInterface $reportProcessor
+ * @param \Magento\ImportExport\Model\History $historyModel
+ * @param \Magento\ImportExport\Helper\Report $reportHelper
+ * @param \Magento\ImportExport\Model\Import $importModel
+ */
+ public function __construct(
+ \Magento\Backend\App\Action\Context $context,
+ \Magento\ImportExport\Model\Report\ReportProcessorInterface $reportProcessor,
+ \Magento\ImportExport\Model\History $historyModel,
+ \Magento\ImportExport\Helper\Report $reportHelper,
+ \Magento\ImportExport\Model\Import $importModel
+ ) {
+ parent::__construct($context, $reportProcessor, $historyModel, $reportHelper);
+ $this->importModel = $importModel;
+ }
+
/**
* Start import process action
*
@@ -23,23 +46,26 @@ public function execute()
$resultLayout = $this->resultFactory->create(ResultFactory::TYPE_LAYOUT);
/** @var $resultBlock \Magento\ImportExport\Block\Adminhtml\Import\Frame\Result */
$resultBlock = $resultLayout->getLayout()->getBlock('import.frame.result');
- /** @var $importModel \Magento\ImportExport\Model\Import */
- $importModel = $this->_objectManager->create('Magento\ImportExport\Model\Import');
+ $resultBlock
+ ->addAction('show', 'import_validation_container')
+ ->addAction('innerHTML', 'import_validation_container_header', __('Status'))
+ ->addAction('hide', ['edit_form', 'upload_button', 'messages']);
- try {
- $importModel->setData($data);
- $importModel->importSource();
- $importModel->invalidateIndex();
- $resultBlock->addAction('show', 'import_validation_container')
- ->addAction('innerHTML', 'import_validation_container_header', __('Status'));
- } catch (\Exception $e) {
- $resultBlock->addError($e->getMessage());
- return $resultLayout;
+ $this->importModel->setData($data);
+ $this->importModel->importSource();
+ $errorAggregator = $this->importModel->getErrorAggregator();
+ if ($this->importModel->getErrorAggregator()->hasToBeTerminated()) {
+ $resultBlock->addError(__('Maximum error count has been reached or system error is occurred!'));
+ $this->addErrorMessages($resultBlock, $errorAggregator);
+ } else {
+ $this->importModel->invalidateIndex();
+ $this->addErrorMessages($resultBlock, $errorAggregator);
+ $resultBlock->addSuccess(__('Import successfully done'));
}
- $resultBlock->addAction('hide', ['edit_form', 'upload_button', 'messages'])
- ->addSuccess(__('Import successfully done'));
+
return $resultLayout;
}
+
/** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
$resultRedirect->setPath('adminhtml/*/index');
diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php
index e09c555b4cce7..631966a9a40c2 100644
--- a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php
+++ b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Validate.php
@@ -5,57 +5,15 @@
*/
namespace Magento\ImportExport\Controller\Adminhtml\Import;
-use Magento\ImportExport\Controller\Adminhtml\Import as ImportController;
+use Magento\ImportExport\Controller\Adminhtml\ImportResult as ImportResultController;
use Magento\ImportExport\Model\Import;
use Magento\ImportExport\Block\Adminhtml\Import\Frame\Result as ImportResultBlock;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\ImportExport\Model\Import\Adapter as ImportAdapter;
-class Validate extends ImportController
+class Validate extends ImportResultController
{
- /**
- * Process validation results
- *
- * @param \Magento\ImportExport\Model\Import $import
- * @param \Magento\ImportExport\Block\Adminhtml\Import\Frame\Result $resultBlock
- * @return void
- */
- protected function processValidationError(
- Import $import,
- ImportResultBlock $resultBlock
- ) {
- if ($import->getProcessedRowsCount() == $import->getInvalidRowsCount()) {
- $resultBlock->addNotice(__('This file is invalid. Please fix errors and re-upload the file.'));
- } elseif ($import->getErrorsCount() >= $import->getErrorsLimit()) {
- $resultBlock->addNotice(
- __(
- 'You\'ve reached an error limit (%1). Please fix errors and re-upload the file.',
- $import->getErrorsLimit()
- )
- );
- } else {
- if ($import->isImportAllowed()) {
- $resultBlock->addNotice(
- __(
- 'Please fix errors and re-upload the file. Or press "Import" to skip rows with errors.'
- ),
- true
- );
- } else {
- $resultBlock->addNotice(
- __('The file is partially valid, but we can\'t import it for some reason.'),
- false
- );
- }
- }
- // errors info
- foreach ($import->getErrors() as $errorCode => $rows) {
- $error = $errorCode . ' ' . __('in rows:') . ' ' . implode(', ', $rows);
- $resultBlock->addError($error);
- }
- }
-
/**
* Validate uploaded files action
*
@@ -66,7 +24,7 @@ public function execute()
$data = $this->getRequest()->getPostValue();
/** @var \Magento\Framework\View\Result\Layout $resultLayout */
$resultLayout = $this->resultFactory->create(ResultFactory::TYPE_LAYOUT);
- /** @var $resultBlock \Magento\ImportExport\Block\Adminhtml\Import\Frame\Result */
+ /** @var $resultBlock ImportResultBlock */
$resultBlock = $resultLayout->getLayout()->getBlock('import.frame.result');
if ($data) {
// common actions
@@ -75,49 +33,53 @@ public function execute()
'import_validation_container'
);
- try {
- /** @var $import \Magento\ImportExport\Model\Import */
- $import = $this->_objectManager->create('Magento\ImportExport\Model\Import')->setData($data);
- $source = ImportAdapter::findAdapterFor(
- $import->uploadSource(),
- $this->_objectManager->create('Magento\Framework\Filesystem')
- ->getDirectoryWrite(DirectoryList::ROOT),
- $data[$import::FIELD_FIELD_SEPARATOR]
- );
- $validationResult = $import->validateSource($source);
+ /** @var $import \Magento\ImportExport\Model\Import */
+ $import = $this->_objectManager->create('Magento\ImportExport\Model\Import')->setData($data);
+ $source = ImportAdapter::findAdapterFor(
+ $import->uploadSource(),
+ $this->_objectManager->create('Magento\Framework\Filesystem')
+ ->getDirectoryWrite(DirectoryList::ROOT),
+ $data[$import::FIELD_FIELD_SEPARATOR]
+ );
+ $validationResult = $import->validateSource($source);
- if (!$import->getProcessedRowsCount()) {
+ if (!$import->getProcessedRowsCount()) {
+ if (!$import->getErrorAggregator()->getErrorsCount()) {
$resultBlock->addError(__('This file is empty. Please try another one.'));
} else {
- if (!$validationResult) {
- $this->processValidationError($import, $resultBlock);
- } else {
- if ($import->isImportAllowed()) {
- $resultBlock->addSuccess(
- __('File is valid! To start import process press "Import" button'),
- true
- );
- } else {
- $resultBlock->addError(
- __('The file is valid, but we can\'t import it for some reason.'),
- false
- );
- }
+ foreach ($import->getErrorAggregator()->getAllErrors() as $error) {
+ $resultBlock->addError($error->getErrorMessage(), false);
}
- $resultBlock->addNotice($import->getNotices());
- $resultBlock->addNotice(
- __(
- 'Checked rows: %1, checked entities: %2, invalid rows: %3, total errors: %4',
- $import->getProcessedRowsCount(),
- $import->getProcessedEntitiesCount(),
- $import->getInvalidRowsCount(),
- $import->getErrorsCount()
- )
+ }
+ } else {
+ $errorAggregator = $import->getErrorAggregator();
+ if (!$validationResult) {
+ $resultBlock->addError(
+ __('Data validation is failed. Please fix errors and re-upload the file..')
);
+ $this->addErrorMessages($resultBlock, $errorAggregator);
+ } else {
+ if ($import->isImportAllowed()) {
+ $resultBlock->addSuccess(
+ __('File is valid! To start import process press "Import" button'),
+ true
+ );
+ } else {
+ $resultBlock->addError(
+ __('The file is valid, but we can\'t import it for some reason.'),
+ false
+ );
+ }
}
- } catch (\Exception $e) {
- $resultBlock->addNotice(__('Please fix errors and re-upload the file.'))
- ->addError($e->getMessage());
+ $resultBlock->addNotice(
+ __(
+ 'Checked rows: %1, checked entities: %2, invalid rows: %3, total errors: %4',
+ $import->getProcessedRowsCount(),
+ $import->getProcessedEntitiesCount(),
+ $errorAggregator->getInvalidRowsCount(),
+ $errorAggregator->getErrorsCount()
+ )
+ );
}
return $resultLayout;
} elseif ($this->getRequest()->isPost() && empty($_FILES)) {
diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php
new file mode 100644
index 0000000000000..bfb3cdb95fd23
--- /dev/null
+++ b/app/code/Magento/ImportExport/Controller/Adminhtml/ImportResult.php
@@ -0,0 +1,151 @@
+reportProcessor = $reportProcessor;
+ $this->historyModel = $historyModel;
+ $this->reportHelper = $reportHelper;
+ }
+
+ /**
+ * @param \Magento\Framework\View\Element\AbstractBlock $resultBlock
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
+ * @return $this
+ */
+ protected function addErrorMessages(
+ \Magento\Framework\View\Element\AbstractBlock $resultBlock,
+ ProcessingErrorAggregatorInterface $errorAggregator
+ ) {
+ if ($errorAggregator->getErrorsCount()) {
+ $message = '';
+ $counter = 0;
+ foreach ($this->getErrorMessages($errorAggregator) as $error) {
+ $message .= ++$counter . '. ' . $error . ' ';
+ if ($counter >= self::LIMIT_ERRORS_MESSAGE) {
+ break;
+ }
+ }
+ if ($errorAggregator->hasFatalExceptions()) {
+ foreach ($this->getSystemExceptions($errorAggregator) as $error) {
+ $message .= $error->getErrorMessage()
+ . ' '
+ . __('Show more') . ' ' . __('Additional data') . ': '
+ . $error->getErrorDescription() . '
';
+ }
+ }
+ try {
+ $resultBlock->addNotice(
+ '' . __('Following Error(s) has been occurred during importing process:') . ' '
+ . ''
+ );
+ } catch (\Exception $e) {
+ foreach ($this->getErrorMessages($errorAggregator) as $errorMessage) {
+ $resultBlock->addError($errorMessage);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface $errorAggregator
+ * @return array
+ */
+ protected function getErrorMessages(ProcessingErrorAggregatorInterface $errorAggregator)
+ {
+ $messages = [];
+ $rowMessages = $errorAggregator->getRowsGroupedByErrorCode([], [AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION]);
+ foreach ($rowMessages as $errorCode => $rows) {
+ $messages[] = $errorCode . ' ' . __('in rows:') . ' ' . implode(', ', $rows);
+ }
+ return $messages;
+ }
+
+ /**
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
+ * @return \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError[]
+ */
+ protected function getSystemExceptions(ProcessingErrorAggregatorInterface $errorAggregator)
+ {
+ return $errorAggregator->getErrorsByCode([AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION]);
+ }
+
+ /**
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
+ * @return string
+ */
+ protected function createErrorReport(ProcessingErrorAggregatorInterface $errorAggregator)
+ {
+ $this->historyModel->loadLastInsertItem();
+ $sourceFile = $this->reportHelper->getReportAbsolutePath($this->historyModel->getImportedFile());
+ $writeOnlyErrorItems = true;
+ if ($this->historyModel->getData('execution_time') == ModelHistory::IMPORT_VALIDATION) {
+ $writeOnlyErrorItems = false;
+ }
+ $fileName = $this->reportProcessor->createReport($sourceFile, $errorAggregator, $writeOnlyErrorItems);
+ $this->historyModel->addErrorReportFile($fileName);
+ return $fileName;
+ }
+
+ /**
+ * @param string $fileName
+ * @return string
+ */
+ protected function createDownloadUrlImportHistoryFile($fileName)
+ {
+ return $this->getUrl(self::IMPORT_HISTORY_FILE_DOWNLOAD_ROUTE, ['filename' => $fileName]);
+ }
+}
diff --git a/app/code/Magento/ImportExport/Helper/Report.php b/app/code/Magento/ImportExport/Helper/Report.php
index 935a64fe13a5d..f05e0a790f26c 100644
--- a/app/code/Magento/ImportExport/Helper/Report.php
+++ b/app/code/Magento/ImportExport/Helper/Report.php
@@ -90,6 +90,15 @@ public function getReportOutput($filename)
return $this->varDirectory->readFile($this->getFilePath($filename));
}
+ /**
+ * @param string $fileName
+ * @return string
+ */
+ public function getReportAbsolutePath($fileName)
+ {
+ return $this->varDirectory->getAbsolutePath(Import::IMPORT_HISTORY_DIR . $fileName);
+ }
+
/**
* Retrieve report file size
*
diff --git a/app/code/Magento/ImportExport/Model/Export/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Export/AbstractEntity.php
index e11145a53667d..d9780c68c1ab5 100644
--- a/app/code/Magento/ImportExport/Model/Export/AbstractEntity.php
+++ b/app/code/Magento/ImportExport/Model/Export/AbstractEntity.php
@@ -268,6 +268,20 @@ public function addMessageTemplate($errorCode, $message)
return $this;
}
+ /**
+ * Retrieve message template
+ *
+ * @param string $errorCode
+ * @return null|string
+ */
+ public function retrieveMessageTemplate($errorCode)
+ {
+ if (isset($this->_messageTemplates[$errorCode])) {
+ return $this->_messageTemplates[$errorCode];
+ }
+ return null;
+ }
+
/**
* Export process
*
diff --git a/app/code/Magento/ImportExport/Model/Export/Adapter/AbstractAdapter.php b/app/code/Magento/ImportExport/Model/Export/Adapter/AbstractAdapter.php
index 20a92c0f6c943..4e1087fb6aa9f 100644
--- a/app/code/Magento/ImportExport/Model/Export/Adapter/AbstractAdapter.php
+++ b/app/code/Magento/ImportExport/Model/Export/Adapter/AbstractAdapter.php
@@ -37,13 +37,17 @@ abstract class AbstractAdapter
/**
* Constructor
*
- * @param \Magento\Framework\Filesystem $filesystem
+ * @param Filesystem $filesystem
* @param string|null $destination
+ * @param string $destinationDirectoryCode
* @throws \Magento\Framework\Exception\LocalizedException
*/
- public function __construct(\Magento\Framework\Filesystem $filesystem, $destination = null)
- {
- $this->_directoryHandle = $filesystem->getDirectoryWrite(DirectoryList::SYS_TMP);
+ public function __construct(
+ \Magento\Framework\Filesystem $filesystem,
+ $destination = null,
+ $destinationDirectoryCode = DirectoryList::SYS_TMP
+ ) {
+ $this->_directoryHandle = $filesystem->getDirectoryWrite($destinationDirectoryCode);
if (!$destination) {
$destination = uniqid('importexport_');
$this->_directoryHandle->touch($destination);
diff --git a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php
index 136ab28fb7c99..9ff3b8c8b45ec 100644
--- a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php
+++ b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php
@@ -346,6 +346,20 @@ public function addMessageTemplate($errorCode, $message)
return $this;
}
+ /**
+ * Retrieve message template
+ *
+ * @param string $errorCode
+ * @return null|string
+ */
+ public function retrieveMessageTemplate($errorCode)
+ {
+ if (isset($this->_messageTemplates[$errorCode])) {
+ return $this->_messageTemplates[$errorCode];
+ }
+ return null;
+ }
+
/**
* Export process.
*
diff --git a/app/code/Magento/ImportExport/Model/History.php b/app/code/Magento/ImportExport/Model/History.php
index 9cdad07dd5d3a..f21cf7edf8eed 100644
--- a/app/code/Magento/ImportExport/Model/History.php
+++ b/app/code/Magento/ImportExport/Model/History.php
@@ -23,6 +23,8 @@ class History extends \Magento\Framework\Model\AbstractModel
const IMPORTED_FILE = 'imported_file';
+ const ERROR_FILE = 'error_file';
+
const EXECUTION_TIME = 'execution_time';
const SUMMARY = 'summary';
@@ -91,6 +93,19 @@ public function addReport($filename)
return $this;
}
+ /**
+ * Add errors to import history report
+ *
+ * @param string $filename
+ * @return $this
+ */
+ public function addErrorReportFile($filename)
+ {
+ $this->setErrorFile($filename);
+ $this->save();
+ return $this;
+ }
+
/**
* Update import history report
*
@@ -170,6 +185,16 @@ public function getImportedFile()
return $this->getData(self::IMPORTED_FILE);
}
+ /**
+ * Get error file
+ *
+ * @return string
+ */
+ public function getErrorFile()
+ {
+ return $this->getData(self::ERROR_FILE);
+ }
+
/**
* Get import execution time
*
@@ -234,6 +259,16 @@ public function setImportedFile($importedFile)
return $this->setData(self::IMPORTED_FILE, $importedFile);
}
+ /**
+ * Set error file name
+ *
+ * @param string $errorFile
+ * @return $this
+ */
+ public function setErrorFile($errorFile)
+ {
+ return $this->setData(self::ERROR_FILE, $errorFile);
+ }
/**
* Set Execution Time
*
@@ -256,6 +291,16 @@ public function setSummary($summary)
return $this->setData(self::SUMMARY, $summary);
}
+ /**
+ * @return $this
+ */
+ public function loadLastInsertItem()
+ {
+ $this->load($this->getLastItemId());
+
+ return $this;
+ }
+
/**
* Retrieve admin ID
*
diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php
index e46e82e6abe8d..94a7c1a6dd3c1 100644
--- a/app/code/Magento/ImportExport/Model/Import.php
+++ b/app/code/Magento/ImportExport/Model/Import.php
@@ -10,6 +10,8 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\HTTP\Adapter\FileTransferFactory;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
/**
* Import model
@@ -56,6 +58,16 @@ class Import extends \Magento\ImportExport\Model\AbstractModel
*/
const FIELD_NAME_IMG_FILE_DIR = 'import_images_file_dir';
+ /**
+ * Allowed errors count field name
+ */
+ const FIELD_NAME_ALLOWED_ERROR_COUNT = 'allowed_error_count';
+
+ /**
+ * Validation startegt field name
+ */
+ const FIELD_NAME_VALIDATION_STRATEGY = 'validation_strategy';
+
/**
* Import field separator.
*/
@@ -199,9 +211,9 @@ public function __construct(
*/
protected function _getEntityAdapter()
{
+
if (!$this->_entityAdapter) {
$entities = $this->_importConfig->getEntities();
-
if (isset($entities[$this->getEntity()])) {
try {
$this->_entityAdapter = $this->_entityFactory->create($entities[$this->getEntity()]['model']);
@@ -255,31 +267,19 @@ protected function _getSourceAdapter($sourceFile)
/**
* Return operation result messages
*
- * @param bool $validationResult
+ * @param ProcessingErrorAggregatorInterface $validationResult
* @return string[]
*/
- public function getOperationResultMessages($validationResult)
+ public function getOperationResultMessages(ProcessingErrorAggregatorInterface $validationResult)
{
$messages = [];
if ($this->getProcessedRowsCount()) {
- if (!$validationResult) {
- if ($this->getProcessedRowsCount() == $this->getInvalidRowsCount()) {
- $messages[] = __('This file is invalid. Please fix errors and re-upload the file.');
- } elseif ($this->getErrorsCount() >= $this->getErrorsLimit()) {
- $messages[] = __(
- 'You\'ve reached an error limit (%1). Please fix errors and re-upload the file.',
- $this->getErrorsLimit()
- );
- } else {
- if ($this->isImportAllowed()) {
- $messages[] = __('Please fix errors and re-upload the file.');
- } else {
- $messages[] = __('The file is partially valid, but we can\'t import it for some reason.');
- }
- }
+ if ($validationResult->getErrorsCount()) {
+ $messages[] = __('Data validation is failed. Please fix errors and re-upload the file.');
+
// errors info
- foreach ($this->getErrors() as $errorCode => $rows) {
- $error = $errorCode . ' ' . __('in rows') . ': ' . implode(', ', $rows);
+ foreach ($validationResult->getRowsGroupedByErrorCode() as $errorMessage => $rows) {
+ $error = $errorMessage . ' ' . __('in rows') . ': ' . implode(', ', $rows);
$messages[] = $error;
}
} else {
@@ -289,16 +289,18 @@ public function getOperationResultMessages($validationResult)
$messages[] = __('The file is valid, but we can\'t import it for some reason.');
}
}
- $notices = $this->getNotices();
- if (is_array($notices)) {
- $messages = array_merge($messages, $notices);
- }
+
$messages[] = __(
'Checked rows: %1, checked entities: %2, invalid rows: %3, total errors: %4',
$this->getProcessedRowsCount(),
$this->getProcessedEntitiesCount(),
- $this->getInvalidRowsCount(),
- $this->getErrorsCount()
+ $validationResult->getInvalidRowsCount(),
+ $validationResult->getErrorsCount(
+ [
+ ProcessingError::ERROR_LEVEL_CRITICAL,
+ ProcessingError::ERROR_LEVEL_NOT_CRITICAL
+ ]
+ )
);
} else {
$messages[] = __('This file does not contain any data.');
@@ -358,56 +360,6 @@ public function getEntity()
return $this->_data['entity'];
}
- /**
- * Get entity adapter errors.
- *
- * @return array
- */
- public function getErrors()
- {
- return $this->_getEntityAdapter()->getErrorMessages();
- }
-
- /**
- * Returns error counter.
- *
- * @return int
- */
- public function getErrorsCount()
- {
- return $this->_getEntityAdapter()->getErrorsCount();
- }
-
- /**
- * Returns error limit value.
- *
- * @return int
- */
- public function getErrorsLimit()
- {
- return $this->_getEntityAdapter()->getErrorsLimit();
- }
-
- /**
- * Returns invalid rows count.
- *
- * @return int
- */
- public function getInvalidRowsCount()
- {
- return $this->_getEntityAdapter()->getInvalidRowsCount();
- }
-
- /**
- * Returns entity model noticees.
- *
- * @return string[]
- */
- public function getNotices()
- {
- return $this->_getEntityAdapter()->getNotices();
- }
-
/**
* Returns number of checked entities.
*
@@ -442,7 +394,6 @@ public function getWorkingDir()
* Import source file structure to DB.
*
* @return bool
- * @throws \Magento\Framework\Exception\AlreadyExistsException
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function importSource()
@@ -453,32 +404,56 @@ public function importSource()
$this->addLogComment(__('Begin import of "%1" with "%2" behavior', $this->getEntity(), $this->getBehavior()));
- try {
- $result = $this->_getEntityAdapter()->importData();
- } catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
- $this->importHistoryModel->invalidateReport($this);
- throw new \Magento\Framework\Exception\AlreadyExistsException(
- __($e->getMessage())
+ $result = $this->processImport();
+
+ if ($result) {
+ $this->addLogComment(
+ [
+ __(
+ 'Checked rows: %1, checked entities: %2, invalid rows: %3, total errors: %4',
+ $this->getProcessedRowsCount(),
+ $this->getProcessedEntitiesCount(),
+ $this->getErrorAggregator()->getInvalidRowsCount(),
+ $this->getErrorAggregator()->getErrorsCount()
+ ),
+ __('The import was successful.'),
+ ]
);
+ $this->importHistoryModel->updateReport($this, true);
+ } else {
+ $this->importHistoryModel->invalidateReport($this);
}
- $this->addLogComment(
- [
- __(
- 'Checked rows: %1, checked entities: %2, invalid rows: %3, total errors: %4',
- $this->getProcessedRowsCount(),
- $this->getProcessedEntitiesCount(),
- $this->getInvalidRowsCount(),
- $this->getErrorsCount()
- ),
- __('The import was successful.'),
- ]
- );
- $this->importHistoryModel->updateReport($this, true);
return $result;
}
+ /**
+ * @return bool
+ */
+ protected function processImport()
+ {
+ $errorAggregator = $this->_getEntityAdapter()->getErrorAggregator();
+ $errorAggregator->initValidationStrategy(
+ $this->getData(self::FIELD_NAME_VALIDATION_STRATEGY),
+ $this->getData(self::FIELD_NAME_ALLOWED_ERROR_COUNT)
+ );
+ try {
+ $this->_getEntityAdapter()->importData();
+ } catch (\Exception $e) {
+ $errorAggregator->addError(
+ \Magento\ImportExport\Model\Import\Entity\AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION,
+ ProcessingError::ERROR_LEVEL_CRITICAL,
+ null,
+ null,
+ null,
+ $e->getMessage()
+ );
+ }
+
+ return !$errorAggregator->hasToBeTerminated();
+ }
+
/**
* Import possibility getter.
*
@@ -489,6 +464,15 @@ public function isImportAllowed()
return $this->_getEntityAdapter()->isImportAllowed();
}
+ /**
+ * @return ProcessingErrorAggregatorInterface
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function getErrorAggregator()
+ {
+ return $this->_getEntityAdapter()->getErrorAggregator();
+ }
+
/**
* Move uploaded file and create source adapter instance.
*
@@ -577,11 +561,25 @@ protected function _removeBom($sourceFile)
public function validateSource(\Magento\ImportExport\Model\Import\AbstractSource $source)
{
$this->addLogComment(__('Begin data validation'));
- $adapter = $this->_getEntityAdapter()->setSource($source);
- $result = $adapter->isDataValid();
+ try {
+ $adapter = $this->_getEntityAdapter()->setSource($source);
+ $errorAggregator = $adapter->validateData();
+ } catch (\Exception $e) {
+ $errorAggregator = $this->getErrorAggregator();
+ $errorAggregator->addError(
+ \Magento\ImportExport\Model\Import\Entity\AbstractEntity::ERROR_CODE_SYSTEM_EXCEPTION,
+ ProcessingError::ERROR_LEVEL_CRITICAL,
+ null,
+ null,
+ null,
+ $e->getMessage()
+ );
+ }
- $messages = $this->getOperationResultMessages($result);
+ $messages = $this->getOperationResultMessages($errorAggregator);
$this->addLogComment($messages);
+
+ $result = !$errorAggregator->getErrorsCount();
if ($result) {
$this->addLogComment(__('Import data validation is complete.'));
}
@@ -636,6 +634,7 @@ public function getEntityBehaviors()
$behaviourData[$entityCode] = [
'token' => $behaviorClassName,
'code' => $behavior->getCode() . '_behavior',
+ 'notes' => $behavior->getNotes($entityCode),
];
} else {
throw new \Magento\Framework\Exception\LocalizedException(
@@ -678,12 +677,14 @@ public function getUniqueEntityBehaviors()
public function isReportEntityType($entity = null)
{
$result = false;
+ if (!$entity) {
+ $entity = $this->getEntity();
+ }
if ($entity !== null && $this->_getEntityAdapter()->getEntityTypeCode() != $entity) {
$entities = $this->_importConfig->getEntities();
- if (isset($entities[$this->getEntity()])) {
+ if (isset($entities[$entity])) {
try {
- $adapter = $this->_entityFactory->create($entities[$entity]['model']);
- $result = $adapter->isNeedToLogInHistory();
+ $result = $this->_getEntityAdapter()->isNeedToLogInHistory();
} catch (\Exception $e) {
throw new \Magento\Framework\Exception\LocalizedException(__('Please enter a correct entity model'));
}
diff --git a/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php
index f4a9e039a465f..50dc55f8ce762 100644
--- a/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php
+++ b/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php
@@ -5,6 +5,8 @@
*/
namespace Magento\ImportExport\Model\Import;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
use Magento\Framework\App\Resource;
/**
@@ -40,6 +42,38 @@ abstract class AbstractEntity
const DB_MAX_TEXT_LENGTH = 65536;
+ const ERROR_CODE_SYSTEM_EXCEPTION = 'systemException';
+ const ERROR_CODE_COLUMN_NOT_FOUND = 'columnNotFound';
+ const ERROR_CODE_COLUMN_EMPTY_HEADER = 'columnEmptyHeader';
+ const ERROR_CODE_COLUMN_NAME_INVALID = 'columnNameInvalid';
+ const ERROR_CODE_ATTRIBUTE_NOT_VALID = 'attributeNotInvalid';
+ const ERROR_CODE_DUPLICATE_UNIQUE_ATTRIBUTE = 'duplicateUniqueAttribute';
+ const ERROR_CODE_ILLEGAL_CHARACTERS = 'illegalCharacters';
+ const ERROR_CODE_INVALID_ATTRIBUTE = 'invalidAttributeName';
+ const ERROR_CODE_WRONG_QUOTES = 'wrongQuotes';
+ const ERROR_CODE_COLUMNS_NUMBER = 'wrongColumnsNumber';
+ const ERROR_EXCEEDED_MAX_LENGTH = 'exceededMaxLength';
+ const ERROR_INVALID_ATTRIBUTE_TYPE = 'invalidAttributeType';
+ const ERROR_INVALID_ATTRIBUTE_OPTION = 'absentAttributeOption';
+
+ protected $errorMessageTemplates = [
+ self::ERROR_CODE_SYSTEM_EXCEPTION => 'General system exception happened',
+ self::ERROR_CODE_COLUMN_NOT_FOUND => 'We can\'t find required columns: %s.',
+ self::ERROR_CODE_COLUMN_EMPTY_HEADER => 'Columns number: "%s" have empty headers',
+ self::ERROR_CODE_COLUMN_NAME_INVALID => 'Column names: "%s" are invalid',
+ self::ERROR_CODE_ATTRIBUTE_NOT_VALID => "Please correct the value for '%s'",
+ self::ERROR_CODE_DUPLICATE_UNIQUE_ATTRIBUTE => "Duplicate Unique Attribute for '%s'",
+ self::ERROR_CODE_ILLEGAL_CHARACTERS => "Illegal character used for attribute %s",
+ self::ERROR_CODE_INVALID_ATTRIBUTE => 'Header contains invalid attribute(s): "%s"',
+ self::ERROR_CODE_WRONG_QUOTES => "Curly quotes used instead of straight quotes",
+ self::ERROR_CODE_COLUMNS_NUMBER => "Number of columns does not correspond to the number of rows in the header",
+ self::ERROR_EXCEEDED_MAX_LENGTH => 'Attribute %s exceeded max length',
+ self::ERROR_INVALID_ATTRIBUTE_TYPE =>
+ 'Value for \'%s\' attribute contains incorrect value, acceptable values are in %s format',
+ self::ERROR_INVALID_ATTRIBUTE_OPTION =>
+ "Value for %s attribute contains incorrect value, see acceptable values on settings specified for Admin",
+ ];
+
/**#@-*/
/**
@@ -57,32 +91,30 @@ abstract class AbstractEntity
protected $_dataValidated = false;
/**
- * DB data source model
+ * Valid column names
*
- * @var \Magento\ImportExport\Model\Resource\Import\Data
+ * @array
*/
- protected $_dataSourceModel;
+ protected $validColumnNames = [];
/**
- * Error codes with arrays of corresponding row numbers
+ * If we should check column names
*
- * @var array
+ * @var bool
*/
- protected $_errors = [];
+ protected $needColumnCheck = false;
/**
- * Error counter
+ * DB data source model
*
- * @var int
+ * @var \Magento\ImportExport\Model\Resource\Import\Data
*/
- protected $_errorsCount = 0;
+ protected $_dataSourceModel;
/**
- * Limit of errors after which pre-processing will exit
- *
- * @var int
+ * @var ProcessingErrorAggregatorInterface
*/
- protected $_errorsLimit = 100;
+ protected $errorAggregator;
/**
* Flag to disable import
@@ -91,27 +123,6 @@ abstract class AbstractEntity
*/
protected $_importAllowed = true;
- /**
- * Array of invalid rows numbers
- *
- * @var array
- */
- protected $_invalidRows = [];
-
- /**
- * Validation failure message template definitions
- *
- * @var array
- */
- protected $_messageTemplates = [];
-
- /**
- * Notice messages
- *
- * @var string[]
- */
- protected $_notices = [];
-
/**
* Magento string lib
*
@@ -159,7 +170,7 @@ abstract class AbstractEntity
*
* @var bool
*/
- protected $logInHistory = false;
+ protected $logInHistory = true;
/**
* Rows which will be skipped during import
@@ -239,12 +250,34 @@ abstract class AbstractEntity
*/
protected $_scopeConfig;
+ /**
+ * Count if created items
+ *
+ * @var int
+ */
+ protected $countItemsCreated = 0;
+
+ /**
+ * Count if updated items
+ *
+ * @var int
+ */
+ protected $countItemsUpdated = 0;
+
+ /**
+ * Count if deleted items
+ *
+ * @var int
+ */
+ protected $countItemsDeleted = 0;
+
/**
* @param \Magento\Framework\Stdlib\StringUtils $string
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\ImportExport\Model\ImportFactory $importFactory
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
- * @param Resource $resource
+ * @param \Magento\Framework\App\Resource $resource
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param array $data
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
@@ -254,6 +287,7 @@ public function __construct(
\Magento\ImportExport\Model\ImportFactory $importFactory,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
Resource $resource,
+ ProcessingErrorAggregatorInterface $errorAggregator,
array $data = []
) {
$this->_scopeConfig = $scopeConfig;
@@ -280,6 +314,20 @@ public function __construct(
static::XML_PATH_BUNCH_SIZE,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
) : 0);
+
+ $this->errorAggregator = $errorAggregator;
+
+ foreach ($this->errorMessageTemplates as $errorCode => $message) {
+ $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
+ }
+ }
+
+ /**
+ * @return ProcessingErrorAggregatorInterface
+ */
+ public function getErrorAggregator()
+ {
+ return $this->errorAggregator;
}
/**
@@ -319,6 +367,25 @@ protected function _prepareRowForDb(array $rowData)
return $rowData;
}
+ /**
+ * Add errors to error aggregator
+ *
+ * @param string $code
+ * @param array|mixed $errors
+ * @return void
+ */
+ protected function addErrors($code, $errors)
+ {
+ if ($errors) {
+ $this->getErrorAggregator()->addError(
+ $code,
+ ProcessingError::ERROR_LEVEL_CRITICAL,
+ null,
+ implode('", "', $errors)
+ );
+ }
+ }
+
/**
* Validate data rows and save bunches to DB
*
@@ -351,11 +418,28 @@ protected function _saveValidatedBunches()
$startNewBunch = false;
}
if ($source->valid()) {
- // errors limit check
- if ($this->_errorsCount >= $this->_errorsLimit) {
- return $this;
+ $valid = true;
+ try {
+ $rowData = $source->current();
+ foreach ($rowData as $attrName => $element) {
+ if (!mb_check_encoding($element, 'UTF-8')) {
+ $valid = false;
+ $this->addRowError(
+ AbstractEntity::ERROR_CODE_ILLEGAL_CHARACTERS,
+ $this->_processedRowsCount,
+ $attrName
+ );
+ }
+ }
+ } catch (\InvalidArgumentException $e) {
+ $valid = false;
+ $this->addRowError($e->getMessage(), $this->_processedRowsCount);
+ }
+ if (!$valid) {
+ $this->_processedRowsCount++;
+ $source->next();
+ continue;
}
- $rowData = $source->current();
if (isset($rowData[$masterAttributeCode]) && trim($rowData[$masterAttributeCode])) {
/* Add entity group that passed validation to bunch */
@@ -390,20 +474,33 @@ protected function _saveValidatedBunches()
}
/**
- * Add error with corresponding current data source row number
+ * Add error with corresponding current data source row number.
*
* @param string $errorCode Error code or simply column name
- * @param int $errorRowNum Row number
- * @param string $columnName OPTIONAL Column name
+ * @param int $errorRowNum Row number.
+ * @param string $colName OPTIONAL Column name.
+ * @param string $errorMessage OPTIONAL Column name.
+ * @param string $errorLevel
+ * @param string $errorDescription
* @return $this
*/
- public function addRowError($errorCode, $errorRowNum, $columnName = null)
- {
+ public function addRowError(
+ $errorCode,
+ $errorRowNum,
+ $colName = null,
+ $errorMessage = null,
+ $errorLevel = ProcessingError::ERROR_LEVEL_CRITICAL,
+ $errorDescription = null
+ ) {
$errorCode = (string)$errorCode;
- $this->_errors[$errorCode][] = [$errorRowNum + 1, $columnName];
- // one added for human readability
- $this->_invalidRows[$errorRowNum] = true;
- $this->_errorsCount++;
+ $this->getErrorAggregator()->addError(
+ $errorCode,
+ $errorLevel,
+ $errorRowNum,
+ $colName,
+ $errorMessage,
+ $errorDescription
+ );
return $this;
}
@@ -417,7 +514,7 @@ public function addRowError($errorCode, $errorRowNum, $columnName = null)
*/
public function addMessageTemplate($errorCode, $message)
{
- $this->_messageTemplates[$errorCode] = $message;
+ $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
return $this;
}
@@ -471,66 +568,6 @@ public static function getDefaultBehavior()
return \Magento\ImportExport\Model\Import::BEHAVIOR_ADD_UPDATE;
}
- /**
- * Returns error information grouped by error types and translated (if possible)
- *
- * @return array
- */
- public function getErrorMessages()
- {
- $messages = [];
- foreach ($this->_errors as $errorCode => $errorRows) {
- if (isset($this->_messageTemplates[$errorCode])) {
- $errorCode = (string)__($this->_messageTemplates[$errorCode]);
- }
- foreach ($errorRows as $errorRowData) {
- $key = $errorRowData[1] ? sprintf($errorCode, $errorRowData[1]) : $errorCode;
- $messages[$key][] = $errorRowData[0];
- }
- }
- return $messages;
- }
-
- /**
- * Returns error counter value
- *
- * @return int
- */
- public function getErrorsCount()
- {
- return $this->_errorsCount;
- }
-
- /**
- * Returns error limit value
- *
- * @return int
- */
- public function getErrorsLimit()
- {
- return $this->_errorsLimit;
- }
-
- /**
- * Returns invalid rows count
- *
- * @return int
- */
- public function getInvalidRowsCount()
- {
- return count($this->_invalidRows);
- }
-
- /**
- * Returns model notices
- *
- * @return string[]
- */
- public function getNotices()
- {
- return $this->_notices;
- }
-
/**
* Returns number of checked entities
*
@@ -606,30 +643,37 @@ public function getMasterAttributeCode()
*/
public function isAttributeValid($attributeCode, array $attributeParams, array $rowData, $rowNumber)
{
+ $message = '';
switch ($attributeParams['type']) {
case 'varchar':
$value = $this->string->cleanString($rowData[$attributeCode]);
$valid = $this->string->strlen($value) < self::DB_MAX_VARCHAR_LENGTH;
+ $message = self::ERROR_EXCEEDED_MAX_LENGTH;
break;
case 'decimal':
$value = trim($rowData[$attributeCode]);
$valid = (double)$value == $value && is_numeric($value);
+ $message = self::ERROR_INVALID_ATTRIBUTE_TYPE;
break;
case 'select':
case 'multiselect':
$valid = isset($attributeParams['options'][strtolower($rowData[$attributeCode])]);
+ $message = self::ERROR_INVALID_ATTRIBUTE_OPTION;
break;
case 'int':
$value = trim($rowData[$attributeCode]);
$valid = (int)$value == $value && is_numeric($value);
+ $message = self::ERROR_INVALID_ATTRIBUTE_TYPE;
break;
case 'datetime':
$value = trim($rowData[$attributeCode]);
$valid = strtotime($value) !== false;
+ $message = self::ERROR_INVALID_ATTRIBUTE_TYPE;
break;
case 'text':
$value = $this->string->cleanString($rowData[$attributeCode]);
$valid = $this->string->strlen($value) < self::DB_MAX_TEXT_LENGTH;
+ $message = self::ERROR_EXCEEDED_MAX_LENGTH;
break;
default:
$valid = true;
@@ -637,10 +681,17 @@ public function isAttributeValid($attributeCode, array $attributeParams, array $
}
if (!$valid) {
- $this->addRowError(__("Please correct the value for '%s'."), $rowNumber, $attributeCode);
+ if ($message == self::ERROR_INVALID_ATTRIBUTE_TYPE) {
+ $message = sprintf(
+ $this->errorMessageTemplates[$message],
+ $attributeCode,
+ $attributeParams['type']
+ );
+ }
+ $this->addRowError($message, $rowNumber, $attributeCode);
} elseif (!empty($attributeParams['is_unique'])) {
if (isset($this->_uniqueAttributes[$attributeCode][$rowData[$attributeCode]])) {
- $this->addRowError(__("Duplicate Unique Attribute for '%s'"), $rowNumber, $attributeCode);
+ $this->addRowError(self::ERROR_CODE_DUPLICATE_UNIQUE_ATTRIBUTE, $rowNumber, $attributeCode);
return false;
}
$this->_uniqueAttributes[$attributeCode][$rowData[$attributeCode]] = true;
@@ -648,17 +699,6 @@ public function isAttributeValid($attributeCode, array $attributeParams, array $
return (bool)$valid;
}
- /**
- * Check that is all of data valid
- *
- * @return bool
- */
- public function isDataValid()
- {
- $this->validateData();
- return 0 == $this->getErrorsCount();
- }
-
/**
* Import possibility getter
*
@@ -729,25 +769,22 @@ public function setSource(AbstractSource $source)
/**
* Validate data
*
- * @return $this
+ * @return ProcessingErrorAggregatorInterface
* @throws \Magento\Framework\Exception\LocalizedException
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function validateData()
{
if (!$this->_dataValidated) {
+ $this->getErrorAggregator()->clear();
// do all permanent columns exist?
$absentColumns = array_diff($this->_permanentAttributes, $this->getSource()->getColNames());
- if ($absentColumns) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('We can\'t find required columns: %1.', implode(', ', $absentColumns))
- );
- }
+ $this->addErrors(self::ERROR_CODE_COLUMN_NOT_FOUND, $absentColumns);
// check attribute columns names validity
$columnNumber = 0;
$emptyHeaderColumns = [];
$invalidColumns = [];
+ $invalidAttributes = [];
foreach ($this->getSource()->getColNames() as $columnName) {
$columnNumber++;
if (!$this->isAttributeParticular($columnName)) {
@@ -755,27 +792,66 @@ public function validateData()
$emptyHeaderColumns[] = $columnNumber;
} elseif (!preg_match('/^[a-z][a-z0-9_]*$/', $columnName)) {
$invalidColumns[] = $columnName;
+ } elseif ($this->needColumnCheck && !in_array($columnName, $this->validColumnNames)) {
+ $invalidAttributes[] = $columnName;
}
}
}
+ $this->addErrors(self::ERROR_CODE_INVALID_ATTRIBUTE, $invalidAttributes);
+ $this->addErrors(self::ERROR_CODE_COLUMN_EMPTY_HEADER, $emptyHeaderColumns);
+ $this->addErrors(self::ERROR_CODE_COLUMN_NAME_INVALID, $invalidColumns);
- if ($emptyHeaderColumns) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('Columns number: "%1" have empty headers', implode('", "', $emptyHeaderColumns))
- );
+ if (!$this->getErrorAggregator()->getErrorsCount()) {
+ $this->_saveValidatedBunches();
+ $this->_dataValidated = true;
}
- if ($invalidColumns) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('Column names: "%1" are invalid', implode('", "', $invalidColumns))
- );
- }
-
- // initialize validation related attributes
- $this->_errors = [];
- $this->_invalidRows = [];
- $this->_saveValidatedBunches();
- $this->_dataValidated = true;
}
+ return $this->getErrorAggregator();
+ }
+
+ /**
+ * Get count of created items
+ *
+ * @return int
+ */
+ public function getCreatedItemsCount()
+ {
+ return $this->countItemsCreated;
+ }
+
+ /**
+ * Get count of updated items
+ *
+ * @return int
+ */
+ public function getUpdatedItemsCount()
+ {
+ return $this->countItemsUpdated;
+ }
+
+ /**
+ * Get count of deleted items
+ *
+ * @return int
+ */
+ public function getDeletedItemsCount()
+ {
+ return $this->countItemsDeleted;
+ }
+
+ /**
+ * Update proceed items counter
+ *
+ * @param array $created
+ * @param array $updated
+ * @param array $deleted
+ * @return $this
+ */
+ protected function updateItemsCounterStats(array $created = [], array $updated = [], array $deleted = [])
+ {
+ $this->countItemsCreated = count($created);
+ $this->countItemsUpdated = count($updated);
+ $this->countItemsDeleted = count($deleted);
return $this;
}
}
diff --git a/app/code/Magento/ImportExport/Model/Import/AbstractSource.php b/app/code/Magento/ImportExport/Model/Import/AbstractSource.php
index 05922175aa09a..d91b394a5c080 100644
--- a/app/code/Magento/ImportExport/Model/Import/AbstractSource.php
+++ b/app/code/Magento/ImportExport/Model/Import/AbstractSource.php
@@ -5,6 +5,8 @@
*/
namespace Magento\ImportExport\Model\Import;
+use Magento\ImportExport\Model\Import\AbstractEntity;
+
/**
* Data source with columns for Magento_ImportExport
*/
@@ -38,6 +40,11 @@ abstract class AbstractSource implements \SeekableIterator
*/
protected $_key = -1;
+ /**
+ * @var bool
+ */
+ protected $_foundWrongQuoteFlag = false;
+
/**
* Get and validate column names
*
@@ -77,7 +84,11 @@ public function current()
{
$row = $this->_row;
if (count($row) != $this->_colQty) {
- $row = array_pad($this->_row, $this->_colQty, '');
+ if ($this->_foundWrongQuoteFlag) {
+ throw new \InvalidArgumentException(AbstractEntity::ERROR_CODE_WRONG_QUOTES);
+ } else {
+ throw new \InvalidArgumentException(AbstractEntity::ERROR_CODE_COLUMNS_NUMBER);
+ }
}
return array_combine($this->_colNames, $row);
}
diff --git a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php
index 38d488a52e752..2e9d08c3e4178 100644
--- a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php
+++ b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php
@@ -5,6 +5,8 @@
*/
namespace Magento\ImportExport\Model\Import\Entity;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
+
/**
* Import EAV entity abstract model
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -78,6 +80,7 @@ abstract class AbstractEav extends \Magento\ImportExport\Model\Import\AbstractEn
* @param \Magento\ImportExport\Model\ImportFactory $importFactory
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Framework\App\Resource $resource
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\ImportExport\Model\Export\Factory $collectionFactory
* @param \Magento\Eav\Model\Config $eavConfig
@@ -91,12 +94,13 @@ public function __construct(
\Magento\ImportExport\Model\ImportFactory $importFactory,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
\Magento\Framework\App\Resource $resource,
+ ProcessingErrorAggregatorInterface $errorAggregator,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\ImportExport\Model\Export\Factory $collectionFactory,
\Magento\Eav\Model\Config $eavConfig,
array $data = []
) {
- parent::__construct($string, $scopeConfig, $importFactory, $resourceHelper, $resource, $data);
+ parent::__construct($string, $scopeConfig, $importFactory, $resourceHelper, $resource, $errorAggregator, $data);
$this->_storeManager = $storeManager;
$this->_attributeCollection = isset(
@@ -176,6 +180,7 @@ protected function _initAttributes()
'type' => \Magento\ImportExport\Model\Import::getAttributeType($attribute),
'options' => $this->getAttributeOptions($attribute),
];
+ $this->validColumnNames[] = $attribute->getAttributeCode();
}
return $this;
}
diff --git a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php
index 078e81c60aaa2..79c12cd16a7c4 100644
--- a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php
+++ b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEntity.php
@@ -8,6 +8,8 @@
use Magento\Framework\App\Resource;
use Magento\ImportExport\Model\Import\AbstractSource;
use Magento\ImportExport\Model\Import as ImportExport;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
/**
* Import entity abstract model
@@ -27,6 +29,37 @@ abstract class AbstractEntity
const DB_MAX_TEXT_LENGTH = 65536;
+ const ERROR_CODE_SYSTEM_EXCEPTION = 'systemException';
+ const ERROR_CODE_COLUMN_NOT_FOUND = 'columnNotFound';
+ const ERROR_CODE_COLUMN_EMPTY_HEADER = 'columnEmptyHeader';
+ const ERROR_CODE_COLUMN_NAME_INVALID = 'columnNameInvalid';
+ const ERROR_CODE_ATTRIBUTE_NOT_VALID = 'attributeNotInvalid';
+ const ERROR_CODE_DUPLICATE_UNIQUE_ATTRIBUTE = 'duplicateUniqueAttribute';
+ const ERROR_CODE_ILLEGAL_CHARACTERS = 'illegalCharacters';
+ const ERROR_CODE_INVALID_ATTRIBUTE = 'invalidAttributeName';
+ const ERROR_CODE_WRONG_QUOTES = 'wrongQuotes';
+ const ERROR_CODE_COLUMNS_NUMBER = 'wrongColumnsNumber';
+
+ protected $errorMessageTemplates = [
+ self::ERROR_CODE_SYSTEM_EXCEPTION => 'General system exception happened',
+ self::ERROR_CODE_COLUMN_NOT_FOUND => 'We can\'t find required columns: %s.',
+ self::ERROR_CODE_COLUMN_EMPTY_HEADER => 'Columns number: "%s" have empty headers',
+ self::ERROR_CODE_COLUMN_NAME_INVALID => 'Column names: "%s" are invalid',
+ self::ERROR_CODE_ATTRIBUTE_NOT_VALID => "Please correct the value for '%s'.",
+ self::ERROR_CODE_DUPLICATE_UNIQUE_ATTRIBUTE => "Duplicate Unique Attribute for '%s'",
+ self::ERROR_CODE_ILLEGAL_CHARACTERS => "Illegal character used for attribute %s",
+ self::ERROR_CODE_INVALID_ATTRIBUTE => 'Header contains invalid attribute(s): "%s"',
+ self::ERROR_CODE_WRONG_QUOTES => "Curly quotes used instead of straight quotes",
+ self::ERROR_CODE_COLUMNS_NUMBER => "Number of columns does not correspond to the number of rows in the header",
+ ];
+
+ /**
+ * Validation failure message template definitions
+ *
+ * @var array
+ */
+ protected $_messageTemplates = [];
+
/**
* DB connection.
*
@@ -35,46 +68,46 @@ abstract class AbstractEntity
protected $_connection;
/**
- * Has data process validation done?
+ * Has data process validation done?8
*
* @var bool
*/
protected $_dataValidated = false;
/**
- * DB data source model.
+ * Valid column names
*
- * @var \Magento\ImportExport\Model\Resource\Import\Data
+ * @array
*/
- protected $_dataSourceModel;
+ protected $validColumnNames = [];
/**
- * Entity type id.
+ * If we should check column names
*
- * @var int
+ * @var bool
*/
- protected $_entityTypeId;
+ protected $needColumnCheck = false;
/**
- * Error codes with arrays of corresponding row numbers.
+ * DB data source model.
*
- * @var array
+ * @var \Magento\ImportExport\Model\Resource\Import\Data
*/
- protected $_errors = [];
+ protected $_dataSourceModel;
/**
- * Error counter.
+ * Entity type id.
*
* @var int
*/
- protected $_errorsCount = 0;
+ protected $_entityTypeId;
/**
- * Limit of errors after which pre-processing will exit.
+ * Error codes with arrays of corresponding row numbers.
*
- * @var int
+ * @var array
*/
- protected $_errorsLimit = 100;
+ protected $_errors = [];
/**
* Flag to disable import.
@@ -90,27 +123,6 @@ abstract class AbstractEntity
*/
protected $_indexValueAttributes = [];
- /**
- * Array of invalid rows numbers.
- *
- * @var array
- */
- protected $_invalidRows = [];
-
- /**
- * Validation failure message template definitions.
- *
- * @var array
- */
- protected $_messageTemplates = [];
-
- /**
- * Notice messages.
- *
- * @var string[]
- */
- protected $_notices = [];
-
/**
* Entity model parameters.
*
@@ -146,17 +158,6 @@ abstract class AbstractEntity
*/
protected $_processedRowsCount = 0;
- /**
- * Rows to skip. Valid rows but we have some reasons to skip them.
- *
- * [Row number 1] => true,
- * ...
- * [Row number N] => true
- *
- * @var array
- */
- protected $_rowsToSkip = [];
-
/**
* Array of numbers of validated rows as keys and boolean TRUE as values.
*
@@ -232,6 +233,11 @@ abstract class AbstractEntity
*/
protected $logInHistory = false;
+ /**
+ * @var ProcessingErrorAggregatorInterface
+ */
+ protected $errorAggregator;
+
/**
* @param \Magento\Framework\Json\Helper\Data $jsonHelper
* @param \Magento\ImportExport\Helper\Data $importExportData
@@ -240,6 +246,8 @@ abstract class AbstractEntity
* @param Resource $resource
* @param \Magento\ImportExport\Model\Resource\Helper $resourceHelper
* @param \Magento\Framework\Stdlib\StringUtils $string
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
public function __construct(
\Magento\Framework\Json\Helper\Data $jsonHelper,
@@ -248,12 +256,18 @@ public function __construct(
\Magento\Eav\Model\Config $config,
Resource $resource,
\Magento\ImportExport\Model\Resource\Helper $resourceHelper,
- \Magento\Framework\Stdlib\StringUtils $string
+ \Magento\Framework\Stdlib\StringUtils $string,
+ ProcessingErrorAggregatorInterface $errorAggregator
) {
$this->jsonHelper = $jsonHelper;
$this->_importExportData = $importExportData;
$this->_resourceHelper = $resourceHelper;
$this->string = $string;
+ $this->errorAggregator = $errorAggregator;
+
+ foreach ($this->errorMessageTemplates as $errorCode => $message) {
+ $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
+ }
$entityType = $config->getEntityType($this->getEntityTypeCode());
@@ -317,6 +331,25 @@ protected function _prepareRowForDb(array $rowData)
return $rowData;
}
+ /**
+ * Add errors to error aggregator
+ *
+ * @param string $code
+ * @param array|mixed $errors
+ * @return void
+ */
+ protected function addErrors($code, $errors)
+ {
+ if ($errors) {
+ $this->getErrorAggregator()->addError(
+ $code,
+ ProcessingError::ERROR_LEVEL_CRITICAL,
+ null,
+ implode('", "', $errors)
+ );
+ }
+ }
+
/**
* Validate data rows and save bunches to DB.
*
@@ -346,11 +379,14 @@ protected function _saveValidatedBunches()
$nextRowBackup = [];
}
if ($source->valid()) {
- if ($this->_errorsCount >= $this->_errorsLimit) {
- // errors limit check
- return;
+ try {
+ $rowData = $source->current();
+ } catch (\InvalidArgumentException $e) {
+ $this->addRowError($e->getMessage(), $this->_processedRowsCount);
+ $this->_processedRowsCount++;
+ $source->next();
+ continue;
}
- $rowData = $source->current();
$this->_processedRowsCount++;
@@ -381,15 +417,28 @@ protected function _saveValidatedBunches()
* @param string $errorCode Error code or simply column name
* @param int $errorRowNum Row number.
* @param string $colName OPTIONAL Column name.
+ * @param string $errorMessage OPTIONAL Column name.
+ * @param string $errorLevel
+ * @param string $errorDescription
* @return $this
*/
- public function addRowError($errorCode, $errorRowNum, $colName = null)
- {
+ public function addRowError(
+ $errorCode,
+ $errorRowNum,
+ $colName = null,
+ $errorMessage = null,
+ $errorLevel = ProcessingError::ERROR_LEVEL_CRITICAL,
+ $errorDescription = null
+ ) {
$errorCode = (string)$errorCode;
- $this->_errors[$errorCode][] = [$errorRowNum + 1, $colName];
- // one added for human readability
- $this->_invalidRows[$errorRowNum] = true;
- $this->_errorsCount++;
+ $this->getErrorAggregator()->addError(
+ $errorCode,
+ $errorLevel,
+ $errorRowNum,
+ $colName,
+ $errorMessage,
+ $errorDescription
+ );
return $this;
}
@@ -403,7 +452,7 @@ public function addRowError($errorCode, $errorRowNum, $colName = null)
*/
public function addMessageTemplate($errorCode, $message)
{
- $this->_messageTemplates[$errorCode] = $message;
+ $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
return $this;
}
@@ -485,66 +534,6 @@ public function getEntityTypeId()
return $this->_entityTypeId;
}
- /**
- * Returns error information grouped by error types and translated (if possible).
- *
- * @return array
- */
- public function getErrorMessages()
- {
- $messages = [];
- foreach ($this->_errors as $errorCode => $errorRows) {
- if (isset($this->_messageTemplates[$errorCode])) {
- $errorCode = (string)__($this->_messageTemplates[$errorCode]);
- }
- foreach ($errorRows as $errorRowData) {
- $key = $errorRowData[1] ? sprintf($errorCode, $errorRowData[1]) : $errorCode;
- $messages[$key][] = $errorRowData[0];
- }
- }
- return $messages;
- }
-
- /**
- * Returns error counter value.
- *
- * @return int
- */
- public function getErrorsCount()
- {
- return $this->_errorsCount;
- }
-
- /**
- * Returns error limit value.
- *
- * @return int
- */
- public function getErrorsLimit()
- {
- return $this->_errorsLimit;
- }
-
- /**
- * Returns invalid rows count.
- *
- * @return int
- */
- public function getInvalidRowsCount()
- {
- return count($this->_invalidRows);
- }
-
- /**
- * Returns model notices.
- *
- * @return string[]
- */
- public function getNotices()
- {
- return $this->_notices;
- }
-
/**
* Returns number of checked entities.
*
@@ -643,10 +632,10 @@ public function isAttributeValid($attrCode, array $attrParams, array $rowData, $
}
if (!$valid) {
- $this->addRowError(__("Please correct the value for '%s'."), $rowNum, $attrCode);
+ $this->addRowError(self::ERROR_CODE_ATTRIBUTE_NOT_VALID, $rowNum, $attrCode);
} elseif (!empty($attrParams['is_unique'])) {
if (isset($this->_uniqueAttributes[$attrCode][$rowData[$attrCode]])) {
- $this->addRowError(__("Duplicate Unique Attribute for '%s'"), $rowNum, $attrCode);
+ $this->addRowError(self::ERROR_CODE_DUPLICATE_UNIQUE_ATTRIBUTE, $rowNum, $attrCode);
return false;
}
$this->_uniqueAttributes[$attrCode][$rowData[$attrCode]] = true;
@@ -654,17 +643,6 @@ public function isAttributeValid($attrCode, array $attrParams, array $rowData, $
return (bool)$valid;
}
- /**
- * Is all of data valid?
- *
- * @return bool
- */
- public function isDataValid()
- {
- $this->validateData();
- return 0 == $this->_errorsCount;
- }
-
/**
* Import possibility getter.
*
@@ -684,7 +662,22 @@ public function isImportAllowed()
*/
public function isRowAllowedToImport(array $rowData, $rowNum)
{
- return $this->validateRow($rowData, $rowNum) && !isset($this->_rowsToSkip[$rowNum]);
+ $this->validateRow($rowData, $rowNum);
+ return !$this->getErrorAggregator()->isRowInvalid($rowNum);
+ }
+
+ /**
+ * Retrieve message template
+ *
+ * @param string $errorCode
+ * @return null|string
+ */
+ public function retrieveMessageTemplate($errorCode)
+ {
+ if (isset($this->_messageTemplates[$errorCode])) {
+ return $this->_messageTemplates[$errorCode];
+ }
+ return null;
}
/**
@@ -718,6 +711,16 @@ public function setParameters(array $params)
return $this;
}
+ /**
+ * Get data from outside to change behavior. I.e. for setting some default parameters etc.
+ *
+ * @return array $params
+ */
+ public function getParameters()
+ {
+ return $this->_parameters;
+ }
+
/**
* Source model setter.
*
@@ -735,25 +738,24 @@ public function setSource(AbstractSource $source)
/**
* Validate data.
*
- * @return $this
+ * @return ProcessingErrorAggregatorInterface
* @throws \Magento\Framework\Exception\LocalizedException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function validateData()
{
if (!$this->_dataValidated) {
+ $this->getErrorAggregator()->clear();
// do all permanent columns exist?
- if ($absentColumns = array_diff($this->_permanentAttributes, $this->getSource()->getColNames())) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('We can\'t find required columns: %1.', implode(', ', $absentColumns))
- );
- }
+ $absentColumns = array_diff($this->_permanentAttributes, $this->getSource()->getColNames());
+ $this->addErrors(self::ERROR_CODE_COLUMN_NOT_FOUND, $absentColumns);
if (ImportExport::BEHAVIOR_DELETE != $this->getBehavior()) {
// check attribute columns names validity
$columnNumber = 0;
$emptyHeaderColumns = [];
$invalidColumns = [];
+ $invalidAttributes = [];
foreach ($this->getSource()->getColNames() as $columnName) {
$columnNumber++;
if (!$this->isAttributeParticular($columnName)) {
@@ -761,29 +763,30 @@ public function validateData()
$emptyHeaderColumns[] = $columnNumber;
} elseif (!preg_match('/^[a-z][a-z0-9_]*$/', $columnName)) {
$invalidColumns[] = $columnName;
+ } elseif ($this->needColumnCheck && !in_array($columnName, $this->validColumnNames)) {
+ $invalidAttributes[] = $columnName;
}
}
}
-
- if ($emptyHeaderColumns) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('Columns number: "%1" have empty headers', implode('", "', $emptyHeaderColumns))
- );
- }
- if ($invalidColumns) {
- throw new \Magento\Framework\Exception\LocalizedException(
- __('Column names: "%1" are invalid', implode('", "', $invalidColumns))
- );
- }
+ $this->addErrors(self::ERROR_CODE_INVALID_ATTRIBUTE, $invalidAttributes);
+ $this->addErrors(self::ERROR_CODE_COLUMN_EMPTY_HEADER, $emptyHeaderColumns);
+ $this->addErrors(self::ERROR_CODE_COLUMN_NAME_INVALID, $invalidColumns);
}
- // initialize validation related attributes
- $this->_errors = [];
- $this->_invalidRows = [];
- $this->_saveValidatedBunches();
- $this->_dataValidated = true;
+ if (!$this->getErrorAggregator()->getErrorsCount()) {
+ $this->_saveValidatedBunches();
+ $this->_dataValidated = true;
+ }
}
- return $this;
+ return $this->getErrorAggregator();
+ }
+
+ /**
+ * @return ProcessingErrorAggregatorInterface
+ */
+ public function getErrorAggregator()
+ {
+ return $this->errorAggregator;
}
/**
diff --git a/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingError.php b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingError.php
new file mode 100644
index 0000000000000..c86984ebc4d73
--- /dev/null
+++ b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingError.php
@@ -0,0 +1,121 @@
+errorCode = $errorCode;
+ $this->errorLevel = $errorLevel;
+ $this->rowNumber = $rowNumber;
+ $this->columnName = $columnName;
+ $this->errorMessage = $errorMessage;
+ $this->errorDescription = $errorDescription;
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorCode()
+ {
+ return $this->errorCode;
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorMessage()
+ {
+ return $this->errorMessage;
+ }
+
+ /**
+ * @return int
+ */
+ public function getRowNumber()
+ {
+ return $this->rowNumber;
+ }
+
+ /**
+ * @return string
+ */
+ public function getColumnName()
+ {
+ return $this->columnName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorLevel()
+ {
+ return $this->errorLevel;
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorDescription()
+ {
+ return $this->errorDescription;
+ }
+}
diff --git a/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php
new file mode 100644
index 0000000000000..acb19a9847212
--- /dev/null
+++ b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php
@@ -0,0 +1,363 @@
+errorFactory = $errorFactory;
+ }
+
+ /**
+ * @param string $errorCode
+ * @param string $errorLevel
+ * @param int|null $rowNumber
+ * @param string|null $columnName
+ * @param string|null $errorMessage
+ * @param string|null $errorDescription
+ * @return $this
+ */
+ public function addError(
+ $errorCode,
+ $errorLevel = ProcessingError::ERROR_LEVEL_CRITICAL,
+ $rowNumber = null,
+ $columnName = null,
+ $errorMessage = null,
+ $errorDescription = null
+ ) {
+ if ($this->isErrorAlreadyAdded($rowNumber, $errorCode)) {
+ return $this;
+ }
+ $this->processErrorStatistics($errorLevel);
+ $this->processInvalidRow($rowNumber);
+ $errorMessage = $this->getErrorMessage($errorCode, $errorMessage, $columnName);
+
+ /** @var ProcessingError $newError */
+ $newError = $this->errorFactory->create();
+ $newError->init($errorCode, $errorLevel, $rowNumber, $columnName, $errorMessage, $errorDescription);
+ $this->items[] = $newError;
+
+ return $this;
+ }
+
+ /**
+ * @param int $rowNumber
+ * @return $this
+ */
+ public function addRowToSkip($rowNumber)
+ {
+ $rowNumber = (int)$rowNumber;
+ if (!in_array($rowNumber, $this->skippedRows)) {
+ $this->skippedRows[] = $rowNumber;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param int $rowNumber
+ * @return $this
+ */
+ protected function processInvalidRow($rowNumber)
+ {
+ if (null !== $rowNumber) {
+ $rowNumber = (int)$rowNumber;
+ if (!in_array($rowNumber, $this->invalidRows)) {
+ $this->invalidRows[] = $rowNumber;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * @param string $code
+ * @param string $template
+ * @return $this
+ */
+ public function addErrorMessageTemplate($code, $template)
+ {
+ $this->messageTemplate[$code] = $template;
+
+ return $this;
+ }
+
+ /**
+ * @param int $rowNumber
+ * @return bool
+ */
+ public function isRowInvalid($rowNumber)
+ {
+ return in_array((int)$rowNumber, array_merge($this->invalidRows, $this->skippedRows));
+ }
+
+ /**
+ * @return int
+ */
+ public function getInvalidRowsCount()
+ {
+ return count($this->invalidRows);
+ }
+
+ /**
+ * @param string $validationStrategy
+ * @param int $allowedErrorCount
+ * @return $this
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function initValidationStrategy($validationStrategy, $allowedErrorCount = 0)
+ {
+ $allowedStrategy = [
+ self::VALIDATION_STRATEGY_STOP_ON_ERROR,
+ self::VALIDATION_STRATEGY_SKIP_ERRORS
+ ];
+ if (!in_array($validationStrategy, $allowedStrategy)) {
+ throw new \Magento\Framework\Exception\LocalizedException(
+ __('ImportExport: Import Data validation - Validation strategy not found')
+ );
+ }
+ $this->validationStrategy = $validationStrategy;
+ $this->allowedErrorsCount = (int)$allowedErrorCount;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasToBeTerminated()
+ {
+ return $this->hasFatalExceptions() || $this->isErrorLimitExceeded();
+ }
+
+ /**
+ * @return bool
+ */
+ public function isErrorLimitExceeded()
+ {
+ $isExceeded = false;
+ $errorsCount = $this->getErrorsCount([ProcessingError::ERROR_LEVEL_NOT_CRITICAL]);
+ if ($errorsCount > 0
+ && $this->validationStrategy == self::VALIDATION_STRATEGY_STOP_ON_ERROR
+ && $errorsCount >= $this->allowedErrorsCount
+ ) {
+ $isExceeded = true;
+ }
+
+ return $isExceeded;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasFatalExceptions()
+ {
+ return (bool)$this->getErrorsCount([ProcessingError::ERROR_LEVEL_CRITICAL]);
+ }
+
+
+ /**
+ * @return ProcessingError[]
+ */
+ public function getAllErrors()
+ {
+ return $this->items;
+ }
+
+ /**
+ * @param string[] $codes
+ * @return ProcessingError[]
+ */
+ public function getErrorsByCode(array $codes)
+ {
+ $result = [];
+ foreach ($this->items as $error) {
+ if (in_array($error->getErrorCode(), $codes)) {
+ $result[] = $error;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param int $rowNumber
+ * @return ProcessingError[]
+ */
+ public function getErrorByRowNumber($rowNumber)
+ {
+ $result = [];
+ foreach ($this->items as $error) {
+ if ($error->getRowNumber() == (int)$rowNumber) {
+ $result[] = $error;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param array $errorCode
+ * @param array $excludedCodes
+ * @param bool $replaceCodeWithMessage
+ * @return array
+ */
+ public function getRowsGroupedByErrorCode(
+ array $errorCode = [],
+ array $excludedCodes = [],
+ $replaceCodeWithMessage = true
+ ) {
+ $result = [];
+ foreach ($this->items as $error) {
+ if ((!empty($errorCode) && in_array($error->getErrorCode(), $errorCode))
+ || in_array($error->getErrorCode(), $excludedCodes)
+ ) {
+ continue;
+ }
+ $message = $replaceCodeWithMessage ? $error->getErrorMessage() : $error->getErrorCode();
+ $result[$message][] = $error->getRowNumber()+1;
+ }
+ return $result;
+ }
+
+ /**
+ * @return int
+ */
+ public function getAllowedErrorsCount()
+ {
+ return $this->allowedErrorsCount;
+ }
+
+ /**
+ * @param string[] $errorLevels
+ * @return int
+ */
+ public function getErrorsCount(
+ array $errorLevels = [
+ ProcessingError::ERROR_LEVEL_CRITICAL,
+ ProcessingError::ERROR_LEVEL_NOT_CRITICAL
+ ]
+ ) {
+ $result = 0;
+ foreach ($errorLevels as $errorLevel) {
+ $result += isset($this->errorStatistics[$errorLevel]) ? $this->errorStatistics[$errorLevel] : 0;
+ }
+
+ return $result;
+ }
+
+ /**
+ * @return $this
+ */
+ public function clear()
+ {
+ $this->items = [];
+ $this->errorStatistics = [];
+ $this->invalidRows = [];
+
+ return $this;
+ }
+
+ /**
+ * @param int $rowNum
+ * @param string $errorCode
+ * @return bool
+ */
+ protected function isErrorAlreadyAdded($rowNum, $errorCode)
+ {
+ $errors = $this->getErrorsByCode([$errorCode]);
+ foreach ($errors as $error) {
+ if ($rowNum == $error->getRowNumber()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param string $errorCode
+ * @param string $errorMessage
+ * @param string $columnName
+ * @return string
+ */
+ protected function getErrorMessage($errorCode, $errorMessage, $columnName)
+ {
+ if (null === $errorMessage && isset($this->messageTemplate[$errorCode])) {
+ $errorMessage = (string)__($this->messageTemplate[$errorCode]);
+ }
+ if ($columnName && $errorMessage) {
+ $errorMessage = sprintf($errorMessage, $columnName);
+ }
+ if (!$errorMessage) {
+ $errorMessage = $errorCode;
+ }
+
+ return $errorMessage;
+ }
+
+ /**
+ * @param string $errorLevel
+ * @return $this
+ */
+ protected function processErrorStatistics($errorLevel)
+ {
+ if (!empty($errorLevel)) {
+ isset($this->errorStatistics[$errorLevel]) ?
+ $this->errorStatistics[$errorLevel]++ : $this->errorStatistics[$errorLevel] = 1;
+ }
+
+ return $this;
+ }
+}
diff --git a/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregatorInterface.php b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregatorInterface.php
new file mode 100644
index 0000000000000..3bbf90a068a08
--- /dev/null
+++ b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregatorInterface.php
@@ -0,0 +1,163 @@
+_file->readCsv(0, $this->_delimiter, $this->_enclosure);
+ $parsed = $this->_file->readCsv(0, $this->_delimiter, $this->_enclosure);
+ if (is_array($parsed) && count($parsed) != $this->_colQty) {
+ foreach ($parsed as $element) {
+ if (strpos($element, "'") !== false) {
+ $this->_foundWrongQuoteFlag = true;
+ break;
+ }
+ }
+ } else {
+ $this->_foundWrongQuoteFlag = false;
+ }
+ return $parsed;
}
/**
diff --git a/app/code/Magento/ImportExport/Model/Report/Csv.php b/app/code/Magento/ImportExport/Model/Report/Csv.php
new file mode 100644
index 0000000000000..387e57e4eefd9
--- /dev/null
+++ b/app/code/Magento/ImportExport/Model/Report/Csv.php
@@ -0,0 +1,151 @@
+reportHelper = $reportHelper;
+ $this->sourceCsvFactory = $sourceCsvFactory;
+ $this->outputCsvFactory = $outputCsvFactory;
+ $this->filesystem = $filesystem;
+ }
+
+ /**
+ * @param string $originalFileName
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
+ * @param bool $writeOnlyErrorItems
+ * @return string
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function createReport(
+ $originalFileName,
+ ProcessingErrorAggregatorInterface $errorAggregator,
+ $writeOnlyErrorItems = false
+ ) {
+ $sourceCsv = $this->createSourceCsvModel($originalFileName);
+
+ $outputFileName = $this->generateOutputFileName($originalFileName);
+ $outputCsv = $this->createOutputCsvModel($outputFileName);
+
+ $columnsName = $sourceCsv->getColNames();
+ array_push($columnsName, self::REPORT_ERROR_COLUMN_NAME);
+ $outputCsv->setHeaderCols($columnsName);
+
+ foreach ($sourceCsv as $rowNum => $rowData) {
+ $errorMessages = $this->retrieveErrorMessagesByRowNumber($rowNum, $errorAggregator);
+ if (!$writeOnlyErrorItems || ($writeOnlyErrorItems && $errorMessages)) {
+ $rowData[self::REPORT_ERROR_COLUMN_NAME] = $errorMessages;
+ $outputCsv->writeRow($rowData);
+ }
+ }
+
+ return $outputFileName;
+ }
+
+ /**
+ * @param int $rowNumber
+ * @param ProcessingErrorAggregatorInterface $errorAggregator
+ * @return string
+ */
+ public function retrieveErrorMessagesByRowNumber($rowNumber, ProcessingErrorAggregatorInterface $errorAggregator)
+ {
+ $messages = '';
+ foreach ($errorAggregator->getErrorByRowNumber((int)$rowNumber) as $error) {
+ $messages .= $error->getErrorMessage() . ',';
+ }
+ $messages = rtrim($messages, ',');
+
+ if ($messages) {
+ $messages = str_pad($messages, 1, '"', STR_PAD_BOTH);
+ }
+
+ return $messages;
+ }
+
+ /**
+ * @param string $sourceFile
+ * @return string
+ */
+ protected function generateOutputFileName($sourceFile)
+ {
+ $fileName = basename($sourceFile, self::ERROR_REPORT_FILE_EXTENSION);
+ return $fileName . self::ERROR_REPORT_FILE_SUFFIX . self::ERROR_REPORT_FILE_EXTENSION;
+ }
+
+ /**
+ * @param string $sourceFile
+ * @return \Magento\ImportExport\Model\Import\Source\Csv
+ */
+ protected function createSourceCsvModel($sourceFile)
+ {
+ return $this->sourceCsvFactory->create(
+ [
+ 'file' => $sourceFile,
+ 'directory' => $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR)
+ ]
+ );
+ }
+
+ /**
+ * @param string $outputFileName
+ * @return \Magento\ImportExport\Model\Export\Adapter\Csv
+ */
+ protected function createOutputCsvModel($outputFileName)
+ {
+ return $this->outputCsvFactory->create(
+ [
+ 'destination' => Import::IMPORT_HISTORY_DIR . $outputFileName,
+ 'destinationDirectoryCode' => DirectoryList::VAR_DIR,
+ ]
+ );
+ }
+}
diff --git a/app/code/Magento/ImportExport/Model/Report/ReportProcessorInterface.php b/app/code/Magento/ImportExport/Model/Report/ReportProcessorInterface.php
new file mode 100644
index 0000000000000..891270eb89c60
--- /dev/null
+++ b/app/code/Magento/ImportExport/Model/Report/ReportProcessorInterface.php
@@ -0,0 +1,27 @@
+ $this->_linkTable],
'link_table.user_id = main_table.user_id',
['username']
- )->where('execution_time != ?', History::IMPORT_VALIDATION);
+ )->where(
+ 'execution_time != ? OR (error_file != "" AND execution_time = ?)',
+ History::IMPORT_VALIDATION,
+ History::IMPORT_VALIDATION
+ );
return $this;
}
diff --git a/app/code/Magento/ImportExport/Model/Source/Import/AbstractBehavior.php b/app/code/Magento/ImportExport/Model/Source/Import/AbstractBehavior.php
index 691fcbaa61c19..2155dc20716d2 100644
--- a/app/code/Magento/ImportExport/Model/Source/Import/AbstractBehavior.php
+++ b/app/code/Magento/ImportExport/Model/Source/Import/AbstractBehavior.php
@@ -39,9 +39,21 @@ public function toOptionArray()
/**
* Get current behaviour group code
- *
+ *;
* @abstract
* @return string
*/
abstract public function getCode();
+
+ /**
+ * Get array of notes for possible values
+ *
+ * @param string $entityCode
+ * @return array
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function getNotes($entityCode)
+ {
+ return [];
+ }
}
diff --git a/app/code/Magento/ImportExport/Model/Source/Import/Behavior/Basic.php b/app/code/Magento/ImportExport/Model/Source/Import/Behavior/Basic.php
index 4b64cd12d5171..f24eb32dc5084 100644
--- a/app/code/Magento/ImportExport/Model/Source/Import/Behavior/Basic.php
+++ b/app/code/Magento/ImportExport/Model/Source/Import/Behavior/Basic.php
@@ -29,4 +29,15 @@ public function getCode()
{
return 'basic';
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getNotes($entityCode)
+ {
+ $messages = ['catalog_product' => [
+ \Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE => __("Note: Product IDs will be regenerated.")
+ ]];
+ return isset($messages[$entityCode]) ? $messages[$entityCode] : [];
+ }
}
diff --git a/app/code/Magento/ImportExport/Setup/UpgradeSchema.php b/app/code/Magento/ImportExport/Setup/UpgradeSchema.php
new file mode 100644
index 0000000000000..ae0999e99326b
--- /dev/null
+++ b/app/code/Magento/ImportExport/Setup/UpgradeSchema.php
@@ -0,0 +1,38 @@
+startSetup();
+ $installer->getConnection()->addColumn(
+ $installer->getTable('import_history'),
+ 'error_file',
+ [
+ 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
+ 'length' => 255,
+ 'nullable' => false,
+ 'comment' => 'Imported file with errors'
+ ]
+ );
+ $installer->endSetup();
+ }
+}
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/AbstractImportTestCase.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/AbstractImportTestCase.php
new file mode 100644
index 0000000000000..f4aee3f827ac6
--- /dev/null
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/AbstractImportTestCase.php
@@ -0,0 +1,44 @@
+objectManagerHelper = new ObjectManagerHelper($this);
+ }
+
+ /**
+ * @param array|null $methods
+ * @return ProcessingErrorAggregatorInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected function getErrorAggregatorObject($methods = null)
+ {
+ $errorFactory = $this->getMockBuilder(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorFactory'
+ )->disableOriginalConstructor()
+ ->setMethods(['create'])
+ ->getMock();
+ $errorFactory->method('create')->willReturn(
+ $this->objectManagerHelper->getObject('Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError')
+ );
+ return $this->getMockBuilder('Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator')
+ ->setMethods($methods)
+ ->setConstructorArgs(['errorFactory' => $errorFactory])
+ ->getMock();
+ }
+}
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/AbstractTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/AbstractTest.php
index e4ffe0d900975..b1bb4e6192522 100644
--- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/AbstractTest.php
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/AbstractTest.php
@@ -9,7 +9,9 @@
*/
namespace Magento\ImportExport\Test\Unit\Model\Import\Entity;
-class AbstractTest extends \PHPUnit_Framework_TestCase
+use Magento\ImportExport\Model\Import\Entity\AbstractEntity;
+
+class AbstractTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
* Abstract import entity model
@@ -22,14 +24,13 @@ protected function setUp()
{
parent::setUp();
- $this->_model = $this->getMockForAbstractClass(
- 'Magento\ImportExport\Model\Import\Entity\AbstractEntity',
- [],
- '',
- false,
- true,
- true,
- ['_saveValidatedBunches']
+ $this->_model = $this->getMockBuilder('Magento\ImportExport\Model\Import\Entity\AbstractEntity')
+ ->disableOriginalConstructor()
+ ->setMethods(['_saveValidatedBunches', 'getErrorAggregator'])
+ ->getMockForAbstractClass();
+
+ $this->_model->method('getErrorAggregator')->willReturn(
+ $this->getErrorAggregatorObject()
);
}
@@ -68,13 +69,15 @@ protected function _createSourceAdapterMock(array $columns)
* Test for method validateData()
*
* @covers \Magento\ImportExport\Model\Import\Entity\AbstractEntity::validateData
- * @expectedException \Magento\Framework\Exception\LocalizedException
- * @expectedExceptionMessage Columns number: "1" have empty headers
*/
public function testValidateDataEmptyColumnName()
{
$this->_createSourceAdapterMock(['']);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertArrayHasKey(
+ AbstractEntity::ERROR_CODE_COLUMN_EMPTY_HEADER,
+ $errorAggregator->getRowsGroupedByErrorCode()
+ );
}
/**
@@ -86,7 +89,8 @@ public function testValidateDataEmptyColumnNameForDeleteBehaviour()
{
$this->_createSourceAdapterMock(['']);
$this->_model->setParameters(['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE]);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertEquals(0, $errorAggregator->getErrorsCount());
}
/**
@@ -98,33 +102,38 @@ public function testValidateDataColumnNameWithWhitespacesForDeleteBehaviour()
{
$this->_createSourceAdapterMock([' ']);
$this->_model->setParameters(['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_DELETE]);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertEquals(0, $errorAggregator->getErrorsCount());
}
/**
* Test for method validateData()
*
* @covers \Magento\ImportExport\Model\Import\Entity\AbstractEntity::validateData
- * @expectedException \Magento\Framework\Exception\LocalizedException
- * @expectedExceptionMessage Columns number: "1" have empty headers
*/
public function testValidateDataColumnNameWithWhitespaces()
{
$this->_createSourceAdapterMock([' ']);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertArrayHasKey(
+ AbstractEntity::ERROR_CODE_COLUMN_EMPTY_HEADER,
+ $errorAggregator->getRowsGroupedByErrorCode()
+ );
}
/**
* Test for method validateData()
*
* @covers \Magento\ImportExport\Model\Import\Entity\AbstractEntity::validateData
- * @expectedException \Magento\Framework\Exception\LocalizedException
- * @expectedExceptionMessage Column names: "_test1" are invalid
*/
public function testValidateDataAttributeNames()
{
$this->_createSourceAdapterMock(['_test1']);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertArrayHasKey(
+ AbstractEntity::ERROR_CODE_COLUMN_NAME_INVALID,
+ $errorAggregator->getRowsGroupedByErrorCode()
+ );
}
/**
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/EavAbstractTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/EavAbstractTest.php
index 6add3933dbf53..321f2f455bbdc 100644
--- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/EavAbstractTest.php
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Entity/EavAbstractTest.php
@@ -9,7 +9,7 @@
*/
namespace Magento\ImportExport\Test\Unit\Model\Import\Entity;
-class EavAbstractTest extends \PHPUnit_Framework_TestCase
+class EavAbstractTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
* Entity type id
@@ -60,6 +60,8 @@ class EavAbstractTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
+ parent::setUp();
+
$this->_string = new \Magento\Framework\Stdlib\StringUtils();
$scopeConfig = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
@@ -96,6 +98,7 @@ protected function setUp()
$this->_importFactory,
$this->_resourceHelper,
$this->_resource,
+ $this->getErrorAggregatorObject(),
$this->_storeManager,
$this->_collectionFactory,
$this->_eavConfig,
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/EntityAbstractTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/EntityAbstractTest.php
index 21b65012b19db..d60b4c66b9f44 100644
--- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/EntityAbstractTest.php
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/EntityAbstractTest.php
@@ -13,7 +13,7 @@
use Magento\ImportExport\Model\Import\AbstractEntity;
-class EntityAbstractTest extends \PHPUnit_Framework_TestCase
+class EntityAbstractTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
* Abstract import entity model
@@ -35,10 +35,12 @@ class EntityAbstractTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
- $this->_model = $this->getMockForAbstractClass(
- 'Magento\ImportExport\Model\Import\AbstractEntity',
- $this->_getModelDependencies()
- );
+ parent::setUp();
+
+ $this->_model = $this->getMockBuilder('Magento\ImportExport\Model\Import\AbstractEntity')
+ ->setConstructorArgs($this->_getModelDependencies())
+ ->setMethods(['_saveValidatedBunches'])
+ ->getMockForAbstractClass();
}
protected function tearDown()
@@ -65,6 +67,7 @@ protected function _getModelDependencies()
'importFactory' => $importFactory,
'resourceHelper' => $resourceHelper,
'resource' => $resource,
+ 'errorAggregator' => $this->getErrorAggregatorObject(),
'data' => [
'data_source_model' => 'not_used',
'connection' => 'not_used',
@@ -109,14 +112,14 @@ public function testPrepareRowForDb()
*/
public function testAddRowError()
{
- $errorCode = 'error_code ';
+ $errorCode = 'error_code';
$errorColumnName = 'error_column';
- $this->_model->addRowError($errorCode . '%s', 0, $errorColumnName);
+ $this->_model->addRowError($errorCode . '%s', 0, $errorColumnName, $errorCode . ' %s');
- $this->assertGreaterThan(0, $this->_model->getErrorsCount());
+ $this->assertGreaterThan(0, $this->_model->getErrorAggregator()->getErrorsCount());
- $errors = $this->_model->getErrorMessages();
- $this->assertArrayHasKey($errorCode . $errorColumnName, $errors);
+ $errors = $this->_model->getErrorAggregator()->getRowsGroupedByErrorCode();
+ $this->assertArrayHasKey($errorCode . ' ' . $errorColumnName, $errors);
}
/**
@@ -152,32 +155,11 @@ public function testAddMessageTemplate()
$this->_model->addMessageTemplate($errorCode, $message);
$this->_model->addRowError($errorCode, 0);
- $errors = $this->_model->getErrorMessages();
+ $errors = $this->_model->getErrorAggregator()->getRowsGroupedByErrorCode();
$this->assertArrayHasKey($message, $errors);
}
- /**
- * Test for method isDataValid()
- */
- public function testIsDataValid()
- {
- /** @var $model AbstractEntity|\PHPUnit_Framework_MockObject_MockObject */
- $model = $this->getMockForAbstractClass(
- 'Magento\ImportExport\Model\Import\AbstractEntity',
- [],
- '',
- false,
- true,
- true,
- ['validateData']
- );
- $model->expects($this->any())->method('validateData');
- $this->assertTrue($model->isDataValid());
- $model->addRowError('test', 1);
- $this->assertFalse($model->isDataValid());
- }
-
/**
* Test for method isRowAllowedToImport()
*/
@@ -417,8 +399,7 @@ public function testIsAttributeValid(array $data)
$rowData[$attributeCode] = $data['invalid_value'];
$this->assertFalse($this->_model->isAttributeValid($attributeCode, $attributeParams, $rowData, 0));
-
- $this->assertEquals(1, $this->_model->getErrorsCount(), 'Wrong count of errors');
+ $this->assertEquals(1, $this->_model->getErrorAggregator()->getErrorsCount(), 'Wrong count of errors');
}
/**
@@ -525,7 +506,6 @@ protected function _getDataSet($code, $type, $validValue, $invalidValue, $isUniq
* Test for method validateData()
*
* @covers \Magento\ImportExport\Model\Import\AbstractEntity::validateData
- * @expectedException \Magento\Framework\Exception\LocalizedException
*/
public function testValidateDataPermanentAttributes()
{
@@ -537,43 +517,45 @@ public function testValidateDataPermanentAttributes()
$property->setAccessible(true);
$property->setValue($this->_model, $permanentAttributes);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertEquals(1, $errorAggregator->getErrorsCount());
}
/**
* Test for method validateData()
*
* @covers \Magento\ImportExport\Model\Import\AbstractEntity::validateData
- * @expectedException \Magento\Framework\Exception\LocalizedException
*/
public function testValidateDataEmptyColumnName()
{
$this->_createSourceAdapterMock(['']);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertEquals(1, $errorAggregator->getErrorsCount());
}
/**
* Test for method validateData()
*
* @covers \Magento\ImportExport\Model\Import\AbstractEntity::validateData
- * @expectedException \Magento\Framework\Exception\LocalizedException
*/
public function testValidateDataColumnNameWithWhitespaces()
{
$this->_createSourceAdapterMock([' ']);
$this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertEquals(1, $errorAggregator->getErrorsCount());
}
/**
* Test for method validateData()
*
* @covers \Magento\ImportExport\Model\Import\AbstractEntity::validateData
- * @expectedException \Magento\Framework\Exception\LocalizedException
*/
public function testValidateDataAttributeNames()
{
$this->_createSourceAdapterMock(['_test1']);
- $this->_model->validateData();
+ $errorAggregator = $this->_model->validateData();
+ $this->assertEquals(1, $errorAggregator->getErrorsCount());
}
/**
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorAggregatorTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorAggregatorTest.php
new file mode 100644
index 0000000000000..63b82e3693d2d
--- /dev/null
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorAggregatorTest.php
@@ -0,0 +1,400 @@
+processingErrorFactoryMock = $this->getMock(
+ '\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+
+ $this->processingErrorMock1 = $this->getMock(
+ '\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError',
+ null,
+ [],
+ '',
+ false
+ );
+
+ $this->processingErrorMock2 = $this->getMock(
+ '\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError',
+ null,
+ [],
+ '',
+ false
+ );
+
+ $this->processingErrorMock3 = $this->getMock(
+ '\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError',
+ null,
+ [],
+ '',
+ false
+ );
+
+ $this->processingErrorFactoryMock->expects($this->any())->method('create')->willReturnOnConsecutiveCalls(
+ $this->processingErrorMock1,
+ $this->processingErrorMock2,
+ $this->processingErrorMock3
+ );
+
+ $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+ $this->model = $objectManager->getObject(
+ '\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator',
+ [
+ 'errorFactory' => $this->processingErrorFactoryMock
+ ]
+ );
+ }
+
+ /**
+ * Test for method addError
+ */
+ public function testAddError()
+ {
+ $this->model->addError('systemException', 'critical', 7, 'Some column name', 'Message', 'Description');
+ }
+
+ /**
+ * Test for method addRowToSkip
+ */
+ public function testAddRowToSkip()
+ {
+ $this->model->addRowToSkip(7);
+ $result = $this->model->isRowInvalid(7);
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Test for method addErrorMessageTemplate
+ */
+ public function testAddErrorMessageTemplate()
+ {
+ $this->model->addErrorMessageTemplate('columnNotFound', 'Template: No column');
+ $this->model->addError('systemException');
+ $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', null, 'Description');
+ $this->model->addError('columnEmptyHeader', 'not-critical', 4, 'Some column name', 'No header', 'Description');
+ $result = $this->model->getRowsGroupedByErrorCode(['systemException']);
+ $expectedResult = [
+ 'Template: No column' => [8],
+ 'No header' => [5]
+ ];
+ $this->assertEquals($expectedResult, $result);
+ }
+
+ /**
+ * Test for method isRowInvalid. Expected true result.
+ */
+ public function testIsRowInvalidTrue()
+ {
+ $this->model->addError('systemException', 'critical', 7, 'Some column name', 'Message', 'Description');
+ $result = $this->model->isRowInvalid(7);
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Test for method isRowInvalid. Expected false result.
+ */
+ public function testIsRowInvalidFalse()
+ {
+ $this->model->addError('systemException');
+ $result = $this->model->isRowInvalid(8);
+ $this->assertFalse($result);
+ }
+
+ /**
+ * Test for method getInvalidRowsCount. Expected 0 invalid rows.
+ */
+ public function testGetInvalidRowsCountZero()
+ {
+ $rowsNumber = $this->model->getInvalidRowsCount();
+ $this->assertEquals($rowsNumber, 0);
+ }
+
+ /**
+ * Test for method getInvalidRowsCount. Expected 1 invalid row.
+ */
+ public function testGetInvalidRowsCountOne()
+ {
+ $this->model->addError('systemException', 'critical', 7, 'Some column name', 'Message', 'Description');
+ $rowsNumber = $this->model->getInvalidRowsCount();
+ $this->assertEquals($rowsNumber, 1);
+ }
+
+ /**
+ * Test for method getInvalidRowsCount. Expected 2 invalid rows.
+ */
+ public function testGetInvalidRowsCountTwo()
+ {
+ $this->model->addError('systemException');
+ $this->model->addError('systemException', 'critical', 8, 'Some column name', 'Message', 'Description');
+ $this->model->addError('systemException', 'critical', 7, 'Some column name', 'Message', 'Description');
+ $rowsNumber = $this->model->getInvalidRowsCount();
+ $this->assertEquals($rowsNumber, 2);
+ }
+
+ /**
+ * Test for method initValidationStrategy.
+ */
+ public function testInitValidationStrategy()
+ {
+ $this->model->initValidationStrategy('validation-stop-on-errors', 5);
+ $this->assertEquals(5, $this->model->getAllowedErrorsCount());
+ }
+
+ /**
+ * Test for method initValidationStrategy.
+ */
+ public function testInitValidationStrategyExceed()
+ {
+ $this->model->addError('systemException', 'not-critical', 7, 'Some column name', 'Message', 'Description');
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $this->model->addError('systemException', 'not-critical', 2, 'Some column name', 'Message', 'Description');
+ $this->model->initValidationStrategy('validation-stop-on-errors', 2);
+ $result = $this->model->isErrorLimitExceeded();
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Test for method initValidationStrategy. Expected exeption due null incoming parameter
+ */
+ public function testInitValidationStrategyException()
+ {
+ $this->setExpectedException('\Magento\Framework\Exception\LocalizedException');
+ $this->model->initValidationStrategy(null);
+ }
+
+ /**
+ * Test for method isErrorLimitExceeded. Expects error limit exceeded.
+ */
+ public function testIsErrorLimitExceededTrue()
+ {
+ $this->model->addError('systemException');
+ $this->model->addError('systemException', 'not-critical', 7, 'Some column name', 'Message', 'Description');
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $result = $this->model->isErrorLimitExceeded();
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Test for method isErrorLimitExceeded. Unexpects error limit exceeded.
+ */
+ public function testIsErrorLimitExceededFalse()
+ {
+ $this->model->addError('systemException');
+ $this->model->addError('systemException', 'critical', 7, 'Some column name', 'Message', 'Description');
+ $this->model->addError('systemException', 'critical', 4, 'Some column name', 'Message', 'Description');
+ $result = $this->model->isErrorLimitExceeded();
+ $this->assertFalse($result);
+ }
+
+ /**
+ * Test for method hasFatalExceptions.
+ */
+ public function testHasFatalExceptionsTrue()
+ {
+ $this->model->addError('systemException');
+ $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', 'Message', 'Description');
+ $this->model->addError('columnEmptyHeader', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $result = $this->model->hasFatalExceptions();
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Test for method hasFatalExceptions. Expects no any fatal exceptions
+ */
+ public function testHasFatalExceptionsFalse()
+ {
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $result = $this->model->hasFatalExceptions();
+ $this->assertFalse($result);
+ }
+
+ /**
+ * Test for method hasToBeTerminated. Unexpects any errors and termination.
+ */
+ public function testHasToBeTerminatedFalse()
+ {
+ $result = $this->model->hasToBeTerminated();
+ $this->assertFalse($result);
+ }
+
+ /**
+ * Test for method hasToBeTerminated. Expects errors and execute termination.
+ */
+ public function testHasToBeTerminatedTrue()
+ {
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $result = $this->model->hasToBeTerminated();
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Test for method getAllErrors
+ */
+ public function testGetAllErrors()
+ {
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $this->model->addError('systemException', 'not-critical', 5, 'Some column name', 'Message', 'Description');
+ $this->model->addError('systemException', 'not-critical', 6, 'Some column name', 'Message', 'Description');
+ $result = $this->model->getAllErrors();
+ //check if is array of objects
+ $this->assertInternalType('array', $result);
+ $this->assertCount(3, $result);
+ $this->assertInstanceOf('\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError', $result[0]);
+ }
+
+ /**
+ * Test for method getErrorByRowNumber
+ */
+ public function testGetErrorByRowNumber()
+ {
+ $this->model->addError('systemException1', 'not-critical', 1);
+ $this->model->addError('systemException2', 'not-critical', 1);
+ $this->model->addError('systemException3', 'not-critical', 2);
+ $result = $this->model->getErrorByRowNumber(1);
+
+ $this->assertInternalType('array', $result);
+ $this->assertCount(2, $result);
+ $this->assertInstanceOf('\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError', $result[0]);
+ $this->assertInstanceOf('\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError', $result[1]);
+ $this->assertEquals('systemException1', $result[0]->getErrorCode());
+ $this->assertEquals('systemException2', $result[1]->getErrorCode());
+ }
+
+ /**
+ * Test logic to prevent adding an identical error more than once.
+ * The error has to have the same error code for the same row number
+ */
+ public function testAddTheSameErrorTwice()
+ {
+ $this->model->addError('systemException', 'not-critical', 1);
+ $this->model->addError('systemException', 'not-critical', 1);
+ $result = $this->model->getErrorByRowNumber(1);
+
+ $this->assertCount(1, $result);
+ $this->assertEquals(1, $this->model->getErrorsCount());
+ }
+
+ /**
+ * Test for method getErrorsByCode. Expects receive errors with code, which present in incomming parameter.
+ */
+ public function testGetErrorsByCodeInArray()
+ {
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', 'No column', 'Description');
+ $this->model->addError('systemException', 'not-critical', 9, 'Some column name', 'Message', 'Description');
+ $result = $this->model->getErrorsByCode(['systemException']);
+ $this->assertCount(2, $result);
+ }
+
+ /**
+ * Test for method getErrorsByCode. Unexpects receive errors with code, which present in incomming parameter.
+ */
+ public function testGetErrorsByCodeNotInArray()
+ {
+ $this->model->addError('columnNotFound', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', 'No column', 'Description');
+ $this->model->addError('columnEmptyHeader', 'not-critical', 5, 'Some column name', 'No header', 'Description');
+ $result = $this->model->getErrorsByCode(['systemException']);
+ $this->assertCount(0, $result);
+ }
+
+ /**
+ * Test for method getRowsGroupedByErrorCode. Expects errors.
+ */
+ public function testGetRowsGroupedByErrorCodeWithErrors()
+ {
+ $this->model->addError('systemException');
+ $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', 'No column', 'Description');
+ $this->model->addError('columnEmptyHeader', 'not-critical', 4, 'Some column name', 'No header', 'Description');
+ $result = $this->model->getRowsGroupedByErrorCode(['systemException']);
+ $expectedResult = [
+ 'No column' => [8],
+ 'No header' => [5]
+ ];
+ $this->assertEquals($expectedResult, $result);
+ }
+
+ /**
+ * Test for method getRowsGroupedByErrorCode. Unexpects errors.
+ */
+ public function testGetRowsGroupedByErrorCodeNoErrors()
+ {
+ $result = $this->model->getRowsGroupedByErrorCode();
+ $this->assertInternalType('array', $result);
+ $this->assertCount(0, $result);
+ }
+
+ /**
+ * Test for method getAllowedErrorsCount.
+ */
+ public function testGetAllowedErrorsCount()
+ {
+ $this->assertEquals($this->model->getAllowedErrorsCount(), 0);
+ }
+
+ /**
+ * Test for method clear.
+ */
+ public function testClear()
+ {
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', 'No column', 'Description');
+ $this->model->clear();
+ $result = $this->model->getAllErrors();
+ $this->assertEquals([], $result);
+ }
+
+ /**
+ * Test for method getErrorsCount
+ */
+ public function testGetErrorsCount()
+ {
+ $this->model->addError('systemException', 'not-critical', 4, 'Some column name', 'Message', 'Description');
+ $this->model->addError('columnNotFound', 'critical', 7, 'Some column name', 'No column', 'Description');
+ $this->model->addError('systemException', 'not-critical', 9, 'Some column name', 'Message', 'Description');
+ $result = $this->model->getErrorsCount(['critical']);
+ $this->assertEquals($result, 1);
+ }
+}
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorTest.php
new file mode 100644
index 0000000000000..55aa06725d893
--- /dev/null
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/ErrorProcessing/ProcessingErrorTest.php
@@ -0,0 +1,283 @@
+model = $objectManager->getObject('\Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError');
+ }
+
+ /**
+ * Test for method init.
+ *
+ * @dataProvider errorMessageInfo
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ */
+ public function testInit($initData)
+ {
+ $errorLevel = isset($initData['errorLevel']) ? $initData['errorLevel'] : null;
+ $rowNumber = isset($initData['rowNumber']) ? $initData['rowNumber'] : null;
+ $columnName = isset($initData['columnName']) ? $initData['columnName'] : null;
+ $errorMessage = isset($initData['errorMessage']) ? $initData['errorMessage'] : null;
+ $errorDescription = isset($initData['errorDescription']) ? $initData['errorDescription'] : null;
+
+ $this->model->init(
+ $initData['errorCode'],
+ $errorLevel,
+ $rowNumber,
+ $columnName,
+ $errorMessage,
+ $errorDescription
+ );
+ }
+
+ /**
+ * Data for method testInit
+ *
+ * @return array
+ */
+ public function errorMessageInfo()
+ {
+ return [
+ [
+ [
+ 'errorCode' => 5,
+ 'errorLevel' => 'critical',
+ 'rowNumber' => 7,
+ 'columnName' => 25,
+ 'errorMessage' => 'some error message',
+ 'errorDescription' => 'some error description'
+ ]
+ ],
+ [
+ [
+ 'errorCode' => 5,
+ 'errorLevel' => null,
+ 'rowNumber' => null,
+ 'columnName' => null,
+ 'errorMessage' => null,
+ 'errorDescription' => null
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * Test for method getErrorCode
+ *
+ * @dataProvider errorCodeData
+ */
+ public function testGetErrorCode($data, $expectedValue)
+ {
+ $this->testInit($data);
+ $result = $this->model->getErrorCode();
+ $this->assertEquals($result, $expectedValue);
+ }
+
+ /**
+ * Data for method testGetErrorCode
+ *
+ * @return array
+ */
+ public function errorCodeData()
+ {
+ return [
+ [
+ ['errorCode' => 5],
+ 5
+ ],
+ [
+ ['errorCode' => null],
+ null
+ ],
+ ];
+ }
+
+ /**
+ * Test for method getErrorMessage
+ *
+ * @dataProvider errorMessageData
+ */
+ public function testGetErrorMessage($data, $expectedValue)
+ {
+ $this->testInit($data);
+ $result = $this->model->getErrorMessage();
+ $this->assertEquals($result, $expectedValue);
+ }
+
+ /**
+ * Data for method testGetErrorMessage
+ *
+ * @return array
+ */
+ public function errorMessageData()
+ {
+ return [
+ [
+ ['errorCode' => 5, 'errorMessage' => 'Some error message'],
+ 'Some error message'
+ ],
+ [
+ ['errorCode' => 5],
+ null
+ ],
+ ];
+ }
+
+ /**
+ * Test for method getRowNumber
+ *
+ * @dataProvider rowNumberData
+ */
+ public function testGetRowNumber($data, $expectedValue)
+ {
+ $this->testInit($data);
+ $result = $this->model->getRowNumber();
+ $this->assertEquals($result, $expectedValue);
+ }
+
+ /**
+ * Data for method testGetRowNumber
+ *
+ * @return array
+ */
+ public function rowNumberData()
+ {
+ return [
+ [
+ ['errorCode' => 5, 'errorMessage' => 'Some error message', 'rowNumber' => 43],
+ 43
+ ],
+ [
+ ['errorCode' => 5],
+ null
+ ],
+ ];
+ }
+
+ /**
+ * Test for method getColumnName
+ *
+ * @dataProvider columnNameData
+ */
+ public function testGetColumnName($data, $expectedValue)
+ {
+ $this->testInit($data);
+ $result = $this->model->getColumnName();
+ $this->assertEquals($result, $expectedValue);
+ }
+
+ /**
+ * Data for method testGetColumnName
+ *
+ * @return array
+ */
+ public function columnNameData()
+ {
+ return [
+ [
+ [
+ 'errorCode' => 5,
+ 'errorMessage' => 'Some error message',
+ 'rowNumber' => 43,
+ 'columnName' => 'Some column name'
+ ],
+ 'Some column name'
+ ],
+ [
+ ['errorCode' => 5],
+ null
+ ],
+ ];
+ }
+
+ /**
+ * Test for method getErrorLevel
+ *
+ * @dataProvider errorLevelData
+ */
+ public function testGetErrorLevel($data, $expectedValue)
+ {
+ $this->testInit($data);
+ $result = $this->model->getErrorLevel();
+ $this->assertEquals($result, $expectedValue);
+ }
+
+ /**
+ * Data for method testGetErrorLevel
+ *
+ * @return array
+ */
+ public function errorLevelData()
+ {
+ return [
+ [
+ [
+ 'errorCode' => 5,
+ 'errorMessage' => 'Some error message',
+ 'rowNumber' => 43,
+ 'columnName' => 'Some column name',
+ 'errorLevel' => 'critical'
+ ],
+ 'critical'
+ ],
+ [
+ ['errorCode' => 5],
+ null
+ ],
+ ];
+ }
+
+ /**
+ * Test for method getErrorDescription
+ *
+ * @dataProvider errorDescriptionData
+ */
+ public function testGetErrorDescription($data, $expectedValue)
+ {
+ $this->testInit($data);
+ $result = $this->model->getErrorDescription();
+ $this->assertEquals($result, $expectedValue);
+ }
+
+ /**
+ * Data for method testGetErrorDescription
+ *
+ * @return array
+ */
+ public function errorDescriptionData()
+ {
+ return [
+ [
+ [
+ 'errorCode' => 5,
+ 'errorMessage' => 'Some error message',
+ 'rowNumber' => 43,
+ 'columnName' => 'Some column name',
+ 'errorLevel' => 'critical',
+ 'errorDescription' => 'Some error description'
+ ],
+ 'Some error description'
+ ],
+ [
+ ['errorCode' => 5],
+ null
+ ],
+ ];
+ }
+}
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Source/CsvTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Source/CsvTest.php
index 25e6e1a441c08..015809a8d9620 100644
--- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Source/CsvTest.php
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Source/CsvTest.php
@@ -111,6 +111,10 @@ public function optionalArgsDataProvider()
];
}
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage wrongColumnsNumber
+ */
public function testRewind()
{
$this->_directoryMock->expects(
@@ -139,6 +143,6 @@ public function testRewind()
$model->next();
$model->next();
$this->assertSame(2, $model->key());
- $this->assertSame(['column1' => '5', 'column2' => ''], $model->current());
+ $model->current();
}
}
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/SourceAbstractTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/SourceAbstractTest.php
index 225d63b42a06f..ac17ff543661a 100644
--- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/SourceAbstractTest.php
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/SourceAbstractTest.php
@@ -43,9 +43,12 @@ public function testGetColNames()
$this->assertSame(['key1', 'key2', 'key3'], $this->_model->getColNames());
}
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage wrongColumnsNumber
+ */
public function testIteratorInterface()
{
- $this->assertSame(['key1' => '', 'key2' => '', 'key3' => ''], $this->_model->current());
$this->assertSame(-1, $this->_model->key());
$this->assertFalse($this->_model->valid());
@@ -54,7 +57,7 @@ public function testIteratorInterface()
)->method(
'_getNextRow'
)->will(
- $this->onConsecutiveCalls([1, 2, 3], [4, 5], [6, 7, 8], false)
+ $this->onConsecutiveCalls([1, 2, 3], [4, 5, 5], [6, 7, 8])
);
$data = [];
foreach ($this->_model as $key => $value) {
@@ -63,11 +66,12 @@ public function testIteratorInterface()
$this->assertSame(
[
['key1' => 1, 'key2' => 2, 'key3' => 3],
- ['key1' => 4, 'key2' => 5, 'key3' => ''],
+ ['key1' => 4, 'key2' => 5, 'key3' => 5],
['key1' => 6, 'key2' => 7, 'key3' => 8],
],
$data
);
+ $this->_model->current();
}
public function testSeekableInterface()
@@ -81,12 +85,12 @@ public function testSeekableInterface()
)->method(
'_getNextRow'
)->will(
- $this->onConsecutiveCalls([1, 2, 3], [4, 5], [6, 7, 8], [1, 2, 3], [4, 5])
+ $this->onConsecutiveCalls([1, 2, 3], [4, 5, 5], [6, 7, 8], [1, 2, 3], [4, 5, 5])
);
$this->_model->seek(2);
$this->assertSame(['key1' => 6, 'key2' => 7, 'key3' => 8], $this->_model->current());
$this->_model->seek(1);
- $this->assertSame(['key1' => 4, 'key2' => 5, 'key3' => ''], $this->_model->current());
+ $this->assertSame(['key1' => 4, 'key2' => 5, 'key3' => 5], $this->_model->current());
}
/**
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php
index 66b249b836222..9e65d5516c612 100644
--- a/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php
@@ -11,7 +11,7 @@
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.TooManyFields)
*/
-class ImportTest extends \PHPUnit_Framework_TestCase
+class ImportTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractImportTestCase
{
/**
@@ -110,6 +110,8 @@ class ImportTest extends \PHPUnit_Framework_TestCase
*/
public function setUp()
{
+ parent::setUp();
+
$logger = $this->getMockBuilder('\Psr\Log\LoggerInterface')
->disableOriginalConstructor()
->getMock();
@@ -126,16 +128,18 @@ public function setUp()
->disableOriginalConstructor()
->setMethods(['getEntityTypeCode', 'getBehavior', 'getEntities'])
->getMockForAbstractClass();
- $this->_entityFactory = $this->getMock(
- '\Magento\ImportExport\Model\Import\Entity\Factory',
- ['create', 'isNeedToLogInHistory'],
- [],
- '',
- false
- );
- $this->getMockBuilder('\Magento\ImportExport\Model\Import\Entity\Factory')
+ $this->_entityFactory = $this->getMockBuilder('\Magento\ImportExport\Model\Import\Entity\Factory')
->disableOriginalConstructor()
->getMock();
+ $this->_entityAdapter = $this->getMockBuilder('\Magento\ImportExport\Model\Import\Entity\AbstractEntity')
+ ->disableOriginalConstructor()
+ ->setMethods(['importData', '_saveValidatedBunches', 'getErrorAggregator'])
+ ->getMockForAbstractClass();
+ $this->_entityAdapter->method('getErrorAggregator')->willReturn(
+ $this->getErrorAggregatorObject(['initValidationStrategy'])
+ );
+ $this->_entityFactory->method('create')->willReturn($this->_entityAdapter);
+
$this->_importData = $this->getMockBuilder('\Magento\ImportExport\Model\Resource\Import\Data')
->disableOriginalConstructor()
->getMock();
@@ -195,22 +199,17 @@ public function setUp()
])
->setMethods([
'getDataSourceModel',
- '_getEntityAdapter',
'setData',
'getProcessedEntitiesCount',
'getProcessedRowsCount',
- 'getInvalidRowsCount',
- 'getErrorsCount',
'getEntity',
'getBehavior',
'isReportEntityType',
+ '_getEntityAdapter'
])
->getMock();
$this->setPropertyValue($this->import, '_varDirectory', $this->_varDirectory);
- $this->_entityAdapter = $this->getMockBuilder('\Magento\ImportExport\Model\Import\Entity\AbstractEntity')
- ->disableOriginalConstructor()
- ->setMethods(['importData'])
- ->getMockForAbstractClass();
+
}
/**
@@ -238,34 +237,36 @@ public function testImportSource()
$this->import->expects($this->any())
->method('addLogComment')
->with($this->isInstanceOf($phraseClass));
- $this->_entityAdapter->expects($this->once())
+ $this->_entityAdapter->expects($this->any())
->method('importData')
->will($this->returnSelf());
- $this->import->expects($this->once())
+ $this->import->expects($this->any())
->method('_getEntityAdapter')
->will($this->returnValue($this->_entityAdapter));
-
+ $this->_importConfig
+ ->expects($this->any())
+ ->method('getEntities')
+ ->willReturn(
+ [
+ $entityTypeCode => [
+ 'model' => $entityTypeCode
+ ]
+ ]
+ );
$importOnceMethodsReturnNull = [
- 'getEntity',
- 'getBehavior',
- 'getProcessedRowsCount',
- 'getProcessedEntitiesCount',
- 'getInvalidRowsCount',
- 'getErrorsCount',
+ 'getBehavior'
];
foreach ($importOnceMethodsReturnNull as $method) {
$this->import->expects($this->once())->method($method)->will($this->returnValue(null));
}
- $this->import->importSource();
+ $this->assertEquals(true, $this->import->importSource());
}
/**
* Test importSource with expected exception
*
- * @expectedException \Magento\Framework\Exception\AlreadyExistsException
- * @expectedExceptionMessage URL key for specified store already exists.
*/
public function testImportSourceException()
{
@@ -277,7 +278,7 @@ public function testImportSourceException()
->method('getEntityTypeCode')
->will($this->returnValue($entityTypeCode));
$behaviour = 'behaviour';
- $this->_importData->expects($this->once())
+ $this->_importData->expects($this->any())
->method('getBehavior')
->will($this->returnValue($behaviour));
$this->import->expects($this->any())
@@ -291,14 +292,13 @@ public function testImportSourceException()
$this->import->expects($this->any())
->method('addLogComment')
->with($this->isInstanceOf($phraseClass));
- $this->_entityAdapter->expects($this->once())
+ $this->_entityAdapter->expects($this->any())
->method('importData')
->will($this->throwException($exceptionMock));
- $this->import->expects($this->once())
+ $this->import->expects($this->any())
->method('_getEntityAdapter')
->will($this->returnValue($this->_entityAdapter));
$importOnceMethodsReturnNull = [
- 'getEntity',
'getBehavior',
];
diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Report/CsvTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Report/CsvTest.php
new file mode 100644
index 0000000000000..ed812fd387504
--- /dev/null
+++ b/app/code/Magento/ImportExport/Test/Unit/Model/Report/CsvTest.php
@@ -0,0 +1,114 @@
+reportHelperMock = $this->getMock('\Magento\ImportExport\Helper\Report', [], [], '', false);
+
+ $this->outputCsvFactoryMock = $this->getMock(
+ '\Magento\ImportExport\Model\Export\Adapter\CsvFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+ $this->outputCsvMock = $this->getMock('\Magento\ImportExport\Model\Export\Adapter\Csv', [], [], '', false);
+ $this->outputCsvFactoryMock->expects($this->any())->method('create')->willReturn($this->outputCsvMock);
+
+ $this->sourceCsvFactoryMock = $this->getMock(
+ '\Magento\ImportExport\Model\Import\Source\CsvFactory',
+ ['create'],
+ [],
+ '',
+ false
+ );
+ $this->sourceCsvMock = $this->getMock('\Magento\ImportExport\Model\Import\Source\Csv', [], [], '', false);
+ $this->sourceCsvMock->expects($this->any())->method('valid')->willReturnOnConsecutiveCalls(true, true, false);
+ $this->sourceCsvMock->expects($this->any())->method('current')->willReturnOnConsecutiveCalls(
+ [23 => 'first error'],
+ [27 => 'second error']
+ );
+ $this->sourceCsvFactoryMock->expects($this->any())->method('create')->willReturn($this->sourceCsvMock);
+
+ $this->filesystemMock = $this->getMock('\Magento\Framework\Filesystem', [], [], '', false);
+
+
+ $this->csvModel = $objectManager->getObject(
+ '\Magento\ImportExport\Model\Report\Csv',
+ [
+ 'reportHelper' => $this->reportHelperMock,
+ 'sourceCsvFactory' => $this->sourceCsvFactoryMock,
+ 'outputCsvFactory' => $this->outputCsvFactoryMock,
+ 'filesystem' => $this->filesystemMock
+ ]
+ );
+ }
+
+ public function testCreateReport()
+ {
+ $errorAggregatorMock = $this->getMock(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregator',
+ [],
+ [],
+ '',
+ false
+ );
+ $errorProcessingMock = $this->getMock(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing',
+ ['getErrorMessage'],
+ [],
+ '',
+ false
+ );
+ $errorProcessingMock->expects($this->any())->method('getErrorMessage')->willReturn('some_error_message');
+ $errorAggregatorMock->expects($this->any())->method('getErrorByRowNumber')->willReturn([$errorProcessingMock]);
+ $this->sourceCsvMock->expects($this->any())->method('getColNames')->willReturn([]);
+
+ $name = $this->csvModel->createReport('some_file_name', $errorAggregatorMock, true);
+
+ $this->assertEquals($name, 'some_file_name_error_report.csv');
+ }
+}
diff --git a/app/code/Magento/ImportExport/etc/di.xml b/app/code/Magento/ImportExport/etc/di.xml
index bf332bd3080a3..88e5915a35a2e 100644
--- a/app/code/Magento/ImportExport/etc/di.xml
+++ b/app/code/Magento/ImportExport/etc/di.xml
@@ -8,6 +8,8 @@
+
+
diff --git a/app/code/Magento/ImportExport/etc/module.xml b/app/code/Magento/ImportExport/etc/module.xml
index 4dad36db35038..e072148a1dd4b 100644
--- a/app/code/Magento/ImportExport/etc/module.xml
+++ b/app/code/Magento/ImportExport/etc/module.xml
@@ -6,6 +6,6 @@
*/
-->
-
+
diff --git a/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml b/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml
index 839fdb5f7ecb9..22df8f655b3da 100644
--- a/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml
+++ b/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml
@@ -54,6 +54,18 @@
Magento\ImportExport\Block\Adminhtml\Grid\Column\Renderer\Download
+
+
+ Error File
+ type
+ 0
+ 0
+ center
+ action
+ Magento\ImportExport\Block\Adminhtml\Grid\Column\Renderer\Error
+
+
+
Execution Time
diff --git a/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_import_index.xml b/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_import_index.xml
index ba7694ea26659..2168ec3cd3416 100644
--- a/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_import_index.xml
+++ b/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_import_index.xml
@@ -6,6 +6,9 @@
*/
-->
+
+
+
diff --git a/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml b/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml
index c7993391938a7..ec4d7ec59ed64 100644
--- a/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml
+++ b/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml
@@ -31,6 +31,12 @@ require(['jquery', 'prototype'], function(jQuery){
*/
entityBehaviors: getEntityBehaviors() ?>,
+ /**
+ * Behaviour notes for import entities
+ * @type {Array}
+ */
+ entityBehaviorsNotes: getEntityBehaviorsNotes() ?>,
+
/**
* Base url
* @type {string}
@@ -129,6 +135,25 @@ require(['jquery', 'prototype'], function(jQuery){
this.showUploadFile(false);
this.showSampleFile(false);
}
+ this.handleImportBehaviorSelector();
+ },
+
+ /**
+ * Handle value change in behavior selector
+ */
+ handleImportBehaviorSelector: function() {
+ var entity = jQuery('#entity');
+ if (entity && entity.val()) {
+ var notes = this.entityBehaviorsNotes[entity.val()];
+ var requiredBehavior = this.entityBehaviors[entity.val()];
+ var behaviorInput = jQuery('#' + requiredBehavior);
+ var behavior = behaviorInput && behaviorInput.val();
+ if (behavior && notes[behavior]) {
+ jQuery('#' + requiredBehavior + '-note').html(notes[behavior]);
+ } else {
+ jQuery('#' + requiredBehavior + '-note').html('');
+ }
+ }
},
/**
diff --git a/app/code/Magento/ImportExport/view/adminhtml/web/css/importexport.css b/app/code/Magento/ImportExport/view/adminhtml/web/css/importexport.css
new file mode 100644
index 0000000000000..968e2b74fba06
--- /dev/null
+++ b/app/code/Magento/ImportExport/view/adminhtml/web/css/importexport.css
@@ -0,0 +1,15 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+.import-error-wrapper {
+ margin-top: 10px;
+}
+
+.import-error-list {
+ max-height: 120px;
+ overflow-y: auto;
+ padding: 10px;
+ background-color: #fcc;
+ margin: 10px 0 0 0;
+}
diff --git a/app/code/Magento/Indexer/Console/Command/AbstractIndexerCommand.php b/app/code/Magento/Indexer/Console/Command/AbstractIndexerCommand.php
index 799cbde5e83f0..cdd3ee2541d8b 100644
--- a/app/code/Magento/Indexer/Console/Command/AbstractIndexerCommand.php
+++ b/app/code/Magento/Indexer/Console/Command/AbstractIndexerCommand.php
@@ -62,7 +62,7 @@ protected function getObjectManager()
/** @var \Magento\Framework\App\State $appState */
$appState = $this->objectManager->get('Magento\Framework\App\State');
$appState->setAreaCode($area);
- $configLoader = $this->objectManager->get('Magento\Framework\App\ObjectManager\ConfigLoader');
+ $configLoader = $this->objectManager->get('Magento\Framework\ObjectManager\ConfigLoaderInterface');
$this->objectManager->configure($configLoader->load($area));
}
return $this->objectManager;
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php
index a6bca473428ff..0179895599cd5 100644
--- a/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/AbstractIndexerCommandCommonSetup.php
@@ -53,7 +53,7 @@ protected function setUp()
->method('get')
->will($this->returnValueMap([
['Magento\Framework\App\State', $this->stateMock],
- ['Magento\Framework\App\ObjectManager\ConfigLoader', $this->configLoaderMock]
+ ['Magento\Framework\ObjectManager\ConfigLoaderInterface', $this->configLoaderMock]
]));
$this->collectionFactory = $this->getMockBuilder('Magento\Indexer\Model\Indexer\CollectionFactory')
diff --git a/app/code/Magento/PageCache/etc/varnish3.vcl b/app/code/Magento/PageCache/etc/varnish3.vcl
index 0b6651fbc0cd4..678244bb6f790 100644
--- a/app/code/Magento/PageCache/etc/varnish3.vcl
+++ b/app/code/Magento/PageCache/etc/varnish3.vcl
@@ -80,8 +80,8 @@ sub vcl_fetch {
set beresp.do_gzip = true;
}
- # cache only successfully responses
- if (beresp.status != 200) {
+ # cache only successfully responses and 404s
+ if (beresp.status != 200 && beresp.status != 404) {
set beresp.ttl = 0s;
return (hit_for_pass);
} elsif (beresp.http.Cache-Control ~ "private") {
diff --git a/app/code/Magento/PageCache/etc/varnish4.vcl b/app/code/Magento/PageCache/etc/varnish4.vcl
index 2a3db0b42339d..d9ff63e5e9fa2 100644
--- a/app/code/Magento/PageCache/etc/varnish4.vcl
+++ b/app/code/Magento/PageCache/etc/varnish4.vcl
@@ -71,8 +71,8 @@ sub vcl_backend_response {
set beresp.do_gzip = true;
}
- # cache only successfully responses
- if (beresp.status != 200) {
+ # cache only successfully responses and 404s
+ if (beresp.status != 200 && beresp.status != 404) {
set beresp.ttl = 0s;
set beresp.uncacheable = true;
return (deliver);
diff --git a/app/code/Magento/Paypal/Setup/InstallData.php b/app/code/Magento/Paypal/Setup/InstallData.php
index 50272f5adaae7..c839b862fdab6 100644
--- a/app/code/Magento/Paypal/Setup/InstallData.php
+++ b/app/code/Magento/Paypal/Setup/InstallData.php
@@ -48,8 +48,8 @@ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface
*/
$setup->startSetup();
- $quoteInstaller = $this->quoteSetupFactory->create();
- $salesInstaller = $this->salesSetupFactory->create();
+ $quoteInstaller = $this->quoteSetupFactory->create(['resourceName' => 'quote_setup', 'setup' => $setup]);
+ $salesInstaller = $this->salesSetupFactory->create(['resourceName' => 'sales_setup', 'setup' => $setup]);
/**
* Add paypal attributes to the:
* - sales/flat_quote_payment_item table
diff --git a/app/code/Magento/Quote/Setup/InstallData.php b/app/code/Magento/Quote/Setup/InstallData.php
index 8a6d0f150198f..2d65d3ec2f746 100644
--- a/app/code/Magento/Quote/Setup/InstallData.php
+++ b/app/code/Magento/Quote/Setup/InstallData.php
@@ -39,7 +39,7 @@ public function __construct(QuoteSetupFactory $setupFactory)
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
/** @var QuoteSetup $quoteSetup */
- $quoteSetup = $this->quoteSetupFactory->create();
+ $quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]);
/**
* Install eav entity types to the eav/entity_type table
diff --git a/app/code/Magento/Sales/Setup/InstallData.php b/app/code/Magento/Sales/Setup/InstallData.php
index 2dac7727cef40..44d0766318ccc 100644
--- a/app/code/Magento/Sales/Setup/InstallData.php
+++ b/app/code/Magento/Sales/Setup/InstallData.php
@@ -58,7 +58,7 @@ public function __construct(
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
/** @var \Magento\Sales\Setup\SalesSetup $salesSetup */
- $salesSetup = $this->salesSetupFactory->create();
+ $salesSetup = $this->salesSetupFactory->create(['setup' => $setup]);
/**
* Install eav entity types to the eav/entity_type table
diff --git a/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/OrderActionsTest.php b/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/OrderActionsTest.php
deleted file mode 100644
index 71fbaf852cb55..0000000000000
--- a/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/OrderActionsTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
-urlBuilder = $this->getMockForAbstractClass('Magento\Framework\UrlInterface');
- $this->model = $objectManager->getObject(
- 'Magento\Sales\Ui\Component\Listing\Column\OrderActions',
- ['urlBuilder' => $this->urlBuilder]
- );
- }
-
- public function testPrepareDataSource()
- {
- $entityId = 1;
- $url = 'url';
- $itemName = 'itemName';
- $oldItemValue = 'itemValue';
- $newItemValue = [
- 'view' => [
- 'href' => $url,
- 'label' => __('View')
- ]
- ];
- $dataSource = [
- 'data' => [
- 'items' => [
- [
- $itemName => $oldItemValue,
- 'entity_id' => $entityId
- ]
- ]
- ]
- ];
-
- $this->urlBuilder->expects($this->once())
- ->method('getUrl')
- ->with(OrderActions::URL_PATH_VIEW, ['order_id' => $entityId])
- ->willReturn($url);
-
- $this->model->setData('name', $itemName);
- $this->model->prepareDataSource($dataSource);
- $this->assertEquals($newItemValue, $dataSource['data']['items'][0][$itemName]);
- }
-}
diff --git a/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/ViewActionTest.php b/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/ViewActionTest.php
new file mode 100644
index 0000000000000..bf6e0ee16bd6c
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Ui/Component/Listing/Column/ViewActionTest.php
@@ -0,0 +1,98 @@
+objectManager = new ObjectManager($this);
+ $this->urlBuilder = $this->getMockForAbstractClass('Magento\Framework\UrlInterface');
+ }
+
+ /**
+ * @param array $data
+ * @param array $dataSourceItems
+ * @param array $expectedDataSourceItems
+ * @param string $expectedUrlPath
+ * @param array $expectedUrlParam
+ * @dataProvider prepareDataSourceDataProvider
+ */
+ public function testPrepareDataSource(
+ $data,
+ $dataSourceItems,
+ $expectedDataSourceItems,
+ $expectedUrlPath,
+ $expectedUrlParam
+ ) {
+ $this->model = $this->objectManager->getObject(
+ 'Magento\Sales\Ui\Component\Listing\Column\ViewAction',
+ [
+ 'urlBuilder' => $this->urlBuilder,
+ 'data' => $data
+ ]
+ );
+
+ $this->urlBuilder->expects($this->once())
+ ->method('getUrl')
+ ->with($expectedUrlPath, $expectedUrlParam)
+ ->willReturn('url');
+
+ $dataSource = [
+ 'data' => [
+ 'items' => $dataSourceItems
+ ]
+ ];
+ $this->model->prepareDataSource($dataSource);
+ $this->assertEquals($expectedDataSourceItems, $dataSource['data']['items']);
+ }
+
+ /**
+ * Data provider for testPrepareDataSource
+ * @return array
+ */
+ public function prepareDataSourceDataProvider()
+ {
+ return [
+ [
+ ['name' => 'itemName', 'config' => []],
+ [['itemName' => '', 'entity_id' => 1]],
+ [['itemName' => ['view' => ['href' => 'url', 'label' => __('View')]], 'entity_id' => 1]],
+ '#',
+ ['entity_id' => 1]
+ ],
+ [
+ ['name' => 'itemName', 'config' => ['viewUrlPath' => 'url_path', 'urlEntityParamName' => 'order_id']],
+ [['itemName' => '', 'entity_id' => 2]],
+ [['itemName' => ['view' => ['href' => 'url', 'label' => __('View')]], 'entity_id' => 2]],
+ 'url_path',
+ ['order_id' => 2]
+ ]
+ ];
+ }
+}
diff --git a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderActions.php b/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderActions.php
deleted file mode 100644
index 3989e329d866e..0000000000000
--- a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderActions.php
+++ /dev/null
@@ -1,74 +0,0 @@
-urlBuilder = $urlBuilder;
- parent::__construct($context, $uiComponentFactory, $components, $data);
- }
-
- /**
- * Prepare Data Source
- *
- * @param array $dataSource
- * @return void
- */
- public function prepareDataSource(array & $dataSource)
- {
- if (isset($dataSource['data']['items'])) {
- foreach ($dataSource['data']['items'] as & $item) {
- if (isset($item['entity_id'])) {
- $item[$this->getData('name')] = [
- 'view' => [
- 'href' => $this->urlBuilder->getUrl(
- static::URL_PATH_VIEW,
- [
- 'order_id' => $item['entity_id']
- ]
- ),
- 'label' => __('View')
- ]
- ];
- }
- }
- }
- }
-}
diff --git a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderCreditmemoActions.php b/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderCreditmemoActions.php
deleted file mode 100644
index f2a49891c51f5..0000000000000
--- a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderCreditmemoActions.php
+++ /dev/null
@@ -1,74 +0,0 @@
-urlBuilder = $urlBuilder;
- parent::__construct($context, $uiComponentFactory, $components, $data);
- }
-
- /**
- * Prepare Data Source
- *
- * @param array $dataSource
- * @return void
- */
- public function prepareDataSource(array & $dataSource)
- {
- if (isset($dataSource['data']['items'])) {
- foreach ($dataSource['data']['items'] as & $item) {
- if (isset($item['entity_id'])) {
- $item[$this->getData('name')] = [
- 'view' => [
- 'href' => $this->urlBuilder->getUrl(
- static::URL_PATH_VIEW,
- [
- 'creditmemo_id' => $item['entity_id']
- ]
- ),
- 'label' => __('View')
- ]
- ];
- }
- }
- }
- }
-}
diff --git a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderInvoiceActions.php b/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderInvoiceActions.php
deleted file mode 100644
index 301b78e0405ca..0000000000000
--- a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderInvoiceActions.php
+++ /dev/null
@@ -1,74 +0,0 @@
-urlBuilder = $urlBuilder;
- parent::__construct($context, $uiComponentFactory, $components, $data);
- }
-
- /**
- * Prepare Data Source
- *
- * @param array $dataSource
- * @return void
- */
- public function prepareDataSource(array & $dataSource)
- {
- if (isset($dataSource['data']['items'])) {
- foreach ($dataSource['data']['items'] as & $item) {
- if (isset($item['entity_id'])) {
- $item[$this->getData('name')] = [
- 'view' => [
- 'href' => $this->urlBuilder->getUrl(
- static::URL_PATH_VIEW,
- [
- 'invoice_id' => $item['entity_id']
- ]
- ),
- 'label' => __('View')
- ]
- ];
- }
- }
- }
- }
-}
diff --git a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderShipmentActions.php b/app/code/Magento/Sales/Ui/Component/Listing/Column/ViewAction.php
similarity index 83%
rename from app/code/Magento/Sales/Ui/Component/Listing/Column/OrderShipmentActions.php
rename to app/code/Magento/Sales/Ui/Component/Listing/Column/ViewAction.php
index d220b755f1689..0d6e8213ce4bc 100644
--- a/app/code/Magento/Sales/Ui/Component/Listing/Column/OrderShipmentActions.php
+++ b/app/code/Magento/Sales/Ui/Component/Listing/Column/ViewAction.php
@@ -11,15 +11,10 @@
use Magento\Ui\Component\Listing\Columns\Column;
/**
- * Class OrderActions
+ * Class ViewAction
*/
-class OrderShipmentActions extends Column
+class ViewAction extends Column
{
- /**
- * Url path
- */
- const URL_PATH_VIEW = 'sales/shipment/view';
-
/**
* @var UrlInterface
*/
@@ -56,12 +51,14 @@ public function prepareDataSource(array & $dataSource)
if (isset($dataSource['data']['items'])) {
foreach ($dataSource['data']['items'] as & $item) {
if (isset($item['entity_id'])) {
+ $viewUrlPath = $this->getData('config/viewUrlPath') ?: '#';
+ $urlEntityParamName = $this->getData('config/urlEntityParamName') ?: 'entity_id';
$item[$this->getData('name')] = [
'view' => [
'href' => $this->urlBuilder->getUrl(
- static::URL_PATH_VIEW,
+ $viewUrlPath,
[
- 'shipment_id' => $item['entity_id']
+ $urlEntityParamName => $item['entity_id']
]
),
'label' => __('View')
diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml
index 04e78702da570..68bba9acc8f9b 100644
--- a/app/code/Magento/Sales/etc/di.xml
+++ b/app/code/Magento/Sales/etc/di.xml
@@ -761,4 +761,9 @@
Magento\Sales\Model\Order\Payment\State\RegisterCaptureNotificationCommand
+
+
+ sales
+
+
diff --git a/app/code/Magento/Sales/etc/resources.xml b/app/code/Magento/Sales/etc/resources.xml
index 6e290736fe5f0..14e3ed4378b17 100644
--- a/app/code/Magento/Sales/etc/resources.xml
+++ b/app/code/Magento/Sales/etc/resources.xml
@@ -5,7 +5,7 @@
* See COPYING.txt for license details.
*/
-->
-
+
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml
index b6202a0b54460..06ae40bf7ee11 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_creditmemo_grid.xml
@@ -790,7 +790,7 @@
-
+
-
- false
@@ -801,6 +801,8 @@
- actions
- false
- false
+ - sales/creditmemo/view
+ - creditmemo_id
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml
index de2256d9db29d..f8bc243e145ec 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml
@@ -750,7 +750,7 @@
-
+
-
- false
@@ -761,6 +761,8 @@
- actions
- false
- false
+ - sales/order/view
+ - order_id
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml
index 8adf6c8a254de..ea34c1977aff4 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml
@@ -641,7 +641,7 @@
-
+
-
- false
@@ -652,6 +652,8 @@
- actions
- false
- false
+ - sales/invoice/view
+ - invoice_id
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml
index f63f0b24fcf1e..2acd9d47332be 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml
@@ -567,7 +567,7 @@
-
+
-
- false
@@ -578,6 +578,8 @@
- actions
- false
- false
+ - sales/shipment/view
+ - shipment_id
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml
index 7ffa75d9b9b01..adbc33a18c26d 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml
@@ -735,7 +735,7 @@
-
+
-
- false
@@ -746,6 +746,8 @@
- actions
- false
- false
+ - sales/order_creditmemo/view
+ - creditmemo_id
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml
index 4e8b218c7ef4c..2f66916ee8f03 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml
@@ -644,7 +644,7 @@
-
+
-
- false
@@ -655,6 +655,8 @@
- actions
- false
- false
+ - sales/order_invoice/view
+ - invoice_id
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml
index cee10d9d3d557..5d668bea391a1 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml
@@ -565,7 +565,7 @@
-
+
-
- false
@@ -576,6 +576,8 @@
- actions
- false
- false
+ - adminhtml/order_shipment/view
+ - shipment_id
diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php
index 5356a8e953483..52fb187cefa30 100644
--- a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php
+++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php
@@ -7,18 +7,19 @@
use Magento\Store\Model\StoreManagerInterface;
use Magento\Customer\Model\Session;
+use Magento\SalesRule\Model\Resource\Rule as RuleResource;
class QuoteConfigProductAttributes
{
/**
- * @var Rule
+ * @var RuleResource
*/
protected $_ruleResource;
/**
- * @param Rule $ruleResource
+ * @param RuleResource $ruleResource
*/
- public function __construct(\Magento\SalesRule\Model\Resource\Rule $ruleResource)
+ public function __construct(RuleResource $ruleResource)
{
$this->_ruleResource = $ruleResource;
}
diff --git a/app/code/Magento/SalesRule/Model/Resource/Rule/Collection.php b/app/code/Magento/SalesRule/Model/Resource/Rule/Collection.php
index 18891e76f6c3a..cee9cd29366f3 100644
--- a/app/code/Magento/SalesRule/Model/Resource/Rule/Collection.php
+++ b/app/code/Magento/SalesRule/Model/Resource/Rule/Collection.php
@@ -104,12 +104,11 @@ public function setValidationFilter($websiteId, $customerGroupId, $couponCode =
['code']
);
- $select->where(
- 'main_table.coupon_type = ? ',
- \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
- );
-
$orWhereConditions = [
+ $connection->quoteInto(
+ 'main_table.coupon_type = ? ',
+ \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
+ ),
$connection->quoteInto(
'(main_table.coupon_type = ? AND rule_coupons.type = 0)',
\Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO
@@ -138,7 +137,7 @@ public function setValidationFilter($websiteId, $customerGroupId, $couponCode =
$orWhereCondition = implode(' OR ', $orWhereConditions);
$andWhereCondition = implode(' AND ', $andWhereConditions);
- $select->orWhere('(' . $orWhereCondition . ') AND ' . $andWhereCondition);
+ $select->where('(' . $orWhereCondition . ') AND ' . $andWhereCondition);
} else {
$this->addFieldToFilter(
'main_table.coupon_type',
diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php
index 4765f73f9dc5d..980486e3bc284 100644
--- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php
+++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php
@@ -15,15 +15,31 @@ class View extends \Magento\Backend\App\Action
*/
protected $shipmentLoader;
+ /**
+ * @var \Magento\Framework\View\Result\PageFactory
+ */
+ protected $resultPageFactory;
+
+ /**
+ * @var \Magento\Backend\Model\View\Result\ForwardFactory
+ */
+ protected $resultForwardFactory;
+
/**
* @param Action\Context $context
* @param \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader
+ * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory
+ * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
*/
public function __construct(
Action\Context $context,
- \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader
+ \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader,
+ \Magento\Framework\View\Result\PageFactory $resultPageFactory,
+ \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory
) {
$this->shipmentLoader = $shipmentLoader;
+ $this->resultPageFactory = $resultPageFactory;
+ $this->resultForwardFactory = $resultForwardFactory;
parent::__construct($context);
}
@@ -48,18 +64,17 @@ public function execute()
$this->shipmentLoader->setTracking($this->getRequest()->getParam('tracking'));
$shipment = $this->shipmentLoader->load();
if ($shipment) {
- $this->_view->loadLayout();
- $this->_view->getLayout()->getBlock(
- 'sales_shipment_view'
- )->updateBackButtonUrl(
- $this->getRequest()->getParam('come_from')
- );
- $this->_setActiveMenu('Magento_Sales::sales_order');
- $this->_view->getPage()->getConfig()->getTitle()->prepend(__('Shipments'));
- $this->_view->getPage()->getConfig()->getTitle()->prepend("#" . $shipment->getIncrementId());
- $this->_view->renderLayout();
+ $resultPage = $this->resultPageFactory->create();
+ $resultPage->getLayout()->getBlock('sales_shipment_view')
+ ->updateBackButtonUrl($this->getRequest()->getParam('come_from'));
+ $resultPage->setActiveMenu('Magento_Sales::sales_shipment');
+ $resultPage->getConfig()->getTitle()->prepend(__('Shipments'));
+ $resultPage->getConfig()->getTitle()->prepend("#" . $shipment->getIncrementId());
+ return $resultPage;
} else {
- $this->_forward('noroute');
+ $resultForward = $this->resultForwardFactory->create();
+ $resultForward->forward('noroute');
+ return $resultForward;
}
}
}
diff --git a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php
index e8631581b8af3..1dbf636942246 100644
--- a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php
+++ b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php
@@ -12,10 +12,15 @@
class ViewTest extends \PHPUnit_Framework_TestCase
{
/**
- * @var \Magento\Framework\App\Request\Http|\PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $requestMock;
+ /**
+ * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $objectManagerMock;
+
/**
* @var \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -26,35 +31,30 @@ class ViewTest extends \PHPUnit_Framework_TestCase
*/
protected $shipmentMock;
- /**
- * @var \Magento\Framework\App\View|\PHPUnit_Framework_MockObject_MockObject
- */
- protected $viewMock;
-
/**
* @var \Magento\Shipping\Block\Adminhtml\View|\PHPUnit_Framework_MockObject_MockObject
*/
protected $blockMock;
/**
- * @var \Magento\Framework\App\Response\Http|\PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Framework\View\Result\PageFactory|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $responseMock;
+ protected $resultPageFactoryMock;
/**
- * @var \Magento\Backend\Model\Session|\PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Backend\Model\View\Result\Page|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $sessionMock;
+ protected $resultPageMock;
/**
- * @var \Magento\Framework\App\ActionFlag|\PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Backend\Model\View\Result\ForwardFactory|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $actionFlag;
+ protected $resultForwardFactoryMock;
/**
- * @var \Magento\Framework\View\Result\Page|\PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Backend\Model\View\Result\Forward|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $resultPageMock;
+ protected $resultForwardMock;
/**
* @var \Magento\Framework\View\Page\Config|\PHPUnit_Framework_MockObject_MockObject
@@ -73,13 +73,16 @@ class ViewTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
- $this->requestMock = $this->getMock(
- 'Magento\Framework\App\Request\Http',
- ['getParam'],
- [],
- '',
- false
- );
+ $this->requestMock = $this->getMockBuilder('Magento\Framework\App\RequestInterface')
+ ->getMock();
+ $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManagerInterface')
+ ->getMock();
+ $this->pageConfigMock = $this->getMockBuilder('Magento\Framework\View\Page\Config')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->pageTitleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title')
+ ->disableOriginalConstructor()
+ ->getMock();
$this->shipmentLoaderMock = $this->getMock(
'Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader',
['setOrderId', 'setShipmentId', 'setShipment', 'setTracking', 'load'],
@@ -94,71 +97,45 @@ protected function setUp()
'',
false
);
- $this->viewMock = $this->getMock(
- 'Magento\Framework\App\View',
- ['loadLayout', 'getLayout', 'renderLayout', 'getPage'],
- [],
- '',
- false
- );
- $this->responseMock = $this->getMock(
- 'Magento\Framework\App\Response\Http',
- [],
- [],
- '',
- false
- );
- $this->sessionMock = $this->getMock(
- 'Magento\Backend\Model\Session',
- ['setIsUrlNotice'],
- [],
- '',
- false
- );
- $this->actionFlag = $this->getMock(
- 'Magento\Framework\App\ActionFlag',
- ['get'],
- [],
- '',
- false
- );
- $this->resultPageMock = $this->getMockBuilder('Magento\Framework\View\Result\Page')
+ $this->resultPageFactoryMock = $this->getMockBuilder('Magento\Framework\View\Result\PageFactory')
->disableOriginalConstructor()
+ ->setMethods(['create'])
->getMock();
- $this->pageConfigMock = $this->getMockBuilder('Magento\Framework\View\Page\Config')
+ $this->resultPageMock = $this->getMockBuilder('Magento\Backend\Model\View\Result\Page')
->disableOriginalConstructor()
->getMock();
- $this->pageTitleMock = $this->getMockBuilder('Magento\Framework\View\Page\Title')
+ $this->resultForwardFactoryMock = $this->getMockBuilder('Magento\Backend\Model\View\Result\ForwardFactory')
->disableOriginalConstructor()
+ ->setMethods(['create'])
->getMock();
- $contextMock = $this->getMock(
- 'Magento\Backend\App\Action\Context',
- ['getRequest', 'getResponse', 'getView', 'getSession', 'getActionFlag'],
+ $this->resultForwardMock = $this->getMockBuilder('Magento\Backend\Model\View\Result\Forward')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->blockMock = $this->getMock(
+ 'Magento\Shipping\Block\Adminhtml\View',
+ ['updateBackButtonUrl'],
[],
'',
false
);
- $contextMock->expects($this->any())->method('getRequest')->will($this->returnValue($this->requestMock));
- $contextMock->expects($this->any())->method('getResponse')->will($this->returnValue($this->responseMock));
- $contextMock->expects($this->any())->method('getView')->will($this->returnValue($this->viewMock));
- $contextMock->expects($this->any())->method('getSession')->will($this->returnValue($this->sessionMock));
- $contextMock->expects($this->any())->method('getActionFlag')->will($this->returnValue($this->actionFlag));
-
- $this->controller = new \Magento\Shipping\Controller\Adminhtml\Order\Shipment\View(
- $contextMock,
- $this->shipmentLoaderMock
+ $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+ $this->context = $objectManager->getObject(
+ 'Magento\Backend\App\Action\Context',
+ [
+ 'request' => $this->requestMock,
+ 'objectManager' => $this->objectManagerMock
+ ]
+ );
+ $this->controller = $objectManager->getObject(
+ 'Magento\Shipping\Controller\Adminhtml\Order\Shipment\View',
+ [
+ 'context' => $this->context,
+ 'shipmentLoader' => $this->shipmentLoaderMock,
+ 'resultPageFactory' => $this->resultPageFactoryMock,
+ 'resultForwardFactory' => $this->resultForwardFactoryMock
+ ]
);
-
- $this->viewMock->expects($this->any())
- ->method('getPage')
- ->willReturn($this->resultPageMock);
- $this->resultPageMock->expects($this->any())
- ->method('getConfig')
- ->willReturn($this->pageConfigMock);
- $this->pageConfigMock->expects($this->any())
- ->method('getTitle')
- ->willReturn($this->pageTitleMock);
}
/**
@@ -173,79 +150,44 @@ public function testExecute()
$incrementId = '10000001';
$comeFrom = true;
- $this->requestMock->expects($this->at(0))
- ->method('getParam')
- ->with('order_id')
- ->will($this->returnValue($orderId));
- $this->requestMock->expects($this->at(1))
- ->method('getParam')
- ->with('shipment_id')
- ->will($this->returnValue($shipmentId));
- $this->requestMock->expects($this->at(2))
- ->method('getParam')
- ->with('shipment')
- ->will($this->returnValue($shipment));
- $this->requestMock->expects($this->at(3))
- ->method('getParam')
- ->with('tracking')
- ->will($this->returnValue($tracking));
- $this->requestMock->expects($this->at(4))
- ->method('getParam')
- ->with('come_from')
- ->will($this->returnValue($comeFrom));
- $this->shipmentLoaderMock->expects($this->once())->method('setOrderId')->with($orderId);
- $this->shipmentLoaderMock->expects($this->once())->method('setShipmentId')->with($shipmentId);
- $this->shipmentLoaderMock->expects($this->once())->method('setShipment')->with($shipment);
- $this->shipmentLoaderMock->expects($this->once())->method('setTracking')->with($tracking);
- $this->shipmentLoaderMock->expects($this->once())
- ->method('load')
- ->will($this->returnValue($this->shipmentMock));
- $this->shipmentMock->expects($this->once())->method('getIncrementId')->will($this->returnValue($incrementId));
+ $this->loadShipment($orderId, $shipmentId, $shipment, $tracking, $comeFrom, $this->shipmentMock);
+ $this->shipmentMock->expects($this->once())->method('getIncrementId')->willReturn($incrementId);
+ $this->resultPageFactoryMock->expects($this->once())
+ ->method('create')
+ ->willReturn($this->resultPageMock);
- $menuBlockMock = $this->getMock(
- 'Magento\Backend\Block\Menu',
- ['getParentItems', 'getMenuModel'],
- [],
- '',
- false
- );
- $menuBlockMock->expects($this->any())->method('getMenuModel')->will($this->returnSelf());
- $menuBlockMock->expects($this->any())
- ->method('getParentItems')
- ->with('Magento_Sales::sales_order')
- ->will($this->returnValue([]));
- $shipmentBlockMock = $this->getMock(
- 'Magento\Shipping\Block\Adminhtml\View',
- ['updateBackButtonUrl'],
- [],
- '',
- false
- );
- $layoutMock = $this->getMock(
- 'Magento\Framework\View\Layout',
- ['getBlock'],
- [],
- '',
- false
- );
- $shipmentBlockMock->expects($this->once())
- ->method('updateBackButtonUrl')
- ->with($comeFrom)
- ->will($this->returnSelf());
- $layoutMock->expects($this->at(0))
+ $layoutMock = $this->getMock('Magento\Framework\View\Layout', ['getBlock', '__wakeup'], [], '', false);
+ $this->resultPageMock->expects($this->once())
+ ->method('getLayout')
+ ->willReturn($layoutMock);
+ $layoutMock->expects($this->once())
->method('getBlock')
->with('sales_shipment_view')
- ->will($this->returnValue($shipmentBlockMock));
- $layoutMock->expects($this->at(1))
- ->method('getBlock')
- ->with('menu')
- ->will($this->returnValue($menuBlockMock));
-
- $this->viewMock->expects($this->once())->method('loadLayout')->will($this->returnSelf());
- $this->viewMock->expects($this->any())->method('getLayout')->will($this->returnValue($layoutMock));
- $this->viewMock->expects($this->once())->method('renderLayout')->will($this->returnSelf());
+ ->willReturn($this->blockMock);
+ $this->blockMock->expects($this->once())
+ ->method('updateBackButtonUrl')
+ ->with($comeFrom)
+ ->willReturnSelf();
- $this->assertNull($this->controller->execute());
+ $this->resultPageMock->expects($this->once())
+ ->method('setActiveMenu')
+ ->with('Magento_Sales::sales_shipment')
+ ->willReturnSelf();
+ $this->resultPageMock->expects($this->atLeastOnce())
+ ->method('getConfig')
+ ->willReturn($this->pageConfigMock);
+ $this->pageConfigMock->expects($this->atLeastOnce())
+ ->method('getTitle')
+ ->willReturn($this->pageTitleMock);
+ $this->pageTitleMock->expects($this->exactly(2))
+ ->method('prepend')
+ ->withConsecutive(
+ ['Shipments'],
+ ["#" . $incrementId]
+ )
+ ->willReturnSelf();
+
+ $this->assertEquals($this->resultPageMock, $this->controller->execute());
}
/**
@@ -258,45 +200,36 @@ public function testExecuteNoShipment()
$shipment = [];
$tracking = [];
- $this->requestMock->expects($this->at(0))
- ->method('getParam')
- ->with('order_id')
- ->will($this->returnValue($orderId));
- $this->requestMock->expects($this->at(1))
- ->method('getParam')
- ->with('shipment_id')
- ->will($this->returnValue($shipmentId));
- $this->requestMock->expects($this->at(2))
- ->method('getParam')
- ->with('shipment')
- ->will($this->returnValue($shipment));
- $this->requestMock->expects($this->at(3))
+ $this->loadShipment($orderId, $shipmentId, $shipment, $tracking, null, false);
+ $this->resultForwardFactoryMock->expects($this->once())
+ ->method('create')
+ ->willReturn($this->resultForwardMock);
+ $this->resultForwardMock->expects($this->once())
+ ->method('forward')
+ ->with('noroute')
+ ->willReturnSelf();
+
+ $this->assertEquals($this->resultForwardMock, $this->controller->execute());
+ }
+
+ protected function loadShipment($orderId, $shipmentId, $shipment, $tracking, $comeFrom, $returnShipment)
+ {
+ $valueMap = [
+ ['order_id', null, $orderId],
+ ['shipment_id', null, $shipmentId],
+ ['shipment', null, $shipment],
+ ['tracking', null, $tracking],
+ ['come_from', null, $comeFrom],
+ ];
+ $this->requestMock->expects($this->any())
->method('getParam')
- ->with('tracking')
- ->will($this->returnValue($tracking));
- $this->shipmentLoaderMock->expects($this->once())
- ->method('setOrderId')
- ->with($orderId);
- $this->shipmentLoaderMock->expects($this->once())
- ->method('setShipmentId')
- ->with($shipmentId);
- $this->shipmentLoaderMock->expects($this->once())
- ->method('setShipment')
- ->with($shipment);
- $this->shipmentLoaderMock->expects($this->once())
- ->method('setTracking')
- ->with($tracking);
+ ->willReturnMap($valueMap);
+ $this->shipmentLoaderMock->expects($this->once())->method('setOrderId')->with($orderId);
+ $this->shipmentLoaderMock->expects($this->once())->method('setShipmentId')->with($shipmentId);
+ $this->shipmentLoaderMock->expects($this->once())->method('setShipment')->with($shipment);
+ $this->shipmentLoaderMock->expects($this->once())->method('setTracking')->with($tracking);
$this->shipmentLoaderMock->expects($this->once())
->method('load')
- ->will($this->returnValue(false));
- $this->actionFlag->expects($this->once())
- ->method('get')
- ->with('', \Magento\Backend\App\AbstractAction::FLAG_IS_URLS_CHECKED)
- ->will($this->returnValue(true));
- $this->sessionMock->expects($this->once())
- ->method('setIsUrlNotice')
- ->with(true);
-
- $this->assertNull($this->controller->execute());
+ ->willReturn($returnShipment);
}
}
diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml
index 57d4d9f65d15a..d5d09df39b262 100644
--- a/app/code/Magento/Store/etc/di.xml
+++ b/app/code/Magento/Store/etc/di.xml
@@ -102,7 +102,7 @@
Magento\Framework\Session\Generic\Proxy
Magento\Store\Model\Store::CUSTOM_ENTRY_POINT_PARAM
- Magento\Framework\UrlInterface\Proxy
+ Magento\Framework\UrlInterface
@@ -266,7 +266,7 @@
- Magento\Framework\UrlInterface\Proxy
+ Magento\Framework\UrlInterface
Magento\Framework\App\Request\Http\Proxy
diff --git a/app/code/Magento/Swatches/Setup/InstallSchema.php b/app/code/Magento/Swatches/Setup/InstallSchema.php
index aa32c57f92bff..d956b2c053cfc 100644
--- a/app/code/Magento/Swatches/Setup/InstallSchema.php
+++ b/app/code/Magento/Swatches/Setup/InstallSchema.php
@@ -90,10 +90,6 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con
'option_id',
\Magento\Framework\DB\Ddl\Table::ACTION_CASCADE
)
- ->setOption(
- 'type',
- 'InnoDB'
- )
->setComment('Magento Swatches table');
if (!$setup->getConnection()->tableColumnExists($setup->getTable('catalog_eav_attribute'), 'additional_data')) {
diff --git a/app/code/Magento/Tax/Setup/InstallData.php b/app/code/Magento/Tax/Setup/InstallData.php
index a8edea0a79071..d62ae4e22dc7a 100644
--- a/app/code/Magento/Tax/Setup/InstallData.php
+++ b/app/code/Magento/Tax/Setup/InstallData.php
@@ -43,7 +43,7 @@ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface
/**
* Add tax_class_id attribute to the 'eav_attribute' table
*/
- $catalogInstaller = $taxSetup->getCatalogSetup();
+ $catalogInstaller = $taxSetup->getCatalogSetup(['resourceName' => 'catalog_setup', 'setup' => $setup]);
$catalogInstaller->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
'tax_class_id',
diff --git a/app/code/Magento/Tax/etc/di.xml b/app/code/Magento/Tax/etc/di.xml
index fc51d871b821b..eb2c97bf8d7db 100644
--- a/app/code/Magento/Tax/etc/di.xml
+++ b/app/code/Magento/Tax/etc/di.xml
@@ -80,4 +80,9 @@
+
+
+ sales
+
+
diff --git a/app/code/Magento/Theme/Model/Theme/ThemeDependencyChecker.php b/app/code/Magento/Theme/Model/Theme/ThemeDependencyChecker.php
index 81164a9e21fbf..05209e7fd84dc 100644
--- a/app/code/Magento/Theme/Model/Theme/ThemeDependencyChecker.php
+++ b/app/code/Magento/Theme/Model/Theme/ThemeDependencyChecker.php
@@ -70,7 +70,7 @@ public function checkChildThemeByPackagesName($packages)
return $this->checkChildTheme($themePaths);
}
- return false;
+ return [];
}
/**
diff --git a/app/code/Magento/Translation/Model/Js/DataProvider.php b/app/code/Magento/Translation/Model/Js/DataProvider.php
index 2da6a00eb29c8..dad8e6b2f8dfc 100644
--- a/app/code/Magento/Translation/Model/Js/DataProvider.php
+++ b/app/code/Magento/Translation/Model/Js/DataProvider.php
@@ -6,6 +6,7 @@
namespace Magento\Translation\Model\Js;
+use Magento\Framework\Phrase\Renderer\Translate;
use Magento\Framework\App\Utility\Files;
use Magento\Framework\App\State;
use Magento\Framework\Filesystem;
@@ -14,6 +15,7 @@
/**
* DataProvider for js translation
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class DataProvider implements DataProviderInterface
{
@@ -45,17 +47,31 @@ class DataProvider implements DataProviderInterface
*/
protected $rootDirectory;
+ /**
+ * Basic translate renderer
+ *
+ * @var Translate
+ */
+ protected $translate;
+
/**
* @param State $appState
* @param Config $config
* @param Filesystem $filesystem
+ * @param Translate $translate
* @param Files $filesUtility
*/
- public function __construct(State $appState, Config $config, Filesystem $filesystem, Files $filesUtility = null)
- {
+ public function __construct(
+ State $appState,
+ Config $config,
+ Filesystem $filesystem,
+ Translate $translate,
+ Files $filesUtility = null
+ ) {
$this->appState = $appState;
$this->config = $config;
$this->rootDirectory = $filesystem->getDirectoryRead(DirectoryList::ROOT);
+ $this->translate = $translate;
$this->filesUtility = (null !== $filesUtility) ? $filesUtility : new Files(BP);
}
@@ -69,22 +85,20 @@ public function __construct(State $appState, Config $config, Filesystem $filesys
*/
public function getData($themePath)
{
- $dictionary = [];
$areaCode = $this->appState->getAreaCode();
- $files = $this->filesUtility->getJsFiles($areaCode, $themePath);
- $staticHtmlFiles = $this->filesUtility->getStaticHtmlFiles($areaCode, $themePath);
-
- if (is_array($staticHtmlFiles)) {
- foreach ($staticHtmlFiles as $staticFile) {
- $files[] = $staticFile;
- }
- }
+ $files = array_merge(
+ $this->filesUtility->getJsFiles('base', $themePath),
+ $this->filesUtility->getJsFiles($areaCode, $themePath),
+ $this->filesUtility->getStaticHtmlFiles('base', $themePath),
+ $this->filesUtility->getStaticHtmlFiles($areaCode, $themePath)
+ );
+ $dictionary = [];
foreach ($files as $filePath) {
$content = $this->rootDirectory->readFile($this->rootDirectory->getRelativePath($filePath[0]));
foreach ($this->getPhrases($content) as $phrase) {
- $translatedPhrase = (string) __($phrase);
+ $translatedPhrase = $this->translate->render([$phrase], []);
if ($phrase != $translatedPhrase) {
$dictionary[$phrase] = $translatedPhrase;
}
diff --git a/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php b/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php
index 6067c28723fb4..376f19d35f7d3 100644
--- a/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php
+++ b/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php
@@ -12,6 +12,7 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Translation\Model\Js\DataProvider;
use Magento\Translation\Model\Js\Config;
+use Magento\Framework\Phrase\Renderer\Translate;
/**
* Class DataProviderTest
@@ -43,6 +44,11 @@ class DataProviderTest extends \PHPUnit_Framework_TestCase
*/
protected $rootDirectoryMock;
+ /**
+ * @var Translate|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $translateMock;
+
/**
* @return void
*/
@@ -53,15 +59,21 @@ protected function setUp()
$this->filesUtilityMock = $this->getMock('Magento\Framework\App\Utility\Files', [], [], '', false);
$filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
$this->rootDirectoryMock = $this->getMock('Magento\Framework\Filesystem\Directory\Read', [], [], '', false);
+ $this->translateMock = $this->getMock('Magento\Framework\Phrase\Renderer\Translate', [], [], '', false);
$filesystem->expects($this->once())
->method('getDirectoryRead')
->with(DirectoryList::ROOT)
->willReturn($this->rootDirectoryMock);
- $this->model = new DataProvider(
- $this->appStateMock,
- $this->configMock,
- $filesystem,
- $this->filesUtilityMock
+ $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+ $this->model = $objectManager->getObject(
+ 'Magento\Translation\Model\Js\DataProvider',
+ [
+ 'appState' => $this->appStateMock,
+ 'config' => $this->configMock,
+ 'filesystem' => $filesystem,
+ 'filesUtility' => $this->filesUtilityMock,
+ 'translate' => $this->translateMock
+ ]
);
}
@@ -72,26 +84,57 @@ public function testGetData()
{
$themePath = 'blank';
$areaCode = 'adminhtml';
- $files = [['path1'], ['path2']];
+
+ $filePaths = [['path1'], ['path2'], ['path3'], ['path4']];
+
+ $jsFilesMap = [
+ ['base', $themePath, '*', '*', [$filePaths[0]]],
+ [$areaCode, $themePath, '*', '*', [$filePaths[1]]]
+ ];
+ $staticFilesMap = [
+ ['base', $themePath, '*', '*', [$filePaths[2]]],
+ [$areaCode, $themePath, '*', '*', [$filePaths[3]]]
+ ];
$relativePathMap = [
- ['path1' => 'relativePath1'],
- ['path2' => 'relativePath2']
+ ['path1', 'relativePath1'],
+ ['path2', 'relativePath2'],
+ ['path3', 'relativePath3'],
+ ['path4', 'relativePath4']
+ ];
+
+ $expectedResult = [
+ 'hello1' => 'hello1translated',
+ 'hello2' => 'hello2translated',
+ 'hello3' => 'hello3translated',
+ 'hello4' => 'hello4translated'
];
+
$contentsMap = [
- ['relativePath1' => 'content1$.mage.__("hello1")content1'],
- ['relativePath2' => 'content2$.mage.__("hello2")content2']
+ ['relativePath1', null, null, 'content1$.mage.__("hello1")content1'],
+ ['relativePath2', null, null, 'content2$.mage.__("hello2")content2'],
+ ['relativePath3', null, null, 'content2$.mage.__("hello3")content3'],
+ ['relativePath4', null, null, 'content2$.mage.__("hello4")content4']
+ ];
+
+ $translateMap = [
+ [['hello1'], [], 'hello1translated'],
+ [['hello2'], [], 'hello2translated'],
+ [['hello3'], [], 'hello3translated'],
+ [['hello4'], [], 'hello4translated']
];
- $patterns = ['~\$\.mage\.__\([\'|\"](.+?)[\'|\"]\)~'];
+ $patterns = ['~\$\.mage\.__\(([\'"])(.+?)\1\)~'];
$this->appStateMock->expects($this->once())
->method('getAreaCode')
->willReturn($areaCode);
- $this->filesUtilityMock->expects($this->once())
+ $this->filesUtilityMock->expects($this->any())
->method('getJsFiles')
- ->with($areaCode, $themePath)
- ->willReturn($files);
+ ->willReturnMap($jsFilesMap);
+ $this->filesUtilityMock->expects($this->any())
+ ->method('getStaticHtmlFiles')
+ ->willReturnMap($staticFilesMap);
$this->rootDirectoryMock->expects($this->any())
->method('getRelativePath')
@@ -102,7 +145,10 @@ public function testGetData()
$this->configMock->expects($this->any())
->method('getPatterns')
->willReturn($patterns);
+ $this->translateMock->expects($this->any())
+ ->method('render')
+ ->willReturnMap($translateMap);
- $this->assertEquals([], $this->model->getData($themePath));
+ $this->assertEquals($expectedResult, $this->model->getData($themePath));
}
}
diff --git a/app/code/Magento/Ui/Component/Filters/Type/Input.php b/app/code/Magento/Ui/Component/Filters/Type/Input.php
index 7b7bb9b192827..50474472ae05b 100644
--- a/app/code/Magento/Ui/Component/Filters/Type/Input.php
+++ b/app/code/Magento/Ui/Component/Filters/Type/Input.php
@@ -69,7 +69,7 @@ protected function applyFilter()
if (!empty($value)) {
$filter = $this->filterBuilder->setConditionType('like')
->setField($this->getName())
- ->setValue(sprintf('%s%%', $value))
+ ->setValue(sprintf('%%%s%%', $value))
->create();
$this->getContext()->getDataProvider()->addFilter($filter);
diff --git a/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php b/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php
index afe0a833e84b3..e1f76f56e8203 100644
--- a/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php
+++ b/app/code/Magento/Wishlist/Test/Unit/Helper/DataTest.php
@@ -9,7 +9,7 @@
use Magento\Framework\App\Helper\Context;
use Magento\Framework\Data\Helper\PostHelper;
use Magento\Framework\Registry;
-use Magento\Framework\UrlInterface\Proxy as UrlInterface;
+use Magento\Framework\UrlInterface;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Wishlist\Controller\WishlistProviderInterface;
@@ -69,9 +69,8 @@ public function setUp()
->method('getStore')
->willReturn($this->store);
- $this->urlBuilder = $this->getMockBuilder('Magento\Framework\UrlInterface\Proxy')
+ $this->urlBuilder = $this->getMockBuilder('Magento\Framework\UrlInterface')
->disableOriginalConstructor()
- ->setMethods(['getUrl'])
->getMock();
$this->context = $this->getMockBuilder('Magento\Framework\App\Helper\Context')
diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml
index 9b0a5804ab781..3ee4e012f66be 100644
--- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml
+++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml
@@ -5,7 +5,7 @@
* See COPYING.txt for license details.
*/
-->
-
+
diff --git a/app/design/frontend/Magento/luma/etc/view.xml b/app/design/frontend/Magento/luma/etc/view.xml
index 573f628d52629..2795d84c168a1 100644
--- a/app/design/frontend/Magento/luma/etc/view.xml
+++ b/app/design/frontend/Magento/luma/etc/view.xml
@@ -188,7 +188,7 @@
false
true
true
- true
+ true
diff --git a/app/etc/di.xml b/app/etc/di.xml
index ae1df3af1fba0..fbb7c6946ce3c 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -1050,7 +1050,7 @@
- Magento\Framework\UrlInterface\Proxy
+ Magento\Framework\UrlInterface
diff --git a/composer.json b/composer.json
index 3d56ffc30ad81..0889646cdd9c7 100644
--- a/composer.json
+++ b/composer.json
@@ -46,6 +46,7 @@
"magento/magento-composer-installer": "*",
"braintree/braintree_php": "2.39.0",
"symfony/console": "~2.3 <2.7",
+ "symfony/event-dispatcher": "~2.1",
"phpseclib/phpseclib": "~0.3",
"tedivm/jshrink": "~1.0.1",
"magento/composer": "~1.0.0"
@@ -109,6 +110,7 @@
"magento/module-dhl": "self.version",
"magento/module-directory": "self.version",
"magento/module-downloadable": "self.version",
+ "magento/module-downloadable-import-export": "self.version",
"magento/module-eav": "self.version",
"magento/module-email": "self.version",
"magento/module-encryption-key": "self.version",
diff --git a/composer.lock b/composer.lock
index 878cafac4f2e4..5f638af517134 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "3c94391144a4c2de663dfa465b3a2e8a",
+ "hash": "ba8186cbc63f5db144177d64249726e6",
"packages": [
{
"name": "braintree/braintree_php",
@@ -121,16 +121,16 @@
},
{
"name": "justinrainbow/json-schema",
- "version": "1.4.4",
+ "version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
- "reference": "8dc9b9d85ab639ca60ab4608b34c1279d6ae7bce"
+ "reference": "a4bee9f4b344b66e0a0d96c7afae1e92edf385fe"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/8dc9b9d85ab639ca60ab4608b34c1279d6ae7bce",
- "reference": "8dc9b9d85ab639ca60ab4608b34c1279d6ae7bce",
+ "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/a4bee9f4b344b66e0a0d96c7afae1e92edf385fe",
+ "reference": "a4bee9f4b344b66e0a0d96c7afae1e92edf385fe",
"shasum": ""
},
"require": {
@@ -151,8 +151,8 @@
}
},
"autoload": {
- "psr-0": {
- "JsonSchema": "src/"
+ "psr-4": {
+ "JsonSchema\\": "src/JsonSchema/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -183,7 +183,7 @@
"json",
"schema"
],
- "time": "2015-07-14 16:29:50"
+ "time": "2015-09-08 22:28:04"
},
{
"name": "magento/composer",
@@ -764,18 +764,76 @@
"homepage": "https://symfony.com",
"time": "2015-07-26 09:08:40"
},
+ {
+ "name": "symfony/event-dispatcher",
+ "version": "v2.7.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/EventDispatcher.git",
+ "reference": "b58c916f1db03a611b72dd702564f30ad8fe83fa"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/b58c916f1db03a611b72dd702564f30ad8fe83fa",
+ "reference": "b58c916f1db03a611b72dd702564f30ad8fe83fa",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "psr/log": "~1.0",
+ "symfony/config": "~2.0,>=2.0.5",
+ "symfony/dependency-injection": "~2.6",
+ "symfony/expression-language": "~2.6",
+ "symfony/phpunit-bridge": "~2.7",
+ "symfony/stopwatch": "~2.3"
+ },
+ "suggest": {
+ "symfony/dependency-injection": "",
+ "symfony/http-kernel": ""
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\EventDispatcher\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony EventDispatcher Component",
+ "homepage": "https://symfony.com",
+ "time": "2015-08-24 07:13:45"
+ },
{
"name": "symfony/finder",
- "version": "v2.7.3",
+ "version": "v2.7.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/Finder.git",
- "reference": "ae0f363277485094edc04c9f3cbe595b183b78e4"
+ "reference": "fff4b0c362640a0ab7355e2647b3d461608e9065"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Finder/zipball/ae0f363277485094edc04c9f3cbe595b183b78e4",
- "reference": "ae0f363277485094edc04c9f3cbe595b183b78e4",
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/fff4b0c362640a0ab7355e2647b3d461608e9065",
+ "reference": "fff4b0c362640a0ab7355e2647b3d461608e9065",
"shasum": ""
},
"require": {
@@ -811,20 +869,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
- "time": "2015-07-09 16:07:40"
+ "time": "2015-08-26 17:56:37"
},
{
"name": "symfony/process",
- "version": "v2.7.3",
+ "version": "v2.7.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/Process.git",
- "reference": "48aeb0e48600321c272955132d7606ab0a49adb3"
+ "reference": "f7b3f73f70a7f8f49a1c838dc3debbf054732d8e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Process/zipball/48aeb0e48600321c272955132d7606ab0a49adb3",
- "reference": "48aeb0e48600321c272955132d7606ab0a49adb3",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/f7b3f73f70a7f8f49a1c838dc3debbf054732d8e",
+ "reference": "f7b3f73f70a7f8f49a1c838dc3debbf054732d8e",
"shasum": ""
},
"require": {
@@ -860,7 +918,7 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2015-07-01 11:25:50"
+ "time": "2015-08-27 06:45:45"
},
{
"name": "tedivm/jshrink",
@@ -958,12 +1016,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-code.git",
- "reference": "cfd5951ff4348e4430850560416c7ddb755f95d3"
+ "reference": "0ed94f842ba60cdc900c46a61bdbd7ac95a3e140"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-code/zipball/0ed94f842ba60cdc900c46a61bdbd7ac95a3e140",
- "reference": "cfd5951ff4348e4430850560416c7ddb755f95d3",
+ "reference": "0ed94f842ba60cdc900c46a61bdbd7ac95a3e140",
"shasum": ""
},
"require": {
@@ -972,6 +1030,9 @@
},
"require-dev": {
"doctrine/common": ">=2.1",
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-stdlib": "self.version"
},
"suggest": {
@@ -987,7 +1048,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Code\\": ""
+ "Zend\\Code\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -995,12 +1056,12 @@
"BSD-3-Clause"
],
"description": "provides facilities to generate arbitrary code using an object oriented interface",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-code",
"keywords": [
"code",
"zf2"
],
- "time": "2015-04-01 17:59:08"
+ "time": "2015-03-31 15:39:14"
},
{
"name": "zendframework/zend-config",
@@ -1008,12 +1069,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-config.git",
- "reference": "8682fe4e2923b383bb6472fc84b5796a07589163"
+ "reference": "95f3a4b3fa85d49e6f060183122de4596fa6d29d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-config/zipball/95f3a4b3fa85d49e6f060183122de4596fa6d29d",
- "reference": "8682fe4e2923b383bb6472fc84b5796a07589163",
+ "reference": "95f3a4b3fa85d49e6f060183122de4596fa6d29d",
"shasum": ""
},
"require": {
@@ -1021,6 +1082,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-filter": "self.version",
"zendframework/zend-i18n": "self.version",
"zendframework/zend-json": "self.version",
@@ -1041,7 +1105,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Config\\": ""
+ "Zend\\Config\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1049,12 +1113,12 @@
"BSD-3-Clause"
],
"description": "provides a nested object property based user interface for accessing this configuration data within application code",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-config",
"keywords": [
"config",
"zf2"
],
- "time": "2015-04-01 17:59:31"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-console",
@@ -1062,18 +1126,23 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-console.git",
- "reference": "94ab6663b07e19f20b3319ecf317bd72b6a72dca"
+ "reference": "54823d9ba6f8ce39046384ee5a043b5b3d5f56d7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-console/zipball/54823d9ba6f8ce39046384ee5a043b5b3d5f56d7",
- "reference": "94ab6663b07e19f20b3319ecf317bd72b6a72dca",
+ "reference": "54823d9ba6f8ce39046384ee5a043b5b3d5f56d7",
"shasum": ""
},
"require": {
"php": ">=5.3.23",
"zendframework/zend-stdlib": "self.version"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"suggest": {
"zendframework/zend-filter": "To support DefaultRouteMatcher usage",
"zendframework/zend-validator": "To support DefaultRouteMatcher usage"
@@ -1087,19 +1156,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Console\\": ""
+ "Zend\\Console\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-console",
"keywords": [
"console",
"zf2"
],
- "time": "2015-04-01 17:59:48"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-crypt",
@@ -1158,12 +1227,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-di.git",
- "reference": "0811f2a67ad0b50dfb8d602ed67cde0b82249190"
+ "reference": "b9f8de081adecf71a003a569e9ba76c0a4c00bf2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-di/zipball/b9f8de081adecf71a003a569e9ba76c0a4c00bf2",
- "reference": "0811f2a67ad0b50dfb8d602ed67cde0b82249190",
+ "reference": "b9f8de081adecf71a003a569e9ba76c0a4c00bf2",
"shasum": ""
},
"require": {
@@ -1172,6 +1241,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-servicemanager": "self.version"
},
"suggest": {
@@ -1186,19 +1258,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Di\\": ""
+ "Zend\\Di\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-di",
"keywords": [
"di",
"zf2"
],
- "time": "2015-04-01 18:01:30"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-escaper",
@@ -1206,17 +1278,22 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-escaper.git",
- "reference": "65b3328627362b0be1d5e9067bc846511d1fbc96"
+ "reference": "15e5769e4fcdb4bf07ebd76500810e7070e23a97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-escaper/zipball/15e5769e4fcdb4bf07ebd76500810e7070e23a97",
- "reference": "65b3328627362b0be1d5e9067bc846511d1fbc96",
+ "reference": "15e5769e4fcdb4bf07ebd76500810e7070e23a97",
"shasum": ""
},
"require": {
"php": ">=5.3.23"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -1226,19 +1303,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Escaper\\": ""
+ "Zend\\Escaper\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-escaper",
"keywords": [
"escaper",
"zf2"
],
- "time": "2015-04-01 18:02:07"
+ "time": "2015-03-23 18:29:14"
},
{
"name": "zendframework/zend-eventmanager",
@@ -1246,18 +1323,23 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-eventmanager.git",
- "reference": "38df5b567d4ff4d22144745c503ba0502d0d5695"
+ "reference": "58d21c95c7005a527262fd536499195f104e83f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/58d21c95c7005a527262fd536499195f104e83f9",
- "reference": "38df5b567d4ff4d22144745c503ba0502d0d5695",
+ "reference": "58d21c95c7005a527262fd536499195f104e83f9",
"shasum": ""
},
"require": {
"php": ">=5.3.23",
"zendframework/zend-stdlib": "self.version"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -1267,19 +1349,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\EventManager\\": ""
+ "Zend\\EventManager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-event-manager",
"keywords": [
"eventmanager",
"zf2"
],
- "time": "2015-04-01 18:05:26"
+ "time": "2015-03-23 18:29:14"
},
{
"name": "zendframework/zend-filter",
@@ -1287,12 +1369,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-filter.git",
- "reference": "b13741a88553351fc52472de529b57b580b8f6f1"
+ "reference": "6d8aed2da81b62a04747346c4370562cdbe34595"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-filter/zipball/6d8aed2da81b62a04747346c4370562cdbe34595",
- "reference": "b13741a88553351fc52472de529b57b580b8f6f1",
+ "reference": "6d8aed2da81b62a04747346c4370562cdbe34595",
"shasum": ""
},
"require": {
@@ -1300,6 +1382,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-crypt": "self.version",
"zendframework/zend-servicemanager": "self.version",
"zendframework/zend-uri": "self.version"
@@ -1319,7 +1404,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Filter\\": ""
+ "Zend\\Filter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1327,12 +1412,12 @@
"BSD-3-Clause"
],
"description": "provides a set of commonly needed data filters",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-filter",
"keywords": [
"filter",
"zf2"
],
- "time": "2015-04-01 18:09:25"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-form",
@@ -1340,12 +1425,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-form.git",
- "reference": "09f5bd46ffbf783df22281898e2175b291bd43a3"
+ "reference": "bca0db55718355d25c2c10fdd41a83561f1c94b3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-form/zipball/bca0db55718355d25c2c10fdd41a83561f1c94b3",
- "reference": "09f5bd46ffbf783df22281898e2175b291bd43a3",
+ "reference": "bca0db55718355d25c2c10fdd41a83561f1c94b3",
"shasum": ""
},
"require": {
@@ -1354,6 +1439,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-captcha": "self.version",
"zendframework/zend-code": "self.version",
"zendframework/zend-eventmanager": "self.version",
@@ -1384,19 +1472,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Form\\": ""
+ "Zend\\Form\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-form",
"keywords": [
"form",
"zf2"
],
- "time": "2015-04-01 18:09:25"
+ "time": "2015-03-28 20:29:18"
},
{
"name": "zendframework/zend-http",
@@ -1404,12 +1492,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-http.git",
- "reference": "ee6220609845b32d1b2873c9ac694aef56d508f5"
+ "reference": "9c6047a0bdb3094d3ea07a215ff929cc47de4deb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-http/zipball/9c6047a0bdb3094d3ea07a215ff929cc47de4deb",
- "reference": "ee6220609845b32d1b2873c9ac694aef56d508f5",
+ "reference": "9c6047a0bdb3094d3ea07a215ff929cc47de4deb",
"shasum": ""
},
"require": {
@@ -1419,6 +1507,11 @@
"zendframework/zend-uri": "self.version",
"zendframework/zend-validator": "self.version"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -1428,7 +1521,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Http\\": ""
+ "Zend\\Http\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1436,12 +1529,12 @@
"BSD-3-Clause"
],
"description": "provides an easy interface for performing Hyper-Text Transfer Protocol (HTTP) requests",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-http",
"keywords": [
"http",
"zf2"
],
- "time": "2015-04-01 18:09:25"
+ "time": "2015-03-27 15:46:30"
},
{
"name": "zendframework/zend-i18n",
@@ -1449,12 +1542,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-i18n.git",
- "reference": "33051775d9a8c341fe3b77d1f3daa0e921e2f4bd"
+ "reference": "9aebc5287373a802540d75fe5508417f866c2e52"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-i18n/zipball/9aebc5287373a802540d75fe5508417f866c2e52",
- "reference": "33051775d9a8c341fe3b77d1f3daa0e921e2f4bd",
+ "reference": "9aebc5287373a802540d75fe5508417f866c2e52",
"shasum": ""
},
"require": {
@@ -1462,6 +1555,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-cache": "self.version",
"zendframework/zend-config": "self.version",
"zendframework/zend-eventmanager": "self.version",
@@ -1490,19 +1586,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\I18n\\": ""
+ "Zend\\I18n\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-i18n",
"keywords": [
"i18n",
"zf2"
],
- "time": "2015-04-01 18:09:26"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-inputfilter",
@@ -1510,12 +1606,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-inputfilter.git",
- "reference": "16856fec61f285e41e5492235220a4dec06ab90f"
+ "reference": "4b1398f3635fae3cc5e873c5bb067274f3d10a93"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-inputfilter/zipball/4b1398f3635fae3cc5e873c5bb067274f3d10a93",
- "reference": "16856fec61f285e41e5492235220a4dec06ab90f",
+ "reference": "4b1398f3635fae3cc5e873c5bb067274f3d10a93",
"shasum": ""
},
"require": {
@@ -1525,6 +1621,9 @@
"zendframework/zend-validator": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-servicemanager": "self.version"
},
"suggest": {
@@ -1539,19 +1638,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\InputFilter\\": ""
+ "Zend\\InputFilter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-input-filter",
"keywords": [
"inputfilter",
"zf2"
],
- "time": "2015-04-01 18:09:26"
+ "time": "2015-03-23 18:29:14"
},
{
"name": "zendframework/zend-json",
@@ -1559,12 +1658,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-json.git",
- "reference": "76aeb27e4baf39799e5ca3cf6f2fdd6748ee930c"
+ "reference": "2d845e151c1b9a237cf1899ac31e17fb10bd1e3f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-json/zipball/2d845e151c1b9a237cf1899ac31e17fb10bd1e3f",
- "reference": "76aeb27e4baf39799e5ca3cf6f2fdd6748ee930c",
+ "reference": "2d845e151c1b9a237cf1899ac31e17fb10bd1e3f",
"shasum": ""
},
"require": {
@@ -1572,6 +1671,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-http": "self.version",
"zendframework/zend-server": "self.version"
},
@@ -1589,7 +1691,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Json\\": ""
+ "Zend\\Json\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1597,12 +1699,12 @@
"BSD-3-Clause"
],
"description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-json",
"keywords": [
"json",
"zf2"
],
- "time": "2015-04-01 18:09:26"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-loader",
@@ -1610,17 +1712,22 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-loader.git",
- "reference": "6868b8a0c346f17fb97724c3a63aa2cbf6b94865"
+ "reference": "65de2c7a56f8eee633c6bf1cfab73e45648880d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-loader/zipball/65de2c7a56f8eee633c6bf1cfab73e45648880d4",
- "reference": "6868b8a0c346f17fb97724c3a63aa2cbf6b94865",
+ "reference": "65de2c7a56f8eee633c6bf1cfab73e45648880d4",
"shasum": ""
},
"require": {
"php": ">=5.3.23"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -1630,19 +1737,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Loader\\": ""
+ "Zend\\Loader\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-loader",
"keywords": [
"loader",
"zf2"
],
- "time": "2015-04-01 18:09:26"
+ "time": "2015-03-23 18:29:14"
},
{
"name": "zendframework/zend-log",
@@ -1650,12 +1757,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-log.git",
- "reference": "2d5d20fd45470506bdaff727c46dc25fe953146e"
+ "reference": "002e3c810cad7e31e51c9895e9e3cb6fbd312cdd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-log/zipball/002e3c810cad7e31e51c9895e9e3cb6fbd312cdd",
- "reference": "2d5d20fd45470506bdaff727c46dc25fe953146e",
+ "reference": "002e3c810cad7e31e51c9895e9e3cb6fbd312cdd",
"shasum": ""
},
"require": {
@@ -1664,6 +1771,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-console": "self.version",
"zendframework/zend-db": "self.version",
"zendframework/zend-escaper": "self.version",
@@ -1687,7 +1797,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Log\\": ""
+ "Zend\\Log\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1695,13 +1805,13 @@
"BSD-3-Clause"
],
"description": "component for general purpose logging",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-log",
"keywords": [
"log",
"logging",
"zf2"
],
- "time": "2015-04-01 18:09:26"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-math",
@@ -1709,17 +1819,22 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-math.git",
- "reference": "634123f83ca90b6613f132d0d100e6b5e9890a29"
+ "reference": "f41fe4acfd809c14f2a802d1aa45dec8fcd2cc73"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-math/zipball/f41fe4acfd809c14f2a802d1aa45dec8fcd2cc73",
- "reference": "634123f83ca90b6613f132d0d100e6b5e9890a29",
+ "reference": "f41fe4acfd809c14f2a802d1aa45dec8fcd2cc73",
"shasum": ""
},
"require": {
"php": ">=5.3.23"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"suggest": {
"ext-bcmath": "If using the bcmath functionality",
"ext-gmp": "If using the gmp functionality",
@@ -1735,19 +1850,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Math\\": ""
+ "Zend\\Math\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-math",
"keywords": [
"math",
"zf2"
],
- "time": "2015-04-01 18:09:27"
+ "time": "2015-03-23 18:29:14"
},
{
"name": "zendframework/zend-modulemanager",
@@ -1755,12 +1870,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-modulemanager.git",
- "reference": "cbe16b0eafe734a062ed0182381e64b9c953dccf"
+ "reference": "af7ae3cd29a1efb73cc66ae1081e606039d5c20f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-modulemanager/zipball/af7ae3cd29a1efb73cc66ae1081e606039d5c20f",
- "reference": "cbe16b0eafe734a062ed0182381e64b9c953dccf",
+ "reference": "af7ae3cd29a1efb73cc66ae1081e606039d5c20f",
"shasum": ""
},
"require": {
@@ -1769,6 +1884,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-config": "self.version",
"zendframework/zend-console": "self.version",
"zendframework/zend-loader": "self.version",
@@ -1790,19 +1908,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\ModuleManager\\": ""
+ "Zend\\ModuleManager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-module-manager",
"keywords": [
"modulemanager",
"zf2"
],
- "time": "2015-04-01 18:09:27"
+ "time": "2015-03-23 18:29:14"
},
{
"name": "zendframework/zend-mvc",
@@ -1810,12 +1928,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-mvc.git",
- "reference": "bfff0f5f9e4d925ee13b8c159c9d6ae7e0db5412"
+ "reference": "0b4a4a829b30be510a3f215c4ff00c703ee8b431"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-mvc/zipball/0b4a4a829b30be510a3f215c4ff00c703ee8b431",
- "reference": "bfff0f5f9e4d925ee13b8c159c9d6ae7e0db5412",
+ "reference": "0b4a4a829b30be510a3f215c4ff00c703ee8b431",
"shasum": ""
},
"require": {
@@ -1826,6 +1944,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-authentication": "self.version",
"zendframework/zend-console": "self.version",
"zendframework/zend-di": "self.version",
@@ -1874,19 +1995,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Mvc\\": ""
+ "Zend\\Mvc\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-mvc",
"keywords": [
"mvc",
"zf2"
],
- "time": "2015-04-01 18:09:27"
+ "time": "2015-03-26 18:55:14"
},
{
"name": "zendframework/zend-serializer",
@@ -1894,12 +2015,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-serializer.git",
- "reference": "a46960854d6326f0036d98c9abc7a79e36e25928"
+ "reference": "3c531789a9882a5deb721356a7bd2642b65d4b09"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-serializer/zipball/3c531789a9882a5deb721356a7bd2642b65d4b09",
- "reference": "a46960854d6326f0036d98c9abc7a79e36e25928",
+ "reference": "3c531789a9882a5deb721356a7bd2642b65d4b09",
"shasum": ""
},
"require": {
@@ -1909,6 +2030,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-servicemanager": "self.version"
},
"suggest": {
@@ -1923,7 +2047,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Serializer\\": ""
+ "Zend\\Serializer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1931,12 +2055,12 @@
"BSD-3-Clause"
],
"description": "provides an adapter based interface to simply generate storable representation of PHP types by different facilities, and recover",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-serializer",
"keywords": [
"serializer",
"zf2"
],
- "time": "2015-04-01 18:09:28"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-server",
@@ -1944,12 +2068,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-server.git",
- "reference": "fc73c34490908ba143af3c57c7e166b40c4b9f8e"
+ "reference": "d11ff0bd529d202022823d4accf5983cbd50fc49"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-server/zipball/d11ff0bd529d202022823d4accf5983cbd50fc49",
- "reference": "fc73c34490908ba143af3c57c7e166b40c4b9f8e",
+ "reference": "d11ff0bd529d202022823d4accf5983cbd50fc49",
"shasum": ""
},
"require": {
@@ -1957,6 +2081,11 @@
"zendframework/zend-code": "self.version",
"zendframework/zend-stdlib": "self.version"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -1966,19 +2095,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Server\\": ""
+ "Zend\\Server\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-server",
"keywords": [
"server",
"zf2"
],
- "time": "2015-04-01 18:09:28"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-servicemanager",
@@ -1986,18 +2115,21 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-servicemanager.git",
- "reference": "d3c27c708a148a30608f313a5b7a61a531bd9cb9"
+ "reference": "57cf99fa5ac08c05a135a8d0d676c52a5e450083"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/57cf99fa5ac08c05a135a8d0d676c52a5e450083",
- "reference": "d3c27c708a148a30608f313a5b7a61a531bd9cb9",
+ "reference": "57cf99fa5ac08c05a135a8d0d676c52a5e450083",
"shasum": ""
},
"require": {
"php": ">=5.3.23"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-di": "self.version"
},
"suggest": {
@@ -2013,19 +2145,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\ServiceManager\\": ""
+ "Zend\\ServiceManager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-service-manager",
"keywords": [
"servicemanager",
"zf2"
],
- "time": "2015-04-01 18:09:28"
+ "time": "2015-03-23 18:29:14"
},
{
"name": "zendframework/zend-soap",
@@ -2033,12 +2165,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-soap.git",
- "reference": "e42b900798ea95a9063fa4922da976d8b3a8ab6f"
+ "reference": "a599463aba97ce247faf3fb443e3c7858b46449b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-soap/zipball/a599463aba97ce247faf3fb443e3c7858b46449b",
- "reference": "e42b900798ea95a9063fa4922da976d8b3a8ab6f",
+ "reference": "a599463aba97ce247faf3fb443e3c7858b46449b",
"shasum": ""
},
"require": {
@@ -2048,6 +2180,9 @@
"zendframework/zend-uri": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-http": "self.version"
},
"suggest": {
@@ -2062,19 +2197,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Soap\\": ""
+ "Zend\\Soap\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-soap",
"keywords": [
"soap",
"zf2"
],
- "time": "2015-04-01 18:09:29"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-stdlib",
@@ -2137,12 +2272,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-text.git",
- "reference": "35f519e20e575a331c2ee554e5a555a59ce4b9e2"
+ "reference": "d962ea25647b20527f3ca34ae225bbc885dabfc7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-text/zipball/d962ea25647b20527f3ca34ae225bbc885dabfc7",
- "reference": "35f519e20e575a331c2ee554e5a555a59ce4b9e2",
+ "reference": "d962ea25647b20527f3ca34ae225bbc885dabfc7",
"shasum": ""
},
"require": {
@@ -2150,6 +2285,11 @@
"zendframework/zend-servicemanager": "self.version",
"zendframework/zend-stdlib": "self.version"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -2159,19 +2299,19 @@
},
"autoload": {
"psr-4": {
- "Zend\\Text\\": ""
+ "Zend\\Text\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-text",
"keywords": [
"text",
"zf2"
],
- "time": "2015-04-01 18:09:29"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-uri",
@@ -2179,12 +2319,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-uri.git",
- "reference": "53f5b162b293f80de8b951eece8e08be83c4fe16"
+ "reference": "bd9e625639415376f6a82551c73328448d7bc7d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-uri/zipball/bd9e625639415376f6a82551c73328448d7bc7d1",
- "reference": "53f5b162b293f80de8b951eece8e08be83c4fe16",
+ "reference": "bd9e625639415376f6a82551c73328448d7bc7d1",
"shasum": ""
},
"require": {
@@ -2192,6 +2332,11 @@
"zendframework/zend-escaper": "self.version",
"zendframework/zend-validator": "self.version"
},
+ "require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master"
+ },
"type": "library",
"extra": {
"branch-alias": {
@@ -2201,7 +2346,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\Uri\\": ""
+ "Zend\\Uri\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -2209,12 +2354,12 @@
"BSD-3-Clause"
],
"description": "a component that aids in manipulating and validating » Uniform Resource Identifiers (URIs)",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-uri",
"keywords": [
"uri",
"zf2"
],
- "time": "2015-04-01 18:09:29"
+ "time": "2015-03-25 20:55:48"
},
{
"name": "zendframework/zend-validator",
@@ -2286,12 +2431,12 @@
"source": {
"type": "git",
"url": "https://github.com/zendframework/zend-view.git",
- "reference": "e119b4b5f082af58a96eb206e782b62c193227bf"
+ "reference": "37beb1ad46e530f627b4b6c3716efd728e976ba9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zendframework/zend-view/zipball/37beb1ad46e530f627b4b6c3716efd728e976ba9",
- "reference": "e119b4b5f082af58a96eb206e782b62c193227bf",
+ "reference": "37beb1ad46e530f627b4b6c3716efd728e976ba9",
"shasum": ""
},
"require": {
@@ -2301,6 +2446,9 @@
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
+ "fabpot/php-cs-fixer": "1.7.*",
+ "phpunit/phpunit": "~4.0",
+ "satooshi/php-coveralls": "dev-master",
"zendframework/zend-authentication": "self.version",
"zendframework/zend-escaper": "self.version",
"zendframework/zend-feed": "self.version",
@@ -2339,7 +2487,7 @@
},
"autoload": {
"psr-4": {
- "Zend\\View\\": ""
+ "Zend\\View\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -2347,12 +2495,12 @@
"BSD-3-Clause"
],
"description": "provides a system of helpers, output filters, and variable escaping",
- "homepage": "https://github.com/zendframework/zf2",
+ "homepage": "https://github.com/zendframework/zend-view",
"keywords": [
"view",
"zf2"
],
- "time": "2015-04-01 18:09:30"
+ "time": "2015-03-25 20:55:48"
}
],
"packages-dev": [
@@ -2515,16 +2663,16 @@
},
{
"name": "lusitanian/oauth",
- "version": "v0.3.5",
+ "version": "v0.4.1",
"source": {
"type": "git",
"url": "https://github.com/Lusitanian/PHPoAuthLib.git",
- "reference": "ac5a1cd5a4519143728dce2213936eea302edf8a"
+ "reference": "b617831ffe58564c3ae06772a8b20310929af2ea"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/ac5a1cd5a4519143728dce2213936eea302edf8a",
- "reference": "ac5a1cd5a4519143728dce2213936eea302edf8a",
+ "url": "https://api.github.com/repos/Lusitanian/PHPoAuthLib/zipball/b617831ffe58564c3ae06772a8b20310929af2ea",
+ "reference": "b617831ffe58564c3ae06772a8b20310929af2ea",
"shasum": ""
},
"require": {
@@ -2533,6 +2681,7 @@
"require-dev": {
"phpunit/phpunit": "3.7.*",
"predis/predis": "0.8.*@dev",
+ "squizlabs/php_codesniffer": "2.*",
"symfony/http-foundation": "~2.1"
},
"suggest": {
@@ -2561,6 +2710,10 @@
"name": "David Desberg",
"email": "david@daviddesberg.com"
},
+ {
+ "name": "Elliot Chance",
+ "email": "elliotchance@gmail.com"
+ },
{
"name": "Pieter Hordijk",
"email": "info@pieterhordijk.com"
@@ -2573,7 +2726,7 @@
"oauth",
"security"
],
- "time": "2014-09-05 15:19:58"
+ "time": "2015-09-09 23:42:55"
},
{
"name": "pdepend/pdepend",
@@ -3494,16 +3647,16 @@
},
{
"name": "symfony/config",
- "version": "v2.7.3",
+ "version": "v2.7.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/Config.git",
- "reference": "6c905bbed1e728226de656e4c07d620dfe9e80d9"
+ "reference": "5ab9ff48b3cb5b40951a607f77fc1cbfd29edba8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Config/zipball/6c905bbed1e728226de656e4c07d620dfe9e80d9",
- "reference": "6c905bbed1e728226de656e4c07d620dfe9e80d9",
+ "url": "https://api.github.com/repos/symfony/Config/zipball/5ab9ff48b3cb5b40951a607f77fc1cbfd29edba8",
+ "reference": "5ab9ff48b3cb5b40951a607f77fc1cbfd29edba8",
"shasum": ""
},
"require": {
@@ -3540,20 +3693,20 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
- "time": "2015-07-09 16:07:40"
+ "time": "2015-08-27 06:45:45"
},
{
"name": "symfony/dependency-injection",
- "version": "v2.7.3",
+ "version": "v2.7.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/DependencyInjection.git",
- "reference": "851e3ffe8a366b1590bdaf3df2c1395f2d27d8a6"
+ "reference": "c0a3a97b9450d77cd8eff81c5825efb3624c255b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/851e3ffe8a366b1590bdaf3df2c1395f2d27d8a6",
- "reference": "851e3ffe8a366b1590bdaf3df2c1395f2d27d8a6",
+ "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/c0a3a97b9450d77cd8eff81c5825efb3624c255b",
+ "reference": "c0a3a97b9450d77cd8eff81c5825efb3624c255b",
"shasum": ""
},
"require": {
@@ -3600,78 +3753,20 @@
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com",
- "time": "2015-07-28 14:07:07"
- },
- {
- "name": "symfony/event-dispatcher",
- "version": "v2.7.3",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/EventDispatcher.git",
- "reference": "9310b5f9a87ec2ea75d20fec0b0017c77c66dac3"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/9310b5f9a87ec2ea75d20fec0b0017c77c66dac3",
- "reference": "9310b5f9a87ec2ea75d20fec0b0017c77c66dac3",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.9"
- },
- "require-dev": {
- "psr/log": "~1.0",
- "symfony/config": "~2.0,>=2.0.5",
- "symfony/dependency-injection": "~2.6",
- "symfony/expression-language": "~2.6",
- "symfony/phpunit-bridge": "~2.7",
- "symfony/stopwatch": "~2.3"
- },
- "suggest": {
- "symfony/dependency-injection": "",
- "symfony/http-kernel": ""
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.7-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\EventDispatcher\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony EventDispatcher Component",
- "homepage": "https://symfony.com",
- "time": "2015-06-18 19:21:56"
+ "time": "2015-08-24 07:16:32"
},
{
"name": "symfony/filesystem",
- "version": "v2.7.3",
+ "version": "v2.7.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/Filesystem.git",
- "reference": "2d7b2ddaf3f548f4292df49a99d19c853d43f0b8"
+ "reference": "f079e9933799929584200b9a926f72f29e291654"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Filesystem/zipball/2d7b2ddaf3f548f4292df49a99d19c853d43f0b8",
- "reference": "2d7b2ddaf3f548f4292df49a99d19c853d43f0b8",
+ "url": "https://api.github.com/repos/symfony/Filesystem/zipball/f079e9933799929584200b9a926f72f29e291654",
+ "reference": "f079e9933799929584200b9a926f72f29e291654",
"shasum": ""
},
"require": {
@@ -3707,20 +3802,20 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
- "time": "2015-07-09 16:07:40"
+ "time": "2015-08-27 07:03:44"
},
{
"name": "symfony/stopwatch",
- "version": "v2.7.3",
+ "version": "v2.7.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/Stopwatch.git",
- "reference": "b07a866719bbac5294c67773340f97b871733310"
+ "reference": "abc61bac76fb10ffa2c6373d7932bc35190dbf3b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/b07a866719bbac5294c67773340f97b871733310",
- "reference": "b07a866719bbac5294c67773340f97b871733310",
+ "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/abc61bac76fb10ffa2c6373d7932bc35190dbf3b",
+ "reference": "abc61bac76fb10ffa2c6373d7932bc35190dbf3b",
"shasum": ""
},
"require": {
@@ -3756,20 +3851,20 @@
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
- "time": "2015-07-01 18:23:16"
+ "time": "2015-08-24 07:13:45"
},
{
"name": "symfony/yaml",
- "version": "v2.7.3",
+ "version": "v2.7.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
- "reference": "71340e996171474a53f3d29111d046be4ad8a0ff"
+ "reference": "2dc7b06c065df96cc686c66da2705e5e18aef661"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/Yaml/zipball/71340e996171474a53f3d29111d046be4ad8a0ff",
- "reference": "71340e996171474a53f3d29111d046be4ad8a0ff",
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/2dc7b06c065df96cc686c66da2705e5e18aef661",
+ "reference": "2dc7b06c065df96cc686c66da2705e5e18aef661",
"shasum": ""
},
"require": {
@@ -3805,7 +3900,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2015-07-28 14:07:07"
+ "time": "2015-08-24 07:13:45"
}
],
"aliases": [],
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php
index f9a85bef1fca7..0a3bc1d10f2dc 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php
@@ -7,6 +7,8 @@
namespace Magento\Mtf\Util\Generate\Factory;
+use Magento\Framework\Filesystem\DriverInterface;
+
/**
* Class AbstractFactory
*
@@ -103,7 +105,7 @@ protected function endFactory($type)
* @return bool
* @throws \Exception
*/
- protected function checkAndCreateFolder($folder, $mode = 0777)
+ protected function checkAndCreateFolder($folder, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE)
{
if (is_dir($folder)) {
return true;
@@ -125,7 +127,7 @@ protected function checkAndCreateFolder($folder, $mode = 0777)
* @param bool $recursive
* @return bool
*/
- protected function mkDir($dir, $mode = 0777, $recursive = true)
+ protected function mkDir($dir, $mode = 0770, $recursive = true)
{
return @mkdir($dir, $mode, $recursive);
}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php
index 3d81dda6555af..96f3f98571616 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php
@@ -27,7 +27,7 @@ class AssertDiscountInShoppingCart extends AbstractConstraint
public function processAssert(CheckoutCart $checkoutCart, Cart $cart)
{
$checkoutCart->open();
-
+ $checkoutCart->getTotalsBlock()->waitForUpdatedTotals();
\PHPUnit_Framework_Assert::assertEquals(
number_format($cart->getDiscount(), 2),
$checkoutCart->getTotalsBlock()->getDiscount(),
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php
index 6203469a9a827..318b5e531a92e 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php
@@ -15,7 +15,8 @@
*/
class AssertCustomerForgotPasswordSuccessMessage extends AbstractConstraint
{
- const SUCCESS_MESSAGE = "We'll email you a link to reset your password.";
+ const SUCCESS_MESSAGE =
+ 'If there is an account associated with %s you will receive an email with a link to reset your password.';
/**
* Assert that customer forgot password message is present on customer account forgot password page.
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Application.php b/dev/tests/integration/framework/Magento/TestFramework/Application.php
index 3aa2826ead126..18024e723b34d 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Application.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Application.php
@@ -7,6 +7,7 @@
use Magento\Framework\Autoload\AutoloaderInterface;
use Magento\Framework\Filesystem;
+use Magento\Framework\Filesystem\DriverInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\Config\ConfigOptionsListConstants;
@@ -566,7 +567,7 @@ protected function _ensureDirExists($dir)
{
if (!file_exists($dir)) {
$old = umask(0);
- mkdir($dir, 0777);
+ mkdir($dir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
umask($old);
} elseif (!is_dir($dir)) {
throw new \Magento\Framework\Exception\LocalizedException(__("'%1' is not a directory.", $dir));
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Db/Mysql.php b/dev/tests/integration/framework/Magento/TestFramework/Db/Mysql.php
index f823efc6e1b09..d34d3cefe212b 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Db/Mysql.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Db/Mysql.php
@@ -126,7 +126,7 @@ private function ensureDefaultsExtraFile()
$this->assertVarPathWritable();
$extraConfig = ['[client]', 'user=' . $this->_user, 'password="' . $this->_password . '"'];
file_put_contents($this->_defaultsExtraFile, implode(PHP_EOL, $extraConfig));
- chmod($this->_defaultsExtraFile, 0644);
+ chmod($this->_defaultsExtraFile, 0640);
}
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php
index fc753a98ceb3e..9c057a86693cb 100644
--- a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php
+++ b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php
@@ -25,7 +25,7 @@ public static function setUpBeforeClass()
'Magento\Cms\Helper\Wysiwyg\Images'
)->getCurrentPath() . 'MagentoCmsModelWysiwygImagesStorageTest';
if (!file_exists(self::$_baseDir)) {
- mkdir(self::$_baseDir, 0777);
+ mkdir(self::$_baseDir, 0770);
}
touch(self::$_baseDir . '/1.swf');
}
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
index 84ce983401b04..18a38ca094511 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php
@@ -322,10 +322,13 @@ public function testForgotPasswordPostAction()
$this->dispatch('customer/account/forgotPasswordPost');
$this->assertRedirect($this->stringContains('customer/account/'));
+
+ $message = __(
+ 'If there is an account associated with %1 you will receive an email with a link to reset your password.',
+ $email
+ );
$this->assertSessionMessages(
- $this->equalTo([
- 'We\'ll email you a link to reset your password.'
- ]),
+ $this->equalTo([$message]),
MessageInterface::TYPE_SUCCESS
);
}
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassAssignGroupTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassAssignGroupTest.php
new file mode 100644
index 0000000000000..b4bebab4c1fdd
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassAssignGroupTest.php
@@ -0,0 +1,85 @@
+customerRepository = Bootstrap::getObjectManager()->get(
+ 'Magento\Customer\Api\CustomerRepositoryInterface'
+ );
+ }
+
+ protected function tearDown()
+ {
+ /**
+ * Unset customer data
+ */
+ Bootstrap::getObjectManager()->get('Magento\Backend\Model\Session')->setCustomerData(null);
+
+ /**
+ * Unset messages
+ */
+ Bootstrap::getObjectManager()->get('Magento\Backend\Model\Session')->getMessages(true);
+ }
+
+ /**
+ * @magentoDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testMassAssignGroupAction()
+ {
+ $customer = $this->customerRepository->getById(1);
+ $this->assertEquals(1, $customer->getGroupId());
+
+ $this->getRequest()
+ ->setParam('group', 0)
+ ->setPostValue('namespace', 'customer_listing')
+ ->setPostValue('selected', [1]);
+ $this->dispatch('backend/customer/index/massAssignGroup');
+ $this->assertSessionMessages(
+ $this->equalTo(['A total of 1 record(s) were updated.']),
+ \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS
+ );
+ $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl));
+
+ $customer = $this->customerRepository->getById(1);
+ $this->assertEquals(0, $customer->getGroupId());
+ }
+
+ /**
+ * Valid group Id but no customer Ids specified
+ * @magentoDbIsolation enabled
+ */
+ public function testMassAssignGroupActionNoCustomerIds()
+ {
+ $this->getRequest()->setParam('group', 0)->setPostValue('namespace', 'customer_listing');
+ $this->dispatch('backend/customer/index/massAssignGroup');
+ $this->assertSessionMessages(
+ $this->equalTo(['Please select item(s).']),
+ \Magento\Framework\Message\MessageInterface::TYPE_ERROR
+ );
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassDeleteTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassDeleteTest.php
new file mode 100644
index 0000000000000..3b4aba93fa5da
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassDeleteTest.php
@@ -0,0 +1,62 @@
+get('Magento\Backend\Model\Session')->setCustomerData(null);
+
+ /**
+ * Unset messages
+ */
+ Bootstrap::getObjectManager()->get('Magento\Backend\Model\Session')->getMessages(true);
+ }
+
+ /**
+ * @magentoDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testMassDeleteAction()
+ {
+ $this->getRequest()->setPostValue('selected', [1])->setPostValue('namespace', 'customer_listing');
+ $this->dispatch('backend/customer/index/massDelete');
+ $this->assertSessionMessages(
+ $this->equalTo(['A total of 1 record(s) were deleted.']),
+ \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS
+ );
+ $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl));
+ }
+
+ /**
+ * Valid group Id but no customer Ids specified
+ * @magentoDbIsolation enabled
+ */
+ public function testMassDeleteActionNoCustomerIds()
+ {
+ $this->getRequest()->setPostValue('namespace', 'customer_listing');
+ $this->dispatch('backend/customer/index/massDelete');
+ $this->assertSessionMessages(
+ $this->equalTo(['Please select item(s).']),
+ \Magento\Framework\Message\MessageInterface::TYPE_ERROR
+ );
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassSubscribeTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassSubscribeTest.php
new file mode 100644
index 0000000000000..93331ad9e22c4
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Index/MassSubscribeTest.php
@@ -0,0 +1,82 @@
+get('Magento\Backend\Model\Session')->setCustomerData(null);
+
+ /**
+ * Unset messages
+ */
+ Bootstrap::getObjectManager()->get('Magento\Backend\Model\Session')->getMessages(true);
+ }
+
+ /**
+ * @magentoDataFixture Magento/Customer/_files/two_customers.php
+ */
+ public function testMassSubscriberAction()
+ {
+ // Pre-condition
+ /** @var \Magento\Newsletter\Model\SubscriberFactory $subscriberFactory */
+ $subscriberFactory = Bootstrap::getObjectManager()->get('Magento\Newsletter\Model\SubscriberFactory');
+ $this->assertNull($subscriberFactory->create()->loadByCustomerId(1)->getSubscriberStatus());
+ $this->assertNull($subscriberFactory->create()->loadByCustomerId(2)->getSubscriberStatus());
+ // Setup
+ $this->getRequest()->setPostValue('selected', [1, 2])->setPostValue('namespace', 'customer_listing');
+
+ // Test
+ $this->dispatch('backend/customer/index/massSubscribe');
+
+ // Assertions
+ $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl));
+ $this->assertSessionMessages(
+ $this->equalTo(['A total of 2 record(s) were updated.']),
+ \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS
+ );
+ $this->assertEquals(
+ Subscriber::STATUS_SUBSCRIBED,
+ $subscriberFactory->create()->loadByCustomerId(1)->getSubscriberStatus()
+ );
+ $this->assertEquals(
+ Subscriber::STATUS_SUBSCRIBED,
+ $subscriberFactory->create()->loadByCustomerId(2)->getSubscriberStatus()
+ );
+ }
+
+ /**
+ * @magentoDbIsolation enabled
+ */
+ public function testMassSubscriberActionNoSelection()
+ {
+ $this->getRequest()->setPostValue('namespace', 'customer_listing');
+ $this->dispatch('backend/customer/index/massSubscribe');
+
+ $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl));
+ $this->assertSessionMessages(
+ $this->equalTo(['Please select item(s).']),
+ \Magento\Framework\Message\MessageInterface::TYPE_ERROR
+ );
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
index 670a2eea07170..41cda6cd89487 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php
@@ -543,167 +543,6 @@ public function testProductReviewsAction()
$this->assertContains('get('Magento\Newsletter\Model\SubscriberFactory');
- $this->assertNull($subscriberFactory->create()->loadByCustomerId(1)->getSubscriberStatus());
- $this->assertNull($subscriberFactory->create()->loadByCustomerId(2)->getSubscriberStatus());
- // Setup
- $this->getRequest()->setPostValue('selected', [1, 2])->setPostValue('namespace', 'customer_listing');
-
- // Test
- $this->dispatch('backend/customer/index/massSubscribe');
-
- // Assertions
- $this->assertRedirect($this->stringContains('customer/index'));
- $this->assertSessionMessages(
- $this->equalTo(['A total of 2 record(s) were updated.']),
- \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS
- );
- $this->assertEquals(
- Subscriber::STATUS_SUBSCRIBED,
- $subscriberFactory->create()->loadByCustomerId(1)->getSubscriberStatus()
- );
- $this->assertEquals(
- Subscriber::STATUS_SUBSCRIBED,
- $subscriberFactory->create()->loadByCustomerId(2)->getSubscriberStatus()
- );
- }
-
- /**
- * @magentoDbIsolation enabled
- */
- public function testMassSubscriberActionNoSelection()
- {
- $this->getRequest()->setPostValue('namespace', 'customer_listing');
- $this->dispatch('backend/customer/index/massSubscribe');
-
- $this->assertRedirect($this->stringContains('customer/index'));
- $this->assertSessionMessages(
- $this->equalTo(['Please select item(s).']),
- \Magento\Framework\Message\MessageInterface::TYPE_ERROR
- );
- }
-
- /**
- * @magentoDataFixture Magento/Customer/_files/customer.php
- */
- public function testMassDeleteAction()
- {
- $this->getRequest()->setPostValue('selected', [1])->setPostValue('namespace', 'customer_listing');
- $this->dispatch('backend/customer/index/massDelete');
- $this->assertSessionMessages(
- $this->equalTo(['A total of 1 record(s) were deleted.']),
- \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS
- );
- $this->assertRedirect($this->stringContains('customer/index'));
- }
-
- /**
- * Valid group Id but no customer Ids specified
- * @magentoDbIsolation enabled
- */
- public function testMassDeleteActionNoCustomerIds()
- {
- $this->getRequest()->setPostValue('namespace', 'customer_listing');
- $this->dispatch('backend/customer/index/massDelete');
- $this->assertSessionMessages(
- $this->equalTo(['Please select item(s).']),
- \Magento\Framework\Message\MessageInterface::TYPE_ERROR
- );
- }
-
- /**
- * @magentoDataFixture Magento/Customer/_files/customer.php
- */
- public function testMassAssignGroupAction()
- {
- $customer = $this->customerRepository->getById(1);
- $this->assertEquals(1, $customer->getGroupId());
-
- $this->getRequest()
- ->setParam('group', 0)
- ->setPostValue('namespace', 'customer_listing')
- ->setPostValue('selected', [1]);
- $this->dispatch('backend/customer/index/massAssignGroup');
- $this->assertSessionMessages(
- $this->equalTo(['A total of 1 record(s) were updated.']),
- \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS
- );
- $this->assertRedirect($this->stringContains('customer/index'));
-
- $customer = $this->customerRepository->getById(1);
- $this->assertEquals(0, $customer->getGroupId());
- }
-
- /**
- * Valid group Id but no customer Ids specified
- * @magentoDbIsolation enabled
- */
- public function testMassAssignGroupActionNoCustomerIds()
- {
- $this->getRequest()->setParam('group', 0)->setPostValue('namespace', 'customer_listing');
- $this->dispatch('backend/customer/index/massAssignGroup');
- $this->assertSessionMessages(
- $this->equalTo(['Please select item(s).']),
- \Magento\Framework\Message\MessageInterface::TYPE_ERROR
- );
- }
-
- /**
- * @magentoDataFixture Magento/Customer/_files/two_customers.php
- */
- public function testMassUnsubscriberAction()
- {
- // Setup
- /** @var \Magento\Newsletter\Model\SubscriberFactory $subscriberFactory */
- $subscriberFactory = Bootstrap::getObjectManager()->get('Magento\Newsletter\Model\SubscriberFactory');
- $subscriberFactory->create()->subscribeCustomerById(1);
- $subscriberFactory->create()->subscribeCustomerById(2);
- $this->getRequest()->setPostValue('selected', [1, 2])->setPostValue('namespace', 'customer_listing');
-
- // Ensure secret key is disabled (subscription status notification emails turn it off)
- $this->_objectManager->get('Magento\Backend\Model\UrlInterface')->turnOffSecretKey();
-
- // Test
- $this->dispatch('backend/customer/index/massUnsubscribe');
-
- // Assertions
- $this->assertRedirect($this->stringContains('customer/index'));
- $this->assertSessionMessages(
- $this->equalTo(['A total of 2 record(s) were updated.']),
- \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS
- );
- $this->assertEquals(
- Subscriber::STATUS_UNSUBSCRIBED,
- $subscriberFactory->create()->loadByCustomerId(1)->getSubscriberStatus()
- );
- $this->assertEquals(
- Subscriber::STATUS_UNSUBSCRIBED,
- $subscriberFactory->create()->loadByCustomerId(2)->getSubscriberStatus()
- );
- }
-
- /**
- * @magentoDbIsolation enabled
- */
- public function testMassUnsubscriberActionNoSelection()
- {
- $this->getRequest()->setPostValue('namespace', 'customer_listing');
- $this->dispatch('backend/customer/index/massUnsubscribe');
-
- $this->assertRedirect($this->stringContains('customer/index'));
- $this->assertSessionMessages(
- $this->equalTo(['Please select item(s).']),
- \Magento\Framework\Message\MessageInterface::TYPE_ERROR
- );
- }
-
/**
* @magentoDataFixture Magento/Customer/_files/customer.php
* @magentoDataFixture Magento/Customer/_files/customer_address.php
diff --git a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/AddressTest.php b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/AddressTest.php
index df6a03e4fbc70..a4dd5f80b41fb 100644
--- a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/AddressTest.php
+++ b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/AddressTest.php
@@ -110,11 +110,11 @@ public function testConstruct()
// check message templates
$this->assertAttributeInternalType(
'array',
- '_messageTemplates',
+ 'errorMessageTemplates',
$this->_entityAdapter,
'Templates must be an array.'
);
- $this->assertAttributeNotEmpty('_messageTemplates', $this->_entityAdapter, 'Templates must not be empty');
+ $this->assertAttributeNotEmpty('errorMessageTemplates', $this->_entityAdapter, 'Templates must not be empty');
// check attributes
$this->assertAttributeInternalType(
@@ -398,7 +398,9 @@ public function testImportDataAddUpdate()
$result = $this->_entityAdapter->setSource(
\Magento\ImportExport\Model\Import\Adapter::findAdapterFor($sourceFile, $directoryWrite)
- )->isDataValid();
+ )
+ ->validateData()
+ ->hasToBeTerminated();
$this->assertFalse($result, 'Validation result must be false.');
// import data
@@ -492,8 +494,8 @@ public function testImportDataDelete()
$directoryWrite = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
$result = $this->_entityAdapter->setSource(
\Magento\ImportExport\Model\Import\Adapter::findAdapterFor($sourceFile, $directoryWrite)
- )->isDataValid();
- $this->assertTrue($result, 'Validation result must be true.');
+ )->validateData()->hasToBeTerminated();
+ $this->assertTrue(!$result, 'Validation result must be true.');
// import data
$this->_entityAdapter->importData();
diff --git a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerCompositeTest.php b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerCompositeTest.php
index e241fdc28639d..1ac06a6a9110a 100644
--- a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerCompositeTest.php
+++ b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerCompositeTest.php
@@ -6,6 +6,7 @@
namespace Magento\CustomerImportExport\Model\Import;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
class CustomerCompositeTest extends \PHPUnit_Framework_TestCase
{
@@ -145,19 +146,26 @@ public function testImportData($behavior, $sourceFile, array $dataBefore, array
$filesystem = $this->_objectManager->create('Magento\Framework\Filesystem');
$rootDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
+ $this->_entityAdapter->getErrorAggregator()->initValidationStrategy(
+ ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR,
+ 10
+ );
+
// set fixture CSV file
$result = $this->_entityAdapter->setSource(
\Magento\ImportExport\Model\Import\Adapter::findAdapterFor($sourceFile, $rootDirectory)
- )->isDataValid();
+ )
+ ->validateData()
+ ->hasToBeTerminated();
if ($errors) {
- $this->assertFalse($result);
- } else {
$this->assertTrue($result);
+ } else {
+ $this->assertFalse($result);
}
// assert validation errors
// can't use error codes because entity adapter gathers only error messages from aggregated adapters
- $actualErrors = array_values($this->_entityAdapter->getErrorMessages());
+ $actualErrors = array_values($this->_entityAdapter->getErrorAggregator()->getRowsGroupedByErrorCode());
$this->assertEquals($errors, $actualErrors);
// assert data before import
@@ -192,7 +200,7 @@ public function importDataDataProvider()
'$sourceFile' => $filesDirectory . self::UPDATE_FILE_NAME,
'$dataBefore' => $this->_beforeImport,
'$dataAfter' => $this->_afterImport,
- '$errors' => [[6]], // row #6 has no website
+ '$errors' => [],
];
return $sourceData;
diff --git a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerTest.php b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerTest.php
index 802d203628aaa..e9ff2b4c0045e 100644
--- a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerTest.php
+++ b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/CustomerTest.php
@@ -46,7 +46,7 @@ protected function setUp()
->create('Magento\CustomerImportExport\Model\Import\Customer');
$this->_model->setParameters(['behavior' => Import::BEHAVIOR_ADD_UPDATE]);
- $propertyAccessor = new \ReflectionProperty($this->_model, '_messageTemplates');
+ $propertyAccessor = new \ReflectionProperty($this->_model, 'errorMessageTemplates');
$propertyAccessor->setAccessible(true);
$propertyAccessor->setValue($this->_model, []);
@@ -98,7 +98,8 @@ public function testImportData()
$this->_model
->setParameters(['behavior' => Import::BEHAVIOR_ADD_UPDATE])
->setSource($source)
- ->isDataValid();
+ ->validateData()
+ ->hasToBeTerminated();
$this->_model->importData();
@@ -148,7 +149,7 @@ public function testDeleteData()
\Magento\TestFramework\Helper\Bootstrap::getInstance()
->loadArea(\Magento\Framework\App\Area::AREA_FRONTEND);
$source = new \Magento\ImportExport\Model\Import\Source\Csv(
- __DIR__ . '/_files/customers_to_import.csv',
+ __DIR__ . '/_files/customers_to_delete.csv',
$this->directoryWrite
);
@@ -158,11 +159,9 @@ public function testDeleteData()
);
$this->assertEquals(3, $customerCollection->count(), 'Count of existing customers are invalid');
- $this->_model->setParameters(
- ['behavior' => Import::BEHAVIOR_DELETE]
- )->setSource(
- $source
- )->isDataValid();
+ $this->_model->setParameters(['behavior' => Import::BEHAVIOR_DELETE])
+ ->setSource($source)
+ ->validateData();
$this->_model->importData();
@@ -178,68 +177,75 @@ public function testGetEntityTypeCode()
public function testValidateRowDuplicateEmail()
{
+ $this->_model->getErrorAggregator()->clear();
$this->_model->validateRow($this->_customerData, 0);
- $this->assertEquals(0, $this->_model->getErrorsCount());
+ $this->assertEquals(0, $this->_model->getErrorAggregator()->getErrorsCount());
$this->_customerData[Customer::COLUMN_EMAIL] = strtoupper(
$this->_customerData[Customer::COLUMN_EMAIL]
);
$this->_model->validateRow($this->_customerData, 1);
- $this->assertEquals(1, $this->_model->getErrorsCount());
- $this->assertArrayHasKey(
- Customer::ERROR_DUPLICATE_EMAIL_SITE,
- $this->_model->getErrorMessages()
+ $this->assertEquals(1, $this->_model->getErrorAggregator()->getErrorsCount());
+ $this->assertNotEmpty(
+ $this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_DUPLICATE_EMAIL_SITE]
+ )
);
}
public function testValidateRowInvalidEmail()
{
+ $this->_model->getErrorAggregator()->clear();
$this->_customerData[Customer::COLUMN_EMAIL] = 'wrong_email@format';
$this->_model->validateRow($this->_customerData, 0);
- $this->assertEquals(1, $this->_model->getErrorsCount());
- $this->assertArrayHasKey(
- Customer::ERROR_INVALID_EMAIL,
- $this->_model->getErrorMessages()
+ $this->assertEquals(1, $this->_model->getErrorAggregator()->getErrorsCount());
+ $this->assertNotEmpty(
+ $this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_INVALID_EMAIL]
+ )
);
}
public function testValidateRowInvalidWebsite()
{
+ $this->_model->getErrorAggregator()->clear();
$this->_customerData[Customer::COLUMN_WEBSITE] = 'not_existing_web_site';
$this->_model->validateRow($this->_customerData, 0);
- $this->assertEquals(1, $this->_model->getErrorsCount());
- $this->assertArrayHasKey(
- Customer::ERROR_INVALID_WEBSITE,
- $this->_model->getErrorMessages()
+ $this->assertEquals(1, $this->_model->getErrorAggregator()->getErrorsCount());
+ $this->assertNotEmpty(
+ $this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_INVALID_WEBSITE]
+ )
);
}
public function testValidateRowInvalidStore()
{
+ $this->_model->getErrorAggregator()->clear();
$this->_customerData[Customer::COLUMN_STORE] = 'not_existing_web_store';
$this->_model->validateRow($this->_customerData, 0);
- $this->assertEquals(1, $this->_model->getErrorsCount());
- $this->assertArrayHasKey(
- Customer::ERROR_INVALID_STORE,
- $this->_model->getErrorMessages()
+ $this->assertEquals(1, $this->_model->getErrorAggregator()->getErrorsCount());
+ $this->assertNotEmpty(
+ $this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_INVALID_STORE]
+ )
);
}
public function testValidateRowPasswordLengthIncorrect()
{
+ $this->_model->getErrorAggregator()->clear();
$this->_customerData['password'] = '12345';
$this->_model->validateRow($this->_customerData, 0);
- $this->assertEquals(1, $this->_model->getErrorsCount());
- $this->assertArrayHasKey(
- Customer::ERROR_PASSWORD_LENGTH, $this->_model->getErrorMessages()
+ $this->assertEquals(1, $this->_model->getErrorAggregator()->getErrorsCount());
+ $this->assertNotEmpty(
+ $this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_PASSWORD_LENGTH]
+ )
);
}
public function testValidateRowPasswordLengthCorrect()
{
+ $this->_model->getErrorAggregator()->clear();
$this->_customerData['password'] = '1234567890';
$this->_model->validateRow($this->_customerData, 0);
- $this->assertEquals(0, $this->_model->getErrorsCount());
+ $this->assertEquals(0, $this->_model->getErrorAggregator()->getErrorsCount());
}
/**
@@ -247,27 +253,33 @@ public function testValidateRowPasswordLengthCorrect()
*/
public function testValidateRowAttributeRequired()
{
+ $this->_model->getErrorAggregator()->clear();
unset($this->_customerData['firstname']);
unset($this->_customerData['lastname']);
unset($this->_customerData['group_id']);
$this->_model->validateRow($this->_customerData, 0);
- $this->assertEquals(0, $this->_model->getErrorsCount());
+ $this->assertEquals(0, $this->_model->getErrorAggregator()->getErrorsCount());
$this->_customerData[Customer::COLUMN_EMAIL] = 'new.customer@example.com';
$this->_model->validateRow($this->_customerData, 1);
- $this->assertGreaterThan(0, $this->_model->getErrorsCount());
- $this->assertArrayHasKey(Customer::ERROR_VALUE_IS_REQUIRED, $this->_model->getErrorMessages());
+ $this->assertGreaterThan(0, $this->_model->getErrorAggregator()->getErrorsCount());
+ $this->assertNotEmpty(
+ $this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_VALUE_IS_REQUIRED]
+ )
+ );
}
public function testValidateEmailForDeleteBehavior()
{
+ $this->_model->getErrorAggregator()->clear();
$this->_customerData[Customer::COLUMN_EMAIL] = 'new.customer@example.com';
$this->_model->setParameters(['behavior' => Import::BEHAVIOR_DELETE]);
$this->_model->validateRow($this->_customerData, 0);
- $this->assertGreaterThan(0, $this->_model->getErrorsCount());
- $this->assertArrayHasKey(
- Customer::ERROR_CUSTOMER_NOT_FOUND, $this->_model->getErrorMessages()
+ $this->assertGreaterThan(0, $this->_model->getErrorAggregator()->getErrorsCount());
+ $this->assertNotEmpty(
+ $this->_model->getErrorAggregator()->getErrorsByCode([Customer::ERROR_CUSTOMER_NOT_FOUND]
+ )
);
}
}
diff --git a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/address_import_update.csv b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/address_import_update.csv
index 76fbbc72911e6..936184ce967e8 100644
--- a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/address_import_update.csv
+++ b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/address_import_update.csv
@@ -1,5 +1,4 @@
"_website","_email","_entity_id","city","company","country_id","fax","firstname","lastname","middlename","postcode","prefix","region","region_id","street","suffix","telephone","vat_id","vat_is_valid","vat_request_date","vat_request_id","vat_request_success","_address_default_billing_","_address_default_shipping_"
"admin","BetsyParker@example.com",1,,,"US",,"Katy","Parker","T.",19107,,,,"1079 Rocky Road",,"215-629-9720",,,,,,,1
"admin","BetsyParker@example.com",3,"Phoenix",,"US",,"Brad","Brown","H.",85034,,"Arizona",4,"4225 Martha Street",,"928-707-1577",,,,,,1,
-"admin","JenniferCJackson@teleworm.us",4,"Tampa",,"US",,"Jennifer ","Jackson","C.",33602,,"Florida",18,"1192 Maryland Avenue",,"727-555-0854",,,,,,,
"admin","BetsyParker@example.com",,"Tallahassee",,"US",,"William ","Compton","M.",32301,,"Florida",18,"1973 Drainer Avenue",,"850-590-7403",,,,,,,
diff --git a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/customer_composite_update.csv b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/customer_composite_update.csv
index 96fa62191dff9..dfe6ee546efd0 100644
--- a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/customer_composite_update.csv
+++ b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/customer_composite_update.csv
@@ -4,4 +4,3 @@
"LoriBBanks@magento.com","admin","admin",,"05/06/2012 15:59","Admin",0,,"Lori","Female",1,"Banks","B.","7ad6dbdc83d3e9f598825dc58b84678c7351e4281f6bc2b277a32dcd88b9756b:pz",,,,0,,,0,,"Wenatchee",,"US",,"Lori","Banks",,98801,,"Washington","2573 Goodwin Avenue",,"509-421-4364",,1,1
"BetsyParker@example.com","admin","admin",,"05/06/2012 16:13","Admin",0,,"NotBetsy","Female",1,"NotParker","H.","145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1",,,,0,,,2,,"Philadelphia",,"US",,"Betsy","Parker",,19108,,"Pennsylvania","1079 Rocky Road 1079 Rocky Road 2",,"215-629-9720",,1,1
"KellyNIlson@magento.com","base","admin",,"05/06/2012 17:11","Admin",0,,"Kelly","Female",1,"Nilson","H.","145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1",,,,0,,,2,,,,,,,,,,,,,,,,,
-"MichaelJackson@magento.com",,"admin",,"05/06/2012 17:11","Admin",0,,"Michael","Male",1,"Jackson","J.","145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1",,,,0,,,2,,,,,,,,,,,,,,,,,
diff --git a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/customers_to_delete.csv b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/customers_to_delete.csv
new file mode 100644
index 0000000000000..0c7ebed0ec47d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Import/_files/customers_to_delete.csv
@@ -0,0 +1,4 @@
+email,_website,_store,confirmation,created_at,created_in,default_billing,default_shipping,disable_auto_group_change,dob,firstname,gender,group_id,lastname,middlename,password_hash,prefix,rp_token,rp_token_created_at,store_id,suffix,taxvat,website_id,password
+customer@example.com,base,admin,,5/6/2012 16:15,Admin,4,4,0,,Firstname,Male,1,Lastname,T.,145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1,,,,0,,,2,
+julie.worrell@example.com,base,admin,,5/6/2012 16:19,Admin,4,4,0,,Julie,Female,1,Worrell,T.,145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1,,,,0,,,2,
+david.lamar@example.com,base,admin,,5/6/2012 16:25,Admin,4,4,0,,David,Male,1,Lamar,T.,145d12bfff8a6a279eb61e277e3d727c0ba95acc1131237f1594ddbb7687a564:l1,,,,0,,,2,
diff --git a/dev/tests/integration/testsuite/Magento/Developer/Model/Config/Backend/AllowedIpsTest.php b/dev/tests/integration/testsuite/Magento/Developer/Model/Config/Backend/AllowedIpsTest.php
new file mode 100644
index 0000000000000..d34c64a96dc82
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Developer/Model/Config/Backend/AllowedIpsTest.php
@@ -0,0 +1,40 @@
+create(
+ 'Magento\Developer\Model\Config\Backend\AllowedIps'
+ );
+ $model->setValue($value);
+ $model->beforeSave();
+ $model->save();
+ $this->assertEquals($expected, $model->getValue());
+ }
+
+ /**
+ * @return array
+ */
+ public function fieldDataProvider()
+ {
+ return [
+ ['<'.'script>alert(\'XSS\')', '' ],
+ ['10.64.202.22, <'.'script>alert(\'XSS\')', '10.64.202.22' ]
+ ];
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Directory/WriteTest.php b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Directory/WriteTest.php
index 0388ee4f06385..54086e2990872 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Directory/WriteTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Filesystem/Directory/WriteTest.php
@@ -28,7 +28,7 @@ class WriteTest extends \PHPUnit_Framework_TestCase
*/
public function testInstance()
{
- $dir = $this->getDirectoryInstance('newDir1', 0777);
+ $dir = $this->getDirectoryInstance('newDir1', 0770);
$this->assertTrue($dir instanceof ReadInterface);
$this->assertTrue($dir instanceof WriteInterface);
}
@@ -56,10 +56,10 @@ public function testCreate($basePath, $permissions, $path)
public function createProvider()
{
return [
- ['newDir1', 0777, "newDir1"],
- ['newDir1', 0777, "root_dir1/subdir1/subdir2"],
- ['newDir2', 0755, "root_dir2/subdir"],
- ['newDir1', 0777, "."]
+ ['newDir1', 0770, "newDir1"],
+ ['newDir1', 0770, "root_dir1/subdir1/subdir2"],
+ ['newDir2', 0750, "root_dir2/subdir"],
+ ['newDir1', 0770, "."]
];
}
@@ -71,7 +71,7 @@ public function createProvider()
*/
public function testDelete($path)
{
- $directory = $this->getDirectoryInstance('newDir', 0777);
+ $directory = $this->getDirectoryInstance('newDir', 0770);
$directory->create($path);
$this->assertTrue($directory->isExist($path));
$directory->delete($path);
@@ -116,7 +116,7 @@ public function testRename($basePath, $permissions, $name, $newName)
*/
public function renameProvider()
{
- return [['newDir1', 0777, 'first_name.txt', 'second_name.txt']];
+ return [['newDir1', 0770, 'first_name.txt', 'second_name.txt']];
}
/**
@@ -150,7 +150,7 @@ public function testRenameTargetDir($firstDir, $secondDir, $permission, $name, $
*/
public function renameTargetDirProvider()
{
- return [['dir1', 'dir2', 0777, 'first_name.txt', 'second_name.txt']];
+ return [['dir1', 'dir2', 0770, 'first_name.txt', 'second_name.txt']];
}
/**
@@ -180,8 +180,8 @@ public function testCopy($basePath, $permissions, $name, $newName)
public function copyProvider()
{
return [
- ['newDir1', 0777, 'first_name.txt', 'second_name.txt'],
- ['newDir1', 0777, 'subdir/first_name.txt', 'subdir/second_name.txt']
+ ['newDir1', 0770, 'first_name.txt', 'second_name.txt'],
+ ['newDir1', 0770, 'subdir/first_name.txt', 'subdir/second_name.txt']
];
}
@@ -216,8 +216,8 @@ public function testCopyTargetDir($firstDir, $secondDir, $permission, $name, $ne
public function copyTargetDirProvider()
{
return [
- ['dir1', 'dir2', 0777, 'first_name.txt', 'second_name.txt'],
- ['dir1', 'dir2', 0777, 'subdir/first_name.txt', 'subdir/second_name.txt']
+ ['dir1', 'dir2', 0770, 'first_name.txt', 'second_name.txt'],
+ ['dir1', 'dir2', 0770, 'subdir/first_name.txt', 'subdir/second_name.txt']
];
}
@@ -226,9 +226,9 @@ public function copyTargetDirProvider()
*/
public function testChangePermissions()
{
- $directory = $this->getDirectoryInstance('newDir1', 0777);
+ $directory = $this->getDirectoryInstance('newDir1', 0770);
$directory->create('test_directory');
- $this->assertTrue($directory->changePermissions('test_directory', 0644));
+ $this->assertTrue($directory->changePermissions('test_directory', 0640));
}
/**
@@ -269,8 +269,8 @@ public function testTouch($basePath, $permissions, $path, $time)
public function touchProvider()
{
return [
- ['test_directory', 0777, 'touch_file.txt', time() - 3600],
- ['test_directory', 0777, 'subdirectory/touch_file.txt', time() - 3600]
+ ['test_directory', 0770, 'touch_file.txt', time() - 3600],
+ ['test_directory', 0770, 'subdirectory/touch_file.txt', time() - 3600]
];
}
@@ -279,7 +279,7 @@ public function touchProvider()
*/
public function testIsWritable()
{
- $directory = $this->getDirectoryInstance('newDir1', 0777);
+ $directory = $this->getDirectoryInstance('newDir1', 0770);
$directory->create('bar');
$this->assertFalse($directory->isWritable('not_existing_dir'));
$this->assertTrue($directory->isWritable('bar'));
@@ -310,8 +310,8 @@ public function testOpenFile($basePath, $permissions, $path, $mode)
public function openFileProvider()
{
return [
- ['newDir1', 0777, 'newFile.txt', 'w+'],
- ['newDir1', 0777, 'subdirectory/newFile.txt', 'w+']
+ ['newDir1', 0770, 'newFile.txt', 'w+'],
+ ['newDir1', 0770, 'subdirectory/newFile.txt', 'w+']
];
}
@@ -325,7 +325,7 @@ public function openFileProvider()
*/
public function testWriteFile($path, $content, $extraContent)
{
- $directory = $this->getDirectoryInstance('writeFileDir', 0777);
+ $directory = $this->getDirectoryInstance('writeFileDir', 0770);
$directory->writeFile($path, $content);
$this->assertEquals($content, $directory->readFile($path));
$directory->writeFile($path, $extraContent);
@@ -342,7 +342,7 @@ public function testWriteFile($path, $content, $extraContent)
*/
public function testWriteFileAppend($path, $content, $extraContent)
{
- $directory = $this->getDirectoryInstance('writeFileDir', 0777);
+ $directory = $this->getDirectoryInstance('writeFileDir', 0770);
$directory->writeFile($path, $content, 'a+');
$this->assertEquals($content, $directory->readFile($path));
$directory->writeFile($path, $extraContent, 'a+');
diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php
index 6ef46093056d6..7098903cb7e8e 100644
--- a/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php
+++ b/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php
@@ -37,7 +37,10 @@ public function testSaveValidatedBunches()
$objectManager->get('Magento\Framework\App\Config\ScopeConfigInterface'),
$objectManager->get('Magento\ImportExport\Model\ImportFactory'),
$objectManager->get('Magento\ImportExport\Model\Resource\Helper'),
- $objectManager->get('Magento\Framework\App\Resource')
+ $objectManager->get('Magento\Framework\App\Resource'),
+ $objectManager->get(
+ 'Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface'
+ )
],
'',
true,
diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php
index 788e55647ad7b..cdc7979569f1b 100644
--- a/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php
+++ b/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php
@@ -5,6 +5,8 @@
*/
namespace Magento\ImportExport\Model;
+use Magento\ImportExport\Model\Import;
+
/**
* @magentoDataFixture Magento/ImportExport/_files/import_data.php
*/
@@ -13,7 +15,7 @@ class ImportTest extends \PHPUnit_Framework_TestCase
/**
* Model object which is used for tests
*
- * @var \Magento\ImportExport\Model\Import
+ * @var Import
*/
protected $_model;
@@ -31,18 +33,24 @@ class ImportTest extends \PHPUnit_Framework_TestCase
'catalog_product' => [
'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Basic',
'code' => 'basic_behavior',
+ 'notes' => [
+ \Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE => "Note: Product IDs will be regenerated."
+ ],
],
'customer_composite' => [
'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Basic',
'code' => 'basic_behavior',
+ 'notes' => [],
],
'customer' => [
'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Custom',
'code' => 'custom_behavior',
+ 'notes' => [],
],
'customer_address' => [
'token' => 'Magento\ImportExport\Model\Source\Import\Behavior\Custom',
'code' => 'custom_behavior',
+ 'notes' => [],
],
];
@@ -82,6 +90,10 @@ public function testImportSource()
$customersCollection->resetData();
$customersCollection->clear();
+ $this->_model->setData(
+ Import::FIELD_NAME_VALIDATION_STRATEGY,
+ Import\ErrorProcessing\ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_SKIP_ERRORS
+ );
$this->_model->importSource();
$customers = $customersCollection->getItems();
diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Resource/Rule/CollectionTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Resource/Rule/CollectionTest.php
index 83c8eac50720b..d6c4a8bbcf222 100644
--- a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Resource/Rule/CollectionTest.php
+++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Resource/Rule/CollectionTest.php
@@ -18,14 +18,14 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
*/
public function testSetValidationFilter($couponCode, $expectedItems)
{
- $this->_collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+ $collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
'Magento\SalesRule\Model\Resource\Rule\Collection'
);
- $items = array_values($this->_collection->setValidationFilter(1, 0, $couponCode)->getItems());
+ $items = array_values($collection->setValidationFilter(1, 0, $couponCode)->getItems());
$ids = [];
foreach ($items as $key => $item) {
- $this->assertEquals($item->getName(), $expectedItems[$key]);
+ $this->assertEquals($expectedItems[$key], $item->getName());
if (in_array($item->getId(), $ids)) {
$this->fail('Item should be unique in result collection');
}
@@ -36,15 +36,15 @@ public function testSetValidationFilter($couponCode, $expectedItems)
public function setValidationFilterDataProvider()
{
return [
- 'Check type COUPON' => ['coupon_code', ['#1', '#2', '#5']],
+ 'Check type COUPON' => ['coupon_code', ['#1', '#5']],
'Check type NO_COUPON' => ['', ['#2', '#5']],
- 'Check type COUPON_AUTO' => ['coupon_code_auto', ['#2', '#4', '#5']],
- 'Check result with auto generated coupon' => ['autogenerated_3_1', ['#2', '#3', '#5']],
+ 'Check type COUPON_AUTO' => ['coupon_code_auto', ['#4', '#5']],
+ 'Check result with auto generated coupon' => ['autogenerated_3_1', ['#3', '#5']],
'Check result with non actual previously generated coupon' => [
'autogenerated_2_1',
['#2', '#5'],
],
- 'Check result with wrong code' => ['wrong_code', ['#2', '#5']]
+ 'Check result with wrong code' => ['wrong_code', ['#5']]
];
}
}
diff --git a/dev/tests/performance/framework/Magento/TestFramework/Application.php b/dev/tests/performance/framework/Magento/TestFramework/Application.php
index 8ce9836bbb244..f0e072b54ca3f 100644
--- a/dev/tests/performance/framework/Magento/TestFramework/Application.php
+++ b/dev/tests/performance/framework/Magento/TestFramework/Application.php
@@ -10,6 +10,7 @@
namespace Magento\TestFramework;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Filesystem\DriverInterface;
class Application
{
@@ -184,7 +185,7 @@ protected function _updateFilesystemPermissions()
)->getDirectoryWrite(
DirectoryList::VAR_DIR
);
- $varDirectory->changePermissions('', 0777);
+ $varDirectory->changePermissions('', DriverInterface::WRITEABLE_DIRECTORY_MODE);
}
/**
diff --git a/dev/tests/performance/framework/Magento/TestFramework/Performance/Bootstrap.php b/dev/tests/performance/framework/Magento/TestFramework/Performance/Bootstrap.php
index f13126d189a49..9cc810f84829a 100644
--- a/dev/tests/performance/framework/Magento/TestFramework/Performance/Bootstrap.php
+++ b/dev/tests/performance/framework/Magento/TestFramework/Performance/Bootstrap.php
@@ -9,6 +9,8 @@
*/
namespace Magento\TestFramework\Performance;
+use Magento\Framework\Filesystem\DriverInterface;
+
class Bootstrap
{
/**
@@ -64,7 +66,7 @@ public function cleanupReports()
);
}
}
- mkdir($reportDir, 0777, true);
+ mkdir($reportDir, DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
}
/**
diff --git a/dev/tests/performance/framework/tests/unit/testsuite/Magento/Test/Performance/BootstrapTest.php b/dev/tests/performance/framework/tests/unit/testsuite/Magento/Test/Performance/BootstrapTest.php
index 29a617952d587..a6b1efadac81b 100644
--- a/dev/tests/performance/framework/tests/unit/testsuite/Magento/Test/Performance/BootstrapTest.php
+++ b/dev/tests/performance/framework/tests/unit/testsuite/Magento/Test/Performance/BootstrapTest.php
@@ -93,7 +93,7 @@ public function testCleanupReportsRemovesFiles()
$bootstrap = new \Magento\TestFramework\Performance\Bootstrap($this->appBootstrap, $fixtureDir);
$reportDir = $fixtureDir . '/tmp/subdirectory/report';
- mkdir($reportDir, 0777, true);
+ mkdir($reportDir, 0770, true);
$reportFile = $reportDir . '/a.jtl';
touch($reportFile);
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php
index 70fc9300695d3..273295098e3af 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php
@@ -72,11 +72,11 @@ protected function setUp()
$this->_tmpDir = realpath(__DIR__) . '/tmp';
$this->_generationDir = $this->_tmpDir . '/generation';
if (!file_exists($this->_generationDir)) {
- mkdir($this->_generationDir, 0777, true);
+ mkdir($this->_generationDir, 0770, true);
}
$this->_compilationDir = $this->_tmpDir . '/di';
if (!file_exists($this->_compilationDir)) {
- mkdir($this->_compilationDir, 0777, true);
+ mkdir($this->_compilationDir, 0770, true);
}
$this->_command = 'php ' . $basePath . '/bin/magento setup:di:compile-multi-tenant --generation=%s --di=%s';
diff --git a/dev/tests/static/testsuite/Magento/Test/Js/Exemplar/JsHintTest.php b/dev/tests/static/testsuite/Magento/Test/Js/Exemplar/JsHintTest.php
index d02432bdb789f..48fbceed561ab 100644
--- a/dev/tests/static/testsuite/Magento/Test/Js/Exemplar/JsHintTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Js/Exemplar/JsHintTest.php
@@ -29,7 +29,7 @@ protected function setUp()
{
$reportFile = self::$_cmd->getReportFile();
if (!is_dir(dirname($reportFile))) {
- mkdir(dirname($reportFile), 0777);
+ mkdir(dirname($reportFile), 0770);
}
}
diff --git a/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php
index 3e05589de50b7..f51c544a10996 100644
--- a/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Js/LiveCodeTest.php
@@ -60,7 +60,7 @@ public static function setUpBeforeClass()
{
$reportDir = Files::init()->getPathToSource() . '/dev/tests/static/report';
if (!is_dir($reportDir)) {
- mkdir($reportDir, 0777);
+ mkdir($reportDir, 0770);
}
self::$_reportFile = $reportDir . '/js_report.txt';
@unlink(self::$_reportFile);
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
index cc7f031ee15af..f87f99bb42376 100755
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
@@ -3844,4 +3844,5 @@
'Magento\Checkout\Model\Agreements\AgreementsProviderInterface',
'Magento\CheckoutAgreements\Model\AgreementsProviderInterface'
],
+ ['Magento\Setup\Model\SampleData', 'Magento\SampleData\Model\SampleData'],
];
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php
index 38151b5a8b8d2..353b7bef2f399 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php
@@ -73,6 +73,7 @@
['DEFAULT_THEME_NAME', 'Magento\Core\Model\Design\Package'],
['DEFAULT_STORE_ID', 'Magento\Catalog\Model\AbstractModel', 'Magento\Store\Model\Store::DEFAULT_STORE_ID'],
['DEFAULT_VALUE_TABLE_PREFIX'],
+ ['DIRECTORY_PERMISSION', 'Magento\Framework\Code\Generator\Io'],
['DIVIDE_EPSILON', 'Magento\Core\Helper\Data'],
['ENTITY_PRODUCT', 'Magento\Review\Model\Review'],
['EXCEPTION_CODE_IS_GROUPED_PRODUCT'],
@@ -935,5 +936,4 @@
'Magento\Setup\Model\ConfigOptionsList',
'Magento\Framework\Config\ConfigOptionsListConstants::KEY_MODULES'
],
- ['CONFIG_PATH_RESOURCE_DEFAULT_SETUP', 'Magento\Framework\Config\ConfigOptionsListConstants'],
];
diff --git a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php
index 03153c58c0ff3..b7ee29706dcbf 100644
--- a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php
@@ -42,7 +42,7 @@ public static function setUpBeforeClass()
self::$pathToSource = Utility\Files::init()->getPathToSource();
self::$reportDir = self::$pathToSource . '/dev/tests/static/report';
if (!is_dir(self::$reportDir)) {
- mkdir(self::$reportDir, 0777);
+ mkdir(self::$reportDir, 0770);
}
}
diff --git a/dev/tools/Magento/Tools/Migration/Acl/Db/Logger/File.php b/dev/tools/Magento/Tools/Migration/Acl/Db/Logger/File.php
index 8a48285b5ce94..77761c7a1dfb9 100644
--- a/dev/tools/Magento/Tools/Migration/Acl/Db/Logger/File.php
+++ b/dev/tools/Magento/Tools/Migration/Acl/Db/Logger/File.php
@@ -6,6 +6,7 @@
namespace Magento\Tools\Migration\Acl\Db\Logger;
use InvalidArgumentException;
+use Magento\Framework\Filesystem\DriverInterface;
/**
* Db migration logger. Output result put to file
@@ -27,7 +28,7 @@ public function __construct($file)
{
$logDir = realpath(__DIR__ . '/../../') . '/log/';
if (false == is_dir($logDir)) {
- mkdir($logDir, 0777, true);
+ mkdir($logDir, DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
}
if (false == is_writeable($logDir)) {
throw new InvalidArgumentException('Directory ' . dirname($logDir) . ' is not writeable');
diff --git a/dev/tools/Magento/Tools/Migration/Acl/FileManager.php b/dev/tools/Magento/Tools/Migration/Acl/FileManager.php
index a3ea9412217cc..25c7403a9b566 100644
--- a/dev/tools/Magento/Tools/Migration/Acl/FileManager.php
+++ b/dev/tools/Magento/Tools/Migration/Acl/FileManager.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Tools\Migration\Acl;
+use Magento\Framework\Filesystem\DriverInterface;
+
class FileManager
{
/**
@@ -15,7 +17,7 @@ class FileManager
public function write($fileName, $contents)
{
if (false == is_dir(dirname($fileName))) {
- mkdir(dirname($fileName), 0777, true);
+ mkdir(dirname($fileName), DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
}
file_put_contents($fileName, $contents);
}
diff --git a/dev/tools/Magento/Tools/Migration/System/Writer/FileSystem.php b/dev/tools/Magento/Tools/Migration/System/Writer/FileSystem.php
index 4ece101c043ca..9d13f68a94f2d 100644
--- a/dev/tools/Magento/Tools/Migration/System/Writer/FileSystem.php
+++ b/dev/tools/Magento/Tools/Migration/System/Writer/FileSystem.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Tools\Migration\System\Writer;
+use Magento\Framework\Filesystem\DriverInterface;
+
class FileSystem implements \Magento\Tools\Migration\System\WriterInterface
{
/**
@@ -15,7 +17,7 @@ class FileSystem implements \Magento\Tools\Migration\System\WriterInterface
public function write($fileName, $contents)
{
if (false == is_dir(dirname($fileName))) {
- mkdir(dirname($fileName), 0777, true);
+ mkdir(dirname($fileName), DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
}
file_put_contents($fileName, $contents);
}
diff --git a/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php b/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php
index af5075ec5b566..5f48c269ec9a8 100644
--- a/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php
+++ b/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php
@@ -12,6 +12,7 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\Resource;
use Magento\Framework\Filesystem;
+use Magento\Framework\Filesystem\DriverInterface;
class Factory
{
@@ -66,7 +67,7 @@ class Factory
*/
protected $_backendOptions = [
'hashed_directory_level' => 1,
- 'hashed_directory_umask' => 0777,
+ 'hashed_directory_umask' => DriverInterface::WRITEABLE_DIRECTORY_MODE,
'file_name_prefix' => 'mage',
];
diff --git a/lib/internal/Magento/Framework/App/PageCache/Kernel.php b/lib/internal/Magento/Framework/App/PageCache/Kernel.php
index fa5ea418572cf..b065336108b9a 100644
--- a/lib/internal/Magento/Framework/App/PageCache/Kernel.php
+++ b/lib/internal/Magento/Framework/App/PageCache/Kernel.php
@@ -64,7 +64,9 @@ public function process(\Magento\Framework\App\Response\Http $response)
if (preg_match('/public.*s-maxage=(\d+)/', $response->getHeader('Cache-Control')->getFieldValue(), $matches)) {
$maxAge = $matches[1];
$response->setNoCacheHeaders();
- if ($response->getHttpResponseCode() == 200 && ($this->request->isGet() || $this->request->isHead())) {
+ if (($response->getHttpResponseCode() == 200 || $response->getHttpResponseCode() == 404)
+ && ($this->request->isGet() || $this->request->isHead())
+ ) {
$tagsHeader = $response->getHeader('X-Magento-Tags');
$tags = $tagsHeader ? explode(',', $tagsHeader->getFieldValue()) : [];
diff --git a/lib/internal/Magento/Framework/App/State/CleanupFiles.php b/lib/internal/Magento/Framework/App/State/CleanupFiles.php
index 5509d78d60dc0..a03093721c36c 100644
--- a/lib/internal/Magento/Framework/App/State/CleanupFiles.php
+++ b/lib/internal/Magento/Framework/App/State/CleanupFiles.php
@@ -52,7 +52,7 @@ public function clearCodeGeneratedFiles()
*/
public function clearCodeGeneratedClasses()
{
- return $this->emptyDir(DirectoryList::GENERATION);
+ return array_merge($this->emptyDir(DirectoryList::GENERATION), $this->emptyDir(DirectoryList::DI));
}
/**
@@ -99,7 +99,7 @@ private function emptyDir($code, $subPath = null)
return $messages;
}
foreach ($dir->search('*', $subPath) as $path) {
- if (false === strpos($path, '.')) {
+ if ($path !== '.' && $path !== '..') {
$messages[] = $dirPath . $path;
try {
$dir->delete($path);
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
index 874f847ca90ce..1028112e36aef 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/KernelTest.php
@@ -98,10 +98,12 @@ public function loadProvider()
];
}
- public function testProcessSaveCache()
+ /**
+ * @param $httpCode
+ * @dataProvider testProcessSaveCacheDataProvider
+ */
+ public function testProcessSaveCache($httpCode, $at)
{
- $httpCode = 200;
-
$cacheControlHeader = \Zend\Http\Header\CacheControl::fromString(
'Cache-Control: public, max-age=100, s-maxage=100'
);
@@ -116,21 +118,37 @@ public function testProcessSaveCache()
$this->returnValue($cacheControlHeader)
);
$this->responseMock->expects(
- $this->once()
+ $this->any()
)->method(
'getHttpResponseCode'
- )->will(
- $this->returnValue($httpCode)
- );
- $this->requestMock->expects($this->once())->method('isGet')->will($this->returnValue(true));
- $this->responseMock->expects($this->once())->method('setNoCacheHeaders');
- $this->responseMock->expects($this->at(3))->method('getHeader')->with('X-Magento-Tags');
- $this->responseMock->expects($this->at(4))->method('clearHeader')->with($this->equalTo('Set-Cookie'));
- $this->responseMock->expects($this->at(5))->method('clearHeader')->with($this->equalTo('X-Magento-Tags'));
- $this->cacheMock->expects($this->once())->method('save');
+ )->willReturn($httpCode);
+ $this->requestMock->expects($this->once())
+ ->method('isGet')
+ ->willReturn(true);
+ $this->responseMock->expects($this->once())
+ ->method('setNoCacheHeaders');
+ $this->responseMock->expects($this->at($at[0]))
+ ->method('getHeader')
+ ->with('X-Magento-Tags');
+ $this->responseMock->expects($this->at($at[1]))
+ ->method('clearHeader')
+ ->with($this->equalTo('Set-Cookie'));
+ $this->responseMock->expects($this->at($at[2]))
+ ->method('clearHeader')
+ ->with($this->equalTo('X-Magento-Tags'));
+ $this->cacheMock->expects($this->once())
+ ->method('save');
$this->kernel->process($this->responseMock);
}
+ public function testProcessSaveCacheDataProvider()
+ {
+ return [
+ [200, [3, 4, 5]],
+ [404, [4, 5, 6]]
+ ];
+ }
+
/**
* @dataProvider processNotSaveCacheProvider
* @param string $cacheControlHeader
@@ -167,13 +185,11 @@ public function processNotSaveCacheProvider()
return [
['private, max-age=100', 200, true, false],
['private, max-age=100', 200, false, false],
- ['private, max-age=100', 404, true, false],
['private, max-age=100', 500, true, false],
['no-store, no-cache, must-revalidate, max-age=0', 200, true, false],
['no-store, no-cache, must-revalidate, max-age=0', 200, false, false],
['no-store, no-cache, must-revalidate, max-age=0', 404, true, false],
['no-store, no-cache, must-revalidate, max-age=0', 500, true, false],
- ['public, max-age=100, s-maxage=100', 404, true, true],
['public, max-age=100, s-maxage=100', 500, true, true],
['public, max-age=100, s-maxage=100', 200, false, true]
];
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/State/CleanupFilesTest.php b/lib/internal/Magento/Framework/App/Test/Unit/State/CleanupFilesTest.php
index f1290dcc139bc..b9187b39772e1 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/State/CleanupFilesTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/State/CleanupFilesTest.php
@@ -31,11 +31,18 @@ protected function setUp()
public function testClearCodeGeneratedClasses()
{
- $dir = $this->getDirectoryCleanMock();
- $this->filesystem->expects($this->once())
+ $dir1 = $this->getDirectoryCleanMock();
+ $dir2 = $this->getDirectoryCleanMock();
+ $this->filesystem->expects($this->exactly(2))
->method('getDirectoryWrite')
- ->with(DirectoryList::GENERATION)
- ->willReturn($dir);
+ ->will(
+ $this->returnValueMap(
+ [
+ [DirectoryList::GENERATION, DriverPool::FILE, $dir1],
+ [DirectoryList::DI, DriverPool::FILE, $dir2],
+ ]
+ )
+ );
$this->object->clearCodeGeneratedClasses();
}
diff --git a/lib/internal/Magento/Framework/Archive/Helper/File.php b/lib/internal/Magento/Framework/Archive/Helper/File.php
index eab51af7b2c87..ec2f846f5f34c 100644
--- a/lib/internal/Magento/Framework/Archive/Helper/File.php
+++ b/lib/internal/Magento/Framework/Archive/Helper/File.php
@@ -12,6 +12,7 @@
namespace Magento\Framework\Archive\Helper;
use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Filesystem\DriverInterface;
class File
{
@@ -90,7 +91,7 @@ public function __destruct()
* @throws LocalizedException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
- public function open($mode = 'w+', $chmod = 0666)
+ public function open($mode = 'w+', $chmod = DriverInterface::WRITEABLE_FILE_MODE)
{
$this->_isInWriteMode = $this->_isWritableMode($mode);
diff --git a/lib/internal/Magento/Framework/Archive/Tar.php b/lib/internal/Magento/Framework/Archive/Tar.php
index c9e5fe5eebe9a..2f4b6f3f41a2a 100644
--- a/lib/internal/Magento/Framework/Archive/Tar.php
+++ b/lib/internal/Magento/Framework/Archive/Tar.php
@@ -12,6 +12,7 @@
namespace Magento\Framework\Archive;
use Magento\Framework\Archive\Helper\File;
+use Magento\Framework\Filesystem\DriverInterface;
class Tar extends \Magento\Framework\Archive\AbstractArchive implements \Magento\Framework\Archive\ArchiveInterface
{
@@ -378,7 +379,7 @@ protected function _composeHeader($long = false)
/**
* Read TAR string from file, and unpacked it.
- * Create files and directories information about discribed
+ * Create files and directories information about described
* in the string.
*
* @param string $destination path to file is unpacked
@@ -403,7 +404,7 @@ protected function _unpackCurrentTar($destination)
if (in_array($header['type'], ["0", chr(0), ''])) {
if (!file_exists($dirname)) {
- $mkdirResult = @mkdir($dirname, 0777, true);
+ $mkdirResult = @mkdir($dirname, DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
if (false === $mkdirResult) {
throw new \Magento\Framework\Exception\LocalizedException(
diff --git a/lib/internal/Magento/Framework/Backup/Filesystem.php b/lib/internal/Magento/Framework/Backup/Filesystem.php
index 4cd031d5a7f92..1157ed153736b 100644
--- a/lib/internal/Magento/Framework/Backup/Filesystem.php
+++ b/lib/internal/Magento/Framework/Backup/Filesystem.php
@@ -7,6 +7,7 @@
// @codingStandardsIgnoreFile
namespace Magento\Framework\Backup;
+use Magento\Framework\Filesystem\DriverInterface;
/**
* Class to work with filesystem backups
@@ -278,7 +279,7 @@ protected function _checkBackupsDir()
}
mkdir($backupsDir);
- chmod($backupsDir, 0777);
+ chmod($backupsDir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
}
if (!is_writable($backupsDir)) {
diff --git a/lib/internal/Magento/Framework/Backup/Filesystem/Rollback/Ftp.php b/lib/internal/Magento/Framework/Backup/Filesystem/Rollback/Ftp.php
index 395700ab0bb4e..d69f89ed13e61 100644
--- a/lib/internal/Magento/Framework/Backup/Filesystem/Rollback/Ftp.php
+++ b/lib/internal/Magento/Framework/Backup/Filesystem/Rollback/Ftp.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Framework\Backup\Filesystem\Rollback;
+use Magento\Framework\Filesystem\DriverInterface;
+
/**
* Rollback worker for rolling back via ftp
*
@@ -124,7 +126,7 @@ protected function _createTmpDir()
{
$tmpDir = $this->_snapshot->getBackupsDir() . '/~tmp-' . microtime(true);
- $result = @mkdir($tmpDir);
+ $result = @mkdir($tmpDir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
if (false === $result) {
throw new \Magento\Framework\Backup\Exception\NotEnoughPermissions(
diff --git a/lib/internal/Magento/Framework/Cache/InvalidateLogger.php b/lib/internal/Magento/Framework/Cache/InvalidateLogger.php
index 41c26d5370e04..42d4330b3c99c 100644
--- a/lib/internal/Magento/Framework/Cache/InvalidateLogger.php
+++ b/lib/internal/Magento/Framework/Cache/InvalidateLogger.php
@@ -53,4 +53,16 @@ private function makeParams($invalidateInfo)
$url = $this->request->getUriString();
return compact('method', 'url', 'invalidateInfo');
}
+
+ /**
+ * Log critical
+ *
+ * @param string $message
+ * @param mixed $params
+ * @return void
+ */
+ public function critical($message, $params)
+ {
+ $this->logger->critical($message, $this->makeParams($params));
+ }
}
diff --git a/lib/internal/Magento/Framework/Cache/Test/Unit/InvalidateLoggerTest.php b/lib/internal/Magento/Framework/Cache/Test/Unit/InvalidateLoggerTest.php
new file mode 100644
index 0000000000000..6c2b12725f3fd
--- /dev/null
+++ b/lib/internal/Magento/Framework/Cache/Test/Unit/InvalidateLoggerTest.php
@@ -0,0 +1,85 @@
+requestMock = $this->getMock('Magento\Framework\App\Request\Http', [], [], '', false);
+ $this->loggerMock = $this->getMock('Psr\Log\LoggerInterface', [], [], '', false);
+ $this->invalidateLogger = new \Magento\Framework\Cache\InvalidateLogger(
+ $this->requestMock,
+ $this->loggerMock
+ );
+ $this->requestMock->expects($this->once())
+ ->method('getMethod')
+ ->willReturn($this->method);
+ $this->requestMock->expects($this->once())
+ ->method('getUriString')
+ ->willReturn($this->url);
+ }
+
+ public function testCritical()
+ {
+ $this->loggerMock->expects($this->once())
+ ->method('critical')
+ ->with('message', ['method' => $this->method, 'url' => $this->url, 'invalidateInfo' => $this->params]);
+ $this->invalidateLogger->critical('message', $this->params);
+ }
+
+ public function testExecute()
+ {
+ $this->loggerMock->expects($this->once())
+ ->method('debug')
+ ->with(
+ 'cache_invalidate: ',
+ ['method' => $this->method, 'url' => $this->url, 'invalidateInfo' => $this->params]
+ );
+ $this->invalidateLogger->execute($this->params);
+ }
+
+ public function testMakeParams()
+ {
+ $expected = ['method' => $this->method, 'url' => $this->url, 'invalidateInfo' => $this->params];;
+ $method = new \ReflectionMethod($this->invalidateLogger, 'makeParams');
+ $method->setAccessible(true);
+ $this->assertEquals(
+ $expected,
+ $method->invoke($this->invalidateLogger, $this->params)
+ );
+ }
+
+ protected function tearDown()
+ {
+ unset($this->requestMock);
+ unset($this->loggerMock);
+ }
+}
diff --git a/lib/internal/Magento/Framework/Code/Generator/Io.php b/lib/internal/Magento/Framework/Code/Generator/Io.php
index 945f1879afc3b..eb6cabeebf911 100644
--- a/lib/internal/Magento/Framework/Code/Generator/Io.php
+++ b/lib/internal/Magento/Framework/Code/Generator/Io.php
@@ -6,6 +6,7 @@
namespace Magento\Framework\Code\Generator;
use Magento\Framework\Exception\FileSystemException;
+use Magento\Framework\Filesystem\DriverInterface;
class Io
{
@@ -15,11 +16,6 @@ class Io
*/
const DEFAULT_DIRECTORY = 'var/generation';
- /**
- * \Directory permission for created directories
- */
- const DIRECTORY_PERMISSION = 0777;
-
/**
* Path to directory where new file must be created
*
@@ -161,7 +157,7 @@ private function _makeDirectory($directory)
}
try {
if (!$this->filesystemDriver->isDirectory($directory)) {
- $this->filesystemDriver->createDirectory($directory, self::DIRECTORY_PERMISSION);
+ $this->filesystemDriver->createDirectory($directory, DriverInterface::WRITEABLE_DIRECTORY_MODE);
}
return true;
} catch (FileSystemException $e) {
diff --git a/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php b/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php
index 2951d806750fb..16bb120e24707 100644
--- a/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php
+++ b/lib/internal/Magento/Framework/Config/ConfigOptionsListConstants.php
@@ -22,6 +22,7 @@ class ConfigOptionsListConstants
const CONFIG_PATH_DB_CONNECTIONS = 'db/connection';
const CONFIG_PATH_DB_PREFIX = 'db/table_prefix';
const CONFIG_PATH_X_FRAME_OPT = 'x-frame-options';
+ const CONFIG_PATH_CACHE_HOSTS = 'http_cache_hosts';
/**#@-*/
/**#@+
@@ -40,6 +41,7 @@ class ConfigOptionsListConstants
const INPUT_KEY_DB_ENGINE = 'db-engine';
const INPUT_KEY_RESOURCE = 'resource';
const INPUT_KEY_SKIP_DB_VALIDATION = 'skip-db-validation';
+ const INPUT_KEY_CACHE_HOSTS = 'http-cache-hosts';
/**#@-*/
/**#@+
diff --git a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php
index 517518e4e82a5..1020fdd3e95ed 100644
--- a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php
+++ b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php
@@ -2112,44 +2112,58 @@ protected function _getColumnsDefinition(Table $table)
protected function _getIndexesDefinition(Table $table)
{
$definition = [];
- $indexes = $table->getIndexes();
- if (!empty($indexes)) {
- foreach ($indexes as $indexData) {
- if (!empty($indexData['TYPE'])) {
- switch ($indexData['TYPE']) {
- case 'primary':
- $indexType = 'PRIMARY KEY';
- unset($indexData['INDEX_NAME']);
- break;
- default:
- $indexType = strtoupper($indexData['TYPE']);
- break;
- }
- } else {
- $indexType = 'KEY';
+ $indexes = $table->getIndexes();
+ foreach ($indexes as $indexData) {
+ if (!empty($indexData['TYPE'])) {
+ //Skipping not supported fulltext indexes for NDB
+ if (($indexData['TYPE'] == AdapterInterface::INDEX_TYPE_FULLTEXT) && $this->isNdb($table)) {
+ continue;
}
+ switch ($indexData['TYPE']) {
+ case AdapterInterface::INDEX_TYPE_PRIMARY:
+ $indexType = 'PRIMARY KEY';
+ unset($indexData['INDEX_NAME']);
+ break;
+ default:
+ $indexType = strtoupper($indexData['TYPE']);
+ break;
+ }
+ } else {
+ $indexType = 'KEY';
+ }
- $columns = [];
- foreach ($indexData['COLUMNS'] as $columnData) {
- $column = $this->quoteIdentifier($columnData['NAME']);
- if (!empty($columnData['SIZE'])) {
- $column .= sprintf('(%d)', $columnData['SIZE']);
- }
- $columns[] = $column;
+ $columns = [];
+ foreach ($indexData['COLUMNS'] as $columnData) {
+ $column = $this->quoteIdentifier($columnData['NAME']);
+ if (!empty($columnData['SIZE'])) {
+ $column .= sprintf('(%d)', $columnData['SIZE']);
}
- $indexName = isset($indexData['INDEX_NAME']) ? $this->quoteIdentifier($indexData['INDEX_NAME']) : '';
- $definition[] = sprintf(
- ' %s %s (%s)',
- $indexType,
- $indexName,
- implode(', ', $columns)
- );
+ $columns[] = $column;
}
+ $indexName = isset($indexData['INDEX_NAME']) ? $this->quoteIdentifier($indexData['INDEX_NAME']) : '';
+ $definition[] = sprintf(
+ ' %s %s (%s)',
+ $indexType,
+ $indexName,
+ implode(', ', $columns)
+ );
}
return $definition;
}
+ /**
+ * Check if NDB is used for table
+ *
+ * @param Table $table
+ * @return bool
+ */
+ protected function isNdb(Table $table)
+ {
+ $engineType = strtolower($table->getOption('type'));
+ return $engineType == 'ndb' || $engineType == 'ndbcluster';
+ }
+
/**
* Retrieve table foreign keys definition array for create table
*
diff --git a/lib/internal/Magento/Framework/File/Uploader.php b/lib/internal/Magento/Framework/File/Uploader.php
index b5a0dedbbdf5b..9d41363799e1a 100644
--- a/lib/internal/Magento/Framework/File/Uploader.php
+++ b/lib/internal/Magento/Framework/File/Uploader.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Framework\File;
+use Magento\Framework\Filesystem\DriverInterface;
+
/**
* File upload class
*
@@ -221,7 +223,7 @@ public function save($destinationFolder, $newFileName = null)
$this->_result = $this->_moveFile($this->_file['tmp_name'], $destinationFile);
if ($this->_result) {
- chmod($destinationFile, 0777);
+ chmod($destinationFile, DriverInterface::WRITEABLE_DIRECTORY_MODE);
if ($this->_enableFilesDispersion) {
$fileName = str_replace('\\', '/', self::_addDirSeparator($this->_dispretionPath)) . $fileName;
}
@@ -542,7 +544,9 @@ private function _createDestinationFolder($destinationFolder)
$destinationFolder = substr($destinationFolder, 0, -1);
}
- if (!(@is_dir($destinationFolder) || @mkdir($destinationFolder, 0777, true))) {
+ if (!(@is_dir($destinationFolder)
+ || @mkdir($destinationFolder, DriverInterface::WRITEABLE_DIRECTORY_MODE, true)
+ )) {
throw new \Exception("Unable to create directory '{$destinationFolder}'.");
}
return $this;
diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php
index 2ec2a9d3c32f7..a74447f2a91ea 100644
--- a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php
+++ b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php
@@ -6,6 +6,7 @@
namespace Magento\Framework\Filesystem\Directory;
use Magento\Framework\Exception\FileSystemException;
+use Magento\Framework\Filesystem\DriverInterface;
class Write extends Read implements WriteInterface
{
@@ -14,7 +15,7 @@ class Write extends Read implements WriteInterface
*
* @var int
*/
- protected $permissions = 0777;
+ protected $permissions = DriverInterface::WRITEABLE_DIRECTORY_MODE;
/**
* Constructor
diff --git a/lib/internal/Magento/Framework/Filesystem/DriverInterface.php b/lib/internal/Magento/Framework/Filesystem/DriverInterface.php
index ac1ff792e33b3..5122787f7b046 100644
--- a/lib/internal/Magento/Framework/Filesystem/DriverInterface.php
+++ b/lib/internal/Magento/Framework/Filesystem/DriverInterface.php
@@ -14,6 +14,16 @@
*/
interface DriverInterface
{
+ /**
+ * Permissions to give read/write/execute access to owner and owning group, but not to all users
+ */
+ const WRITEABLE_DIRECTORY_MODE = 0770;
+
+ /**
+ * Permissions to give read/write access to owner and owning group, but not to all users
+ */
+ const WRITEABLE_FILE_MODE = 0660;
+
/**
*
* @param string $path
diff --git a/lib/internal/Magento/Framework/Filesystem/Io/File.php b/lib/internal/Magento/Framework/Filesystem/Io/File.php
index 4f754db62250e..b504f54b173be 100644
--- a/lib/internal/Magento/Framework/Filesystem/Io/File.php
+++ b/lib/internal/Magento/Framework/Filesystem/Io/File.php
@@ -5,6 +5,9 @@
*/
namespace Magento\Framework\Filesystem\Io;
+use Magento\Framework\Filesystem\DriverInterface;
+use Symfony\Component\Finder\Tests\Iterator\DateRangeFilterIteratorTest;
+
/**
* Filesystem client
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
@@ -298,7 +301,7 @@ public function close()
* @param bool $recursive
* @return bool
*/
- public function mkdir($dir, $mode = 0777, $recursive = true)
+ public function mkdir($dir, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE, $recursive = true)
{
$this->_cwd();
$result = @mkdir($dir, $mode, $recursive);
@@ -550,7 +553,7 @@ public function createDestinationDir($path)
* @return true
* @throws \Exception
*/
- public function checkAndCreateFolder($folder, $mode = 0777)
+ public function checkAndCreateFolder($folder, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE)
{
if (is_dir($folder)) {
return true;
diff --git a/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php b/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php
index 1f897eee69f01..f909f2cf39fdb 100644
--- a/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php
+++ b/lib/internal/Magento/Framework/Filesystem/Io/Ftp.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Framework\Filesystem\Io;
+use Magento\Framework\Filesystem\DriverInterface;
use Magento\Framework\Phrase;
use Magento\Framework\Exception\LocalizedException;
@@ -158,7 +159,7 @@ public function close()
* @return bool
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
- public function mkdir($dir, $mode = 0777, $recursive = true)
+ public function mkdir($dir, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE, $recursive = true)
{
return @ftp_mkdir($this->_conn, $dir);
}
diff --git a/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php b/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php
index 8466b51ca3728..3fd0883171139 100644
--- a/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php
+++ b/lib/internal/Magento/Framework/Filesystem/Io/IoInterface.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Framework\Filesystem\Io;
+use Magento\Framework\Filesystem\DriverInterface;
+
/**
* Input/output client interface
*/
@@ -33,7 +35,7 @@ public function close();
* @param bool $recursive
* @return bool
*/
- public function mkdir($dir, $mode = 0777, $recursive = true);
+ public function mkdir($dir, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE, $recursive = true);
/**
* Delete a directory
diff --git a/lib/internal/Magento/Framework/Filesystem/Io/Sftp.php b/lib/internal/Magento/Framework/Filesystem/Io/Sftp.php
index 69365d9885b33..9082dfd268c34 100644
--- a/lib/internal/Magento/Framework/Filesystem/Io/Sftp.php
+++ b/lib/internal/Magento/Framework/Filesystem/Io/Sftp.php
@@ -8,6 +8,8 @@
namespace Magento\Framework\Filesystem\Io;
+use Magento\Framework\Filesystem\DriverInterface;
+
/**
* Sftp client interface
*
@@ -76,7 +78,7 @@ public function close()
* @return bool
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
- public function mkdir($dir, $mode = 0777, $recursive = true)
+ public function mkdir($dir, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE, $recursive = true)
{
if ($recursive) {
$no_errors = true;
diff --git a/lib/internal/Magento/Framework/Indexer/GridStructure.php b/lib/internal/Magento/Framework/Indexer/GridStructure.php
index e7116fe3f0ef6..bdc321752fb08 100644
--- a/lib/internal/Magento/Framework/Indexer/GridStructure.php
+++ b/lib/internal/Magento/Framework/Indexer/GridStructure.php
@@ -107,22 +107,21 @@ protected function createFlatTable($tableName, array $fields)
$table->addIndex(
$this->resource->getIdxName($tableName, $name, AdapterInterface::INDEX_TYPE_INDEX),
$name,
- AdapterInterface::INDEX_TYPE_INDEX
+ ['type' => AdapterInterface::INDEX_TYPE_INDEX]
);
}
$table->addColumn($name, $type, $size);
}
- $adapter->createTable($table);
- $adapter->addIndex(
- $tableName,
+ $table->addIndex(
$this->resource->getIdxName(
$tableName,
$searchableFields,
AdapterInterface::INDEX_TYPE_FULLTEXT
),
$searchableFields,
- AdapterInterface::INDEX_TYPE_FULLTEXT
+ ['type' => AdapterInterface::INDEX_TYPE_FULLTEXT]
);
+ $adapter->createTable($table);
}
/**
diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/GridStructureTest.php b/lib/internal/Magento/Framework/Indexer/Test/Unit/GridStructureTest.php
index bf1ea53a8e9e4..cd69aa0160573 100644
--- a/lib/internal/Magento/Framework/Indexer/Test/Unit/GridStructureTest.php
+++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/GridStructureTest.php
@@ -110,9 +110,9 @@ public function testCreate()
->method('getIdxName')
->with($tableName, ['field'], AdapterInterface::INDEX_TYPE_FULLTEXT)
->willReturn($idxName);
- $this->connection->expects($this->once())
+ $table->expects($this->once())
->method('addIndex')
- ->with($tableName, $idxName, ['field'], AdapterInterface::INDEX_TYPE_FULLTEXT);
+ ->with($idxName, ['field'], ['type' => AdapterInterface::INDEX_TYPE_FULLTEXT]);
$this->object->create($index, $fields);
}
}
diff --git a/lib/internal/Magento/Framework/Logger/Handler/Base.php b/lib/internal/Magento/Framework/Logger/Handler/Base.php
index 66037768a062d..3ce02081fb651 100644
--- a/lib/internal/Magento/Framework/Logger/Handler/Base.php
+++ b/lib/internal/Magento/Framework/Logger/Handler/Base.php
@@ -54,7 +54,7 @@ public function write(array $record)
{
$logDir = $this->filesystem->getParentDirectory($this->url);
if (!$this->filesystem->isDirectory($logDir)) {
- $this->filesystem->createDirectory($logDir, 0777);
+ $this->filesystem->createDirectory($logDir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
}
parent::write($record);
diff --git a/lib/internal/Magento/Framework/Setup/BackupRollback.php b/lib/internal/Magento/Framework/Setup/BackupRollback.php
index e8b4df2c95b36..b992827bff9b5 100644
--- a/lib/internal/Magento/Framework/Setup/BackupRollback.php
+++ b/lib/internal/Magento/Framework/Setup/BackupRollback.php
@@ -13,6 +13,7 @@
use Magento\Framework\Backup\Filesystem\Helper;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem\Driver\File;
+use Magento\Framework\Filesystem\DriverInterface;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Phrase;
@@ -120,7 +121,7 @@ public function codeBackup($time, $type = Factory::TYPE_FILESYSTEM)
throw new LocalizedException(new Phrase("This backup type \'$type\' is not supported."));
}
if (!$this->file->isExists($this->backupsDir)) {
- $this->file->createDirectory($this->backupsDir, 0777);
+ $this->file->createDirectory($this->backupsDir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
}
$fsBackup->setBackupsDir($this->backupsDir);
$fsBackup->setBackupExtension('tgz');
@@ -201,7 +202,7 @@ public function dbBackup($time)
$dbBackup = $this->objectManager->create('Magento\Framework\Backup\Db');
$dbBackup->setRootDir($this->directoryList->getRoot());
if (!$this->file->isExists($this->backupsDir)) {
- $this->file->createDirectory($this->backupsDir, 0777);
+ $this->file->createDirectory($this->backupsDir, DriverInterface::WRITEABLE_DIRECTORY_MODE);
}
$dbBackup->setBackupsDir($this->backupsDir);
$dbBackup->setBackupExtension('gz');
@@ -263,8 +264,8 @@ private function setAreaCode()
/** @var \Magento\Framework\App\State $appState */
$appState = $this->objectManager->get('Magento\Framework\App\State');
$appState->setAreaCode($areaCode);
- /** @var \Magento\Framework\App\ObjectManager\ConfigLoader $configLoader */
- $configLoader = $this->objectManager->get('Magento\Framework\App\ObjectManager\ConfigLoader');
+ /** @var \Magento\Framework\ObjectManager\ConfigLoaderInterface $configLoader */
+ $configLoader = $this->objectManager->get('Magento\Framework\ObjectManager\ConfigLoaderInterface');
$this->objectManager->configure($configLoader->load($areaCode));
}
diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/BackupRollbackTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/BackupRollbackTest.php
index 23be7d1921099..3a5a6b838b0f0 100644
--- a/lib/internal/Magento/Framework/Setup/Test/Unit/BackupRollbackTest.php
+++ b/lib/internal/Magento/Framework/Setup/Test/Unit/BackupRollbackTest.php
@@ -83,7 +83,7 @@ public function setUp()
->method('get')
->will($this->returnValueMap([
['Magento\Framework\App\State', $this->getMock('Magento\Framework\App\State', [], [], '', false)],
- ['Magento\Framework\App\ObjectManager\ConfigLoader', $configLoader],
+ ['Magento\Framework\ObjectManager\ConfigLoaderInterface', $configLoader],
]));
$this->objectManager->expects($this->any())
->method('create')
@@ -107,7 +107,7 @@ public function testCodeBackup()
$this->filesystem->expects($this->once())
->method('create');
$this->file->expects($this->once())->method('isExists')->with($this->path . '/backups')->willReturn(false);
- $this->file->expects($this->once())->method('createDirectory')->with($this->path . '/backups', 0777);
+ $this->file->expects($this->once())->method('createDirectory')->with($this->path . '/backups', 0770);
$this->model->codeBackup(time());
}
@@ -158,7 +158,7 @@ public function testMediaBackup()
$this->filesystem->expects($this->once())
->method('create');
$this->file->expects($this->once())->method('isExists')->with($this->path . '/backups')->willReturn(false);
- $this->file->expects($this->once())->method('createDirectory')->with($this->path . '/backups', 0777);
+ $this->file->expects($this->once())->method('createDirectory')->with($this->path . '/backups', 0770);
$this->model->codeBackup(time(), Factory::TYPE_MEDIA);
}
diff --git a/lib/internal/Magento/Framework/System/Dirs.php b/lib/internal/Magento/Framework/System/Dirs.php
index aa8731c6fce2f..3585b2f72a2cf 100644
--- a/lib/internal/Magento/Framework/System/Dirs.php
+++ b/lib/internal/Magento/Framework/System/Dirs.php
@@ -5,6 +5,8 @@
*/
namespace Magento\Framework\System;
+use Magento\Framework\Filesystem\DriverInterface;
+
class Dirs
{
/**
@@ -73,7 +75,7 @@ public static function rm($dirname)
* @return true
* @throws \Exception
*/
- public static function mkdirStrict($path, $recursive = true, $mode = 0777)
+ public static function mkdirStrict($path, $recursive = true, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE)
{
$exists = file_exists($path);
if ($exists && is_dir($path)) {
diff --git a/lib/internal/Magento/Framework/System/Ftp.php b/lib/internal/Magento/Framework/System/Ftp.php
index b36bd07f8f5d2..3aa7a858f6b96 100644
--- a/lib/internal/Magento/Framework/System/Ftp.php
+++ b/lib/internal/Magento/Framework/System/Ftp.php
@@ -6,6 +6,8 @@
namespace Magento\Framework\System;
+use Magento\Framework\Filesystem\DriverInterface;
+
/**
* Class to work with remote FTP server
*/
@@ -50,7 +52,7 @@ public function mdkir($name)
* @param int $mode
* @return bool
*/
- public function mkdirRecursive($path, $mode = 0777)
+ public function mkdirRecursive($path, $mode = DriverInterface::WRITEABLE_DIRECTORY_MODE)
{
$this->checkConnected();
$dir = explode("/", $path);
@@ -217,7 +219,7 @@ public function raw($cmd)
* @return bool
* @throws \Exception
*/
- public function upload($remote, $local, $dirMode = 0777, $ftpMode = FTP_BINARY)
+ public function upload($remote, $local, $dirMode = DriverInterface::WRITEABLE_DIRECTORY_MODE, $ftpMode = FTP_BINARY)
{
$this->checkConnected();
diff --git a/lib/internal/Magento/Framework/UrlInterface/Proxy.php b/lib/internal/Magento/Framework/UrlInterface/Proxy.php
deleted file mode 100644
index 7ed1a1bbc7bff..0000000000000
--- a/lib/internal/Magento/Framework/UrlInterface/Proxy.php
+++ /dev/null
@@ -1,212 +0,0 @@
-_objectManager = $objectManager;
- $this->_instanceName = $instanceName;
- $this->_isShared = $shared;
- }
-
- /**
- * @return array
- */
- public function __sleep()
- {
- return ['_subject', '_isShared'];
- }
-
- /**
- * Retrieve ObjectManager from global scope
- *
- * @return void
- */
- public function __wakeup()
- {
- $this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
- }
-
- /**
- * Clone proxied instance
- *
- * @return void
- */
- public function __clone()
- {
- $this->_subject = clone $this->_getSubject();
- }
-
- /**
- * Get proxied instance
- *
- * @return \Magento\Framework\UrlInterface
- */
- protected function _getSubject()
- {
- if (!$this->_subject) {
- $this->_subject = true === $this->_isShared
- ? $this->_objectManager->get($this->_instanceName)
- : $this->_objectManager->create($this->_instanceName);
- }
- return $this->_subject;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getUseSession()
- {
- return $this->_getSubject()->getUseSession();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getBaseUrl($params = [])
- {
- return $this->_getSubject()->getBaseUrl($params);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getCurrentUrl()
- {
- return $this->_getSubject()->getCurrentUrl();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRouteUrl($routePath = null, $routeParams = null)
- {
- return $this->_getSubject()->getRouteUrl($routePath, $routeParams);
- }
-
- /**
- * {@inheritdoc}
- */
- public function addSessionParam()
- {
- return $this->_getSubject()->addSessionParam();
- }
-
- /**
- * {@inheritdoc}
- */
- public function addQueryParams(array $data)
- {
- return $this->_getSubject()->addQueryParams($data);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setQueryParam($key, $data)
- {
- return $this->_getSubject()->setQueryParam($key, $data);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getUrl($routePath = null, $routeParams = null)
- {
- return $this->_getSubject()->getUrl($routePath, $routeParams);
- }
-
- /**
- * {@inheritdoc}
- */
- public function escape($value)
- {
- return $this->_getSubject()->escape($value);
- }
-
- /**
- * {@inheritdoc}
- */
- public function getDirectUrl($url, $params = [])
- {
- return $this->_getSubject()->getDirectUrl($url, $params);
- }
-
- /**
- * {@inheritdoc}
- */
- public function sessionUrlVar($html)
- {
- return $this->_getSubject()->sessionUrlVar($html);
- }
-
- /**
- * {@inheritdoc}
- */
- public function isOwnOriginUrl()
- {
- return $this->_getSubject()->isOwnOriginUrl();
- }
-
- /**
- * {@inheritdoc}
- */
- public function getRedirectUrl($url)
- {
- return $this->_getSubject()->getRedirectUrl($url);
- }
-
- /**
- * {@inheritdoc}
- */
- public function setScope($params)
- {
- return $this->_getSubject()->setScope($params);
- }
-}
diff --git a/pub/errors/processor.php b/pub/errors/processor.php
index edbbb4dd60204..81b797f62f310 100644
--- a/pub/errors/processor.php
+++ b/pub/errors/processor.php
@@ -4,6 +4,7 @@
* See COPYING.txt for license details.
*/
namespace Magento\Framework\Error;
+use Magento\Framework\Filesystem\DriverInterface;
/**
* Error processor
@@ -453,11 +454,11 @@ public function saveReport($reportData)
$this->_setReportData($reportData);
if (!file_exists($this->_reportDir)) {
- @mkdir($this->_reportDir, 0777, true);
+ @mkdir($this->_reportDir, DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
}
@file_put_contents($this->_reportFile, serialize($reportData));
- @chmod($this->_reportFile, 0777);
+ @chmod($this->_reportFile, DriverInterface::WRITEABLE_FILE_MODE);
if (isset($reportData['skin']) && self::DEFAULT_SKIN != $reportData['skin']) {
$this->_setSkin($reportData['skin']);
diff --git a/setup/config/states.disable.config.php b/setup/config/states.disable.config.php
new file mode 100644
index 0000000000000..68be2c6193ad2
--- /dev/null
+++ b/setup/config/states.disable.config.php
@@ -0,0 +1,79 @@
+ [
+ 'disable' => 'Disable ',
+ ],
+ 'navUpdater' => [
+ [
+ 'id' => 'root.readiness-check-disable',
+ 'url' => 'readiness-check-disable',
+ 'templateUrl' => "{$base}/readiness-check-updater",
+ 'title' => "Readiness \n Check",
+ 'header' => 'Step 1: Readiness Check',
+ 'nav' => true,
+ 'order' => 2,
+ 'type' => 'disable'
+ ],
+ [
+ 'id' => 'root.readiness-check-disable.progress',
+ 'url' => 'readiness-check-disable/progress',
+ 'templateUrl' => "$base/readiness-check-updater/progress",
+ 'title' => 'Readiness Check',
+ 'header' => 'Step 1: Readiness Check',
+ 'controller' => 'readinessCheckController',
+ 'nav' => false,
+ 'order' => 3,
+ 'type' => 'disable'
+ ],
+ [
+ 'id' => 'root.create-backup-disable',
+ 'url' => 'create-backup',
+ 'templateUrl' => "$base/create-backup",
+ 'title' => "Create \n Backup",
+ 'header' => 'Step 2: Create Backup',
+ 'controller' => 'createBackupController',
+ 'nav' => true,
+ 'validate' => true,
+ 'order' => 4,
+ 'type' => 'disable'
+ ],
+ [
+ 'id' => 'root.create-backup-disable.progress',
+ 'url' => 'create-backup/progress',
+ 'templateUrl' => "$base/complete-backup/progress",
+ 'title' => "Create \n Backup",
+ 'header' => 'Step 2: Create Backup',
+ 'controller' => 'completeBackupController',
+ 'nav' => false,
+ 'order' => 5,
+ 'type' => 'disable'
+ ],
+ [
+ 'id' => 'root.start-updater-disable',
+ 'url' => 'disable',
+ 'templateUrl' => "$base/start-updater",
+ 'title' => "Disable",
+ 'controller' => 'startUpdaterController',
+ 'header' => 'Step 3: Disable',
+ 'nav' => true,
+ 'order' => 6,
+ 'type' => 'disable'
+ ],
+ [
+ 'id' => 'root.disable-success',
+ 'url' => 'disable-success',
+ 'templateUrl' => "$base/updater-success",
+ 'controller' => 'updaterSuccessController',
+ 'order' => 7,
+ 'main' => true,
+ 'noMenu' => true
+ ],
+ ],
+];
diff --git a/setup/config/states.enable.config.php b/setup/config/states.enable.config.php
new file mode 100644
index 0000000000000..b019ea139440f
--- /dev/null
+++ b/setup/config/states.enable.config.php
@@ -0,0 +1,79 @@
+ [
+ 'enable' => 'Enable ',
+ ],
+ 'navUpdater' => [
+ [
+ 'id' => 'root.readiness-check-enable',
+ 'url' => 'readiness-check-enable',
+ 'templateUrl' => "{$base}/readiness-check-updater",
+ 'title' => "Readiness \n Check",
+ 'header' => 'Step 1: Readiness Check',
+ 'nav' => true,
+ 'order' => 2,
+ 'type' => 'enable'
+ ],
+ [
+ 'id' => 'root.readiness-check-enable.progress',
+ 'url' => 'readiness-check-enable/progress',
+ 'templateUrl' => "$base/readiness-check-updater/progress",
+ 'title' => 'Readiness Check',
+ 'header' => 'Step 1: Readiness Check',
+ 'controller' => 'readinessCheckController',
+ 'nav' => false,
+ 'order' => 3,
+ 'type' => 'enable'
+ ],
+ [
+ 'id' => 'root.create-backup-enable',
+ 'url' => 'create-backup',
+ 'templateUrl' => "$base/create-backup",
+ 'title' => "Create \n Backup",
+ 'header' => 'Step 2: Create Backup',
+ 'controller' => 'createBackupController',
+ 'nav' => true,
+ 'validate' => true,
+ 'order' => 4,
+ 'type' => 'enable'
+ ],
+ [
+ 'id' => 'root.create-backup-enable.progress',
+ 'url' => 'create-backup/progress',
+ 'templateUrl' => "$base/complete-backup/progress",
+ 'title' => "Create \n Backup",
+ 'header' => 'Step 2: Create Backup',
+ 'controller' => 'completeBackupController',
+ 'nav' => false,
+ 'order' => 5,
+ 'type' => 'enable'
+ ],
+ [
+ 'id' => 'root.start-updater-enable',
+ 'url' => 'enable',
+ 'templateUrl' => "$base/start-updater",
+ 'title' => "Enable Module",
+ 'controller' => 'startUpdaterController',
+ 'header' => 'Step 3: Enable Module',
+ 'nav' => true,
+ 'order' => 6,
+ 'type' => 'enable'
+ ],
+ [
+ 'id' => 'root.enable-success',
+ 'url' => 'enable-success',
+ 'templateUrl' => "$base/updater-success",
+ 'controller' => 'updaterSuccessController',
+ 'order' => 7,
+ 'main' => true,
+ 'noMenu' => true
+ ],
+ ],
+];
diff --git a/setup/config/states.uninstall.config.php b/setup/config/states.uninstall.config.php
index 726ecce7ca147..fa9bfcf9d6d6e 100644
--- a/setup/config/states.uninstall.config.php
+++ b/setup/config/states.uninstall.config.php
@@ -59,15 +59,15 @@
'id' => 'root.data-option',
'url' => 'data-option',
'templateUrl' => "$base/data-option",
- 'title' => "Data \n Option",
+ 'title' => "Remove or \n Keep Data",
'controller' => 'dataOptionController',
- 'header' => 'Step 3: Data Option',
+ 'header' => 'Step 3: Remove or Keep Data',
'nav' => true,
'order' => 6,
'type' => 'uninstall'
],
[
- 'id' => 'root.uninstall',
+ 'id' => 'root.start-updater-uninstall',
'url' => 'uninstall',
'templateUrl' => "$base/start-updater",
'title' => "Uninstall",
diff --git a/setup/pub/magento/setup/component-grid.js b/setup/pub/magento/setup/component-grid.js
index 7ab76cf0592e2..33f1055f9733b 100644
--- a/setup/pub/magento/setup/component-grid.js
+++ b/setup/pub/magento/setup/component-grid.js
@@ -83,6 +83,8 @@ angular.module('component-grid', ['ngStorage'])
if ($scope.isAvailableUpdatePackage(component.name)) {
return indicators.info[type];
+ } else if(component.disable === true) {
+ return indicators.off[type];
}
return indicators.on[type];
};
@@ -115,6 +117,23 @@ angular.module('component-grid', ['ngStorage'])
$state.go('root.readiness-check-uninstall');
};
+ $scope.enableDisable = function(type, component) {
+ if (component.type.indexOf('module') >= 0 ) {
+ $localStorage.packages = [
+ {
+ name: component.moduleName
+ }
+ ];
+ if ($localStorage.titles[type].indexOf(component.moduleName) < 0 ) {
+ $localStorage.titles[type] = type.charAt(0).toUpperCase() + type.slice(1) + ' '
+ + component.moduleName;
+ }
+ $localStorage.componentType = component.type;
+ $localStorage.moduleName = component.moduleName;
+ $state.go('root.readiness-check-'+type);
+ }
+ };
+
$scope.convertDate = function(date) {
return new Date(date);
}
diff --git a/setup/pub/magento/setup/create-backup.js b/setup/pub/magento/setup/create-backup.js
index 66547e1c31bd5..31a08c930ddfb 100644
--- a/setup/pub/magento/setup/create-backup.js
+++ b/setup/pub/magento/setup/create-backup.js
@@ -33,12 +33,10 @@ angular.module('create-backup', ['ngStorage'])
};
$scope.goToStartUpdater = function () {
- if ($state.current.type === 'update') {
- $state.go('root.start-updater-update');
- } else if ($state.current.type === 'upgrade') {
- $state.go('root.start-updater-upgrade');
- } else if ($state.current.type === 'uninstall') {
+ if ($state.current.type === 'uninstall') {
$state.go('root.data-option');
+ } else {
+ $state.go('root.start-updater-' + $state.current.type);
}
}
diff --git a/setup/pub/magento/setup/readiness-check.js b/setup/pub/magento/setup/readiness-check.js
index 451c380b18688..fbbbdf1540e6d 100644
--- a/setup/pub/magento/setup/readiness-check.js
+++ b/setup/pub/magento/setup/readiness-check.js
@@ -13,11 +13,37 @@ angular.module('readiness-check', [])
$scope.startProgress = function() {
++$scope.progressCounter;
};
- if ($state.current.type !== 'uninstall') {
- $scope.dependencyUrl = 'index.php/environment/component-dependency';
- } else {
- $scope.dependencyUrl = 'index.php/environment/uninstall-dependency-check';
+ $scope.componentDependency = {
+ visible: false,
+ processed: false,
+ expanded: false,
+ isRequestError: false,
+ errorMessage: '',
+ packages: null
};
+ switch ($state.current.type) {
+ case 'uninstall':
+ $scope.dependencyUrl = 'index.php/environment/uninstall-dependency-check';
+ if ($localStorage.packages) {
+ $scope.componentDependency.packages = $localStorage.packages;
+ }
+ break;
+ case 'enable':
+ case 'disable':
+ $scope.dependencyUrl = 'index.php/environment/enable-disable-dependency-check';
+ if ($localStorage.packages) {
+ $scope.componentDependency.packages = {
+ type: $state.current.type,
+ packages: $localStorage.packages
+ };
+ }
+ break;
+ default:
+ $scope.dependencyUrl = 'index.php/environment/component-dependency';
+ if ($localStorage.packages) {
+ $scope.componentDependency.packages = $localStorage.packages;
+ }
+ }
$scope.stopProgress = function() {
--$scope.progressCounter;
if ($scope.progressCounter == COUNTER) {
@@ -37,7 +63,6 @@ angular.module('readiness-check', [])
$rootScope.hasErrors = true;
$scope.stopProgress();
};
-
$scope.completed = false;
$scope.hasErrors = false;
@@ -82,17 +107,6 @@ angular.module('readiness-check', [])
setupNoticeMessage: '',
updaterNoticeMessage: ''
};
- $scope.componentDependency = {
- visible: false,
- processed: false,
- expanded: false,
- isRequestError: false,
- errorMessage: '',
- packages: null
- };
- if ($localStorage.packages) {
- $scope.componentDependency.packages = $localStorage.packages;
- }
$scope.items = {
'php-version': {
url:'index.php/environment/php-version',
diff --git a/setup/pub/magento/setup/start-updater.js b/setup/pub/magento/setup/start-updater.js
index 57cab0fe5a4c8..f67b2c414c8a9 100644
--- a/setup/pub/magento/setup/start-updater.js
+++ b/setup/pub/magento/setup/start-updater.js
@@ -64,12 +64,10 @@ angular.module('start-updater', ['ngStorage'])
});
}
$scope.goToPreviousState = function() {
- if ($state.current.type === 'update') {
- $state.go('root.create-backup-update');
- } else if ($state.current.type === 'upgrade') {
- $state.go('root.create-backup-upgrade');
- } else if ($state.current.type === 'uninstall') {
+ if ($state.current.type === 'uninstall') {
$state.go('root.data-option');
+ } else {
+ $state.go('root.create-backup-' + $state.current.type);
}
}
}]);
diff --git a/setup/pub/magento/setup/success.js b/setup/pub/magento/setup/success.js
index a7581e40de242..b5996ef3242cb 100644
--- a/setup/pub/magento/setup/success.js
+++ b/setup/pub/magento/setup/success.js
@@ -25,4 +25,6 @@ angular.module('success', ['ngStorage'])
}
$scope.messages = $localStorage.messages;
$localStorage.$reset();
+ $scope.admin.password = '';
+ $scope.db.password = '';
}]);
diff --git a/setup/src/Magento/Setup/Console/Command/AbstractModuleCommand.php b/setup/src/Magento/Setup/Console/Command/AbstractModuleCommand.php
index dd75e0392ebaa..4dacaa2e3a768 100644
--- a/setup/src/Magento/Setup/Console/Command/AbstractModuleCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/AbstractModuleCommand.php
@@ -84,15 +84,14 @@ protected function cleanup(InputInterface $input, OutputInterface $output)
/** @var \Magento\Framework\App\State\CleanupFiles $cleanupFiles */
$cleanupFiles = $this->objectManager->get('Magento\Framework\App\State\CleanupFiles');
$cleanupFiles->clearCodeGeneratedClasses();
- $output->writeln('Generated classes cleared successfully. ');
+ $output->writeln('Generated classes cleared successfully. Please re-run Magento compile command ');
if ($input->getOption(self::INPUT_KEY_CLEAR_STATIC_CONTENT)) {
$cleanupFiles->clearMaterializedViewFiles();
$output->writeln('Generated static view files cleared successfully. ');
} else {
$output->writeln(
- 'Alert: Generated static view files were not cleared.'
- . ' You can clear them using the --' . self::INPUT_KEY_CLEAR_STATIC_CONTENT . ' option.'
- . ' Failure to clear static view files might cause display issues in the Admin and storefront. '
+ 'Info: Some modules might require static view files to be cleared. Use the optional --' .
+ self::INPUT_KEY_CLEAR_STATIC_CONTENT . ' option to clear them. '
);
}
}
diff --git a/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php b/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php
index 644ee7dbcfa7b..9264ae87da061 100644
--- a/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php
@@ -82,7 +82,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$output->writeln(
"Unable to change status of modules because of the following constraints: "
);
- $output->writeln('' . implode("\n", $constraints) . ' ');
+ $output->writeln('' . implode(" \n", $constraints) . ' ');
return;
}
}
diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
index 941d21c21a712..95cac1be21853 100644
--- a/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Setup\Console\Command;
+use Magento\Framework\Filesystem\DriverInterface;
use Magento\Setup\Model\ObjectManagerProvider;
use Magento\Framework\App\ObjectManager;
use Symfony\Component\Console\Input\InputInterface;
@@ -350,8 +351,9 @@ private function compileCode($generationDir, $fileExcludePatterns, $input)
$directoryInstancesNamesList->getList($generationDir);
$relations = $directoryInstancesNamesList->getRelations();
// 2.2 Compression
- if (!file_exists(dirname($relationsFile))) {
- mkdir(dirname($relationsFile), 0777, true);
+ $relationsFileDir = dirname($relationsFile);
+ if (!file_exists($relationsFileDir)) {
+ mkdir($relationsFileDir, DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
}
$relations = array_filter($relations);
file_put_contents($relationsFile, $serializer->serialize($relations));
@@ -367,8 +369,9 @@ private function compileCode($generationDir, $fileExcludePatterns, $input)
}
}
$outputContent = $serializer->serialize($pluginDefinitions);
- if (!file_exists(dirname($pluginDefFile))) {
- mkdir(dirname($pluginDefFile), 0777, true);
+ $pluginDefFileDir = dirname($pluginDefFile);
+ if (!file_exists($pluginDefFileDir)) {
+ mkdir($pluginDefFileDir, DriverInterface::WRITEABLE_DIRECTORY_MODE, true);
}
file_put_contents($pluginDefFile, $outputContent);
}
diff --git a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php
index 7197865542cd5..e5605051d48d7 100644
--- a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php
@@ -54,5 +54,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
$installer->updateModulesSequence();
$installer->installSchema();
$installer->installDataFixtures();
+ $output->writeln('Please re-run Magento compile command ');
}
}
diff --git a/setup/src/Magento/Setup/Controller/ComponentGrid.php b/setup/src/Magento/Setup/Controller/ComponentGrid.php
index e94f06c941833..cb68dc558aaa1 100644
--- a/setup/src/Magento/Setup/Controller/ComponentGrid.php
+++ b/setup/src/Magento/Setup/Controller/ComponentGrid.php
@@ -7,6 +7,8 @@
namespace Magento\Setup\Controller;
use Magento\Framework\Composer\ComposerInformation;
+use Magento\Framework\Module\FullModuleList;
+use Magento\Framework\Module\ModuleList;
use Magento\Framework\Module\PackageInfo;
use Magento\Setup\Model\ObjectManagerProvider;
use Zend\Mvc\Controller\AbstractActionController;
@@ -20,33 +22,50 @@
class ComponentGrid extends AbstractActionController
{
/**
- * @var ComposerInformation
+ * @var \Magento\Framework\Composer\ComposerInformation
*/
private $composerInformation;
/**
* Module package info
*
- * @var PackageInfo
+ * @var \Magento\Framework\Module\PackageInfo
*/
private $packageInfo;
/**
- * @var UpdatePackagesCache
+ * Enabled Module info
+ *
+ * @var \Magento\Framework\Module\ModuleList
+ */
+ private $enabledModuleList;
+
+ /**
+ * Full Module info
+ *
+ * @var \Magento\Framework\Module\FullModuleList
+ */
+ private $fullModuleList;
+
+ /**
+ * @var \Magento\Setup\Model\UpdatePackagesCache
*/
private $updatePackagesCache;
/**
- * @param ComposerInformation $composerInformation
- * @param ObjectManagerProvider $objectManagerProvider
- * @param UpdatePackagesCache $updatePackagesCache
+ * @param \Magento\Framework\Composer\ComposerInformation $composerInformation
+ * @param \Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider
+ * @param \Magento\Setup\Model\UpdatePackagesCache $updatePackagesCache
*/
public function __construct(
- ComposerInformation $composerInformation,
- ObjectManagerProvider $objectManagerProvider,
- UpdatePackagesCache $updatePackagesCache
+ \Magento\Framework\Composer\ComposerInformation $composerInformation,
+ \Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider,
+ \Magento\Setup\Model\UpdatePackagesCache $updatePackagesCache
) {
$this->composerInformation = $composerInformation;
+ $objectManager = $objectManagerProvider->get();
+ $this->enabledModuleList = $objectManager->get('Magento\Framework\Module\ModuleList');
+ $this->fullModuleList = $objectManager->get('Magento\Framework\Module\FullModuleList');
$this->packageInfo = $objectManagerProvider->get()
->get('Magento\Framework\Module\PackageInfoFactory')->create();
$this->updatePackagesCache = $updatePackagesCache;
@@ -74,11 +93,15 @@ public function componentsAction()
{
$lastSyncData = $this->updatePackagesCache->getPackagesForUpdate();
$components = $this->composerInformation->getInstalledMagentoPackages();
+ $allModules = $this->getAllModules();
+ $components = array_replace_recursive($components, $allModules);
foreach ($components as $component) {
$components[$component['name']]['update'] = false;
$components[$component['name']]['uninstall'] = false;
+ $components[$component['name']]['moduleName'] = $this->packageInfo->getModuleName($component['name']);
if ($this->composerInformation->isPackageInComposerJson($component['name'])
&& ($component['type'] !== ComposerInformation::METAPACKAGE_PACKAGE_TYPE)) {
+ $components[$component['name']]['uninstall'] = true;
if (isset($lastSyncData['packages'][$component['name']]['latestVersion'])
&& version_compare(
$lastSyncData['packages'][$component['name']]['latestVersion'],
@@ -86,14 +109,18 @@ public function componentsAction()
'>'
)) {
$components[$component['name']]['update'] = true;
- $components[$component['name']]['uninstall'] = true;
- } else {
- $components[$component['name']]['uninstall'] = true;
}
}
+ if ($component['type'] === ComposerInformation::MODULE_PACKAGE_TYPE) {
+ $components[$component['name']]['enable'] =
+ $this->enabledModuleList->has($components[$component['name']]['moduleName']);
+ $components[$component['name']]['disable'] = !$components[$component['name']]['enable'];
+ } else {
+ $components[$component['name']]['enable'] = false;
+ $components[$component['name']]['disable'] = false;
+ }
$componentNameParts = explode('/', $component['name']);
$components[$component['name']]['vendor'] = $componentNameParts[0];
- $components[$component['name']]['moduleName'] = $this->packageInfo->getModuleName($component['name']);
}
return new JsonModel(
[
@@ -121,4 +148,22 @@ public function syncAction()
]
);
}
+
+ /**
+ * Get full list of modules as an associative array
+ *
+ * @return array
+ */
+ private function getAllModules()
+ {
+ $modules = [];
+ $allModules = $this->fullModuleList->getNames();
+ foreach ($allModules as $module) {
+ $moduleName = $this->packageInfo->getPackageName($module);
+ $modules[$moduleName]['name'] = $moduleName;
+ $modules[$moduleName]['type'] = ComposerInformation::MODULE_PACKAGE_TYPE;
+ $modules[$moduleName]['version'] = $this->packageInfo->getVersion($module);
+ }
+ return $modules;
+ }
}
diff --git a/setup/src/Magento/Setup/Controller/CustomizeYourStore.php b/setup/src/Magento/Setup/Controller/CustomizeYourStore.php
index 34d8ca58eb95b..fe24ddcd5e586 100644
--- a/setup/src/Magento/Setup/Controller/CustomizeYourStore.php
+++ b/setup/src/Magento/Setup/Controller/CustomizeYourStore.php
@@ -5,32 +5,42 @@
*/
namespace Magento\Setup\Controller;
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Filesystem;
+use Magento\Framework\Module\ModuleList;
use Magento\Framework\Setup\Lists;
-use Magento\Setup\Model\SampleData;
+use Magento\Setup\Model\ObjectManagerProvider;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\View\Model\JsonModel;
class CustomizeYourStore extends AbstractActionController
{
+ /**
+ * @var ModuleList
+ */
+ protected $moduleList;
+
/**
* @var Lists
*/
protected $list;
/**
- * @var SampleData
+ * @var ObjectManagerProvider
*/
- protected $sampleData;
+ protected $objectManagerProvider;
/**
+ * @param ModuleList $moduleList
* @param Lists $list
- * @param SampleData $sampleData
+ * @param ObjectManagerProvider $objectManagerProvider
*/
- public function __construct(Lists $list, SampleData $sampleData)
+ public function __construct(ModuleList $moduleList, Lists $list, ObjectManagerProvider $objectManagerProvider)
{
+ $this->moduleList = $moduleList;
$this->list = $list;
- $this->sampleData = $sampleData;
+ $this->objectManagerProvider = $objectManagerProvider;
}
/**
@@ -38,13 +48,24 @@ public function __construct(Lists $list, SampleData $sampleData)
*/
public function indexAction()
{
+ $sampleDataDeployed = $this->moduleList->has('Magento_SampleData');
+ if ($sampleDataDeployed) {
+ /** @var \Magento\SampleData\Model\SampleData $sampleData */
+ $sampleData = $this->objectManagerProvider->get()->get('Magento\SampleData\Model\SampleData');
+ $isSampleDataInstalled = $sampleData->isInstalledSuccessfully();
+ $isSampleDataErrorInstallation = $sampleData->isInstallationError();
+ } else {
+ $isSampleDataInstalled = false;
+ $isSampleDataErrorInstallation = false;
+ }
+
$view = new ViewModel([
'timezone' => $this->list->getTimezoneList(),
'currency' => $this->list->getCurrencyList(),
'language' => $this->list->getLocaleList(),
- 'isSampledataEnabled' => $this->sampleData->isDeployed(),
- 'isSampleDataInstalled' => $this->sampleData->isInstalledSuccessfully(),
- 'isSampleDataErrorInstallation' => $this->sampleData->isInstallationError()
+ 'isSampledataEnabled' => $sampleDataDeployed,
+ 'isSampleDataInstalled' => $isSampleDataInstalled,
+ 'isSampleDataErrorInstallation' => $isSampleDataErrorInstallation
]);
$view->setTerminal(true);
return $view;
diff --git a/setup/src/Magento/Setup/Controller/Environment.php b/setup/src/Magento/Setup/Controller/Environment.php
index 44f26361c7ae2..57c8a509abadf 100644
--- a/setup/src/Magento/Setup/Controller/Environment.php
+++ b/setup/src/Magento/Setup/Controller/Environment.php
@@ -16,6 +16,8 @@
use Magento\Setup\Model\FilePermissions;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
+use Magento\Setup\Model\ModuleStatusFactory;
+use Magento\Framework\Module\Status;
/**
* Class Environment
@@ -66,6 +68,13 @@ class Environment extends AbstractActionController
*/
protected $phpReadinessCheck;
+ /**
+ * Module/Status Object
+ *
+ * @var Status
+ */
+ protected $moduleStatus;
+
/**
* Constructor
*
@@ -75,6 +84,7 @@ class Environment extends AbstractActionController
* @param DependencyReadinessCheck $dependencyReadinessCheck
* @param UninstallDependencyCheck $uninstallDependencyCheck
* @param PhpReadinessCheck $phpReadinessCheck
+ * @param ModuleStatusFactory $moduleStatusFactory
*/
public function __construct(
FilePermissions $permissions,
@@ -82,7 +92,8 @@ public function __construct(
CronScriptReadinessCheck $cronScriptReadinessCheck,
DependencyReadinessCheck $dependencyReadinessCheck,
UninstallDependencyCheck $uninstallDependencyCheck,
- PhpReadinessCheck $phpReadinessCheck
+ PhpReadinessCheck $phpReadinessCheck,
+ ModuleStatusFactory $moduleStatusFactory
) {
$this->permissions = $permissions;
$this->filesystem = $filesystem;
@@ -90,6 +101,7 @@ public function __construct(
$this->dependencyReadinessCheck = $dependencyReadinessCheck;
$this->uninstallDependencyCheck = $uninstallDependencyCheck;
$this->phpReadinessCheck = $phpReadinessCheck;
+ $this->moduleStatus = $moduleStatusFactory->create();
}
/**
@@ -285,4 +297,53 @@ public function uninstallDependencyCheckAction()
$data['responseType'] = $responseType;
return new JsonModel($data);
}
+
+ /**
+ * Verifies component dependency for enable/disable actions
+ *
+ * @return JsonModel
+ */
+ public function enableDisableDependencyCheckAction()
+ {
+ $responseType = ResponseTypeInterface::RESPONSE_TYPE_SUCCESS;
+ $data = Json::decode($this->getRequest()->getContent(), Json::TYPE_ARRAY);
+
+ try {
+ if (empty($data['packages'])) {
+ throw new \Exception('No packages have been found.');
+ }
+
+ if (empty($data['type'])) {
+ throw new \Exception('Can not determine the flow.');
+ }
+
+ $modules = $data['packages'];
+
+ $isEnable = ($data['type'] !== 'disable');
+
+ $modulesToChange = [];
+ foreach ($modules as $module) {
+ if (!isset($module['name'])) {
+ throw new \Exception('Can not find module name.');
+ }
+ $modulesToChange[] = $module['name'];
+ }
+
+ $constraints = $this->moduleStatus->checkConstraints($isEnable, $modulesToChange);
+ $data = [];
+
+ if ($constraints) {
+ $data['errorMessage'] = "Unable to change status of modules because of the following constraints: "
+ . implode(" ", $constraints);
+ $responseType = ResponseTypeInterface::RESPONSE_TYPE_ERROR;
+ }
+
+ } catch (\Exception $e) {
+ $responseType = ResponseTypeInterface::RESPONSE_TYPE_ERROR;
+ $data['errorMessage'] = $e->getMessage();
+ }
+
+ $data['responseType'] = $responseType;
+ return new JsonModel($data);
+ }
}
diff --git a/setup/src/Magento/Setup/Controller/StartUpdater.php b/setup/src/Magento/Setup/Controller/StartUpdater.php
index da4f1c3517803..b55e16a738b09 100644
--- a/setup/src/Magento/Setup/Controller/StartUpdater.php
+++ b/setup/src/Magento/Setup/Controller/StartUpdater.php
@@ -7,10 +7,11 @@
namespace Magento\Setup\Controller;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Module\FullModuleList;
use Magento\Setup\Model\Cron\JobComponentUninstall;
use Zend\Json\Json;
use Zend\Mvc\Controller\AbstractActionController;
-use Magento\Setup\Model\Updater as ModelUpdater;
+use Magento\Setup\Model\Updater;
use Zend\View\Model\JsonModel;
use Zend\View\Model\ViewModel;
@@ -41,23 +42,31 @@ class StartUpdater extends AbstractActionController
private $navigation;
/**
- * @var ModelUpdater
+ * @var \Magento\Setup\Model\Updater
*/
private $updater;
+ /**
+ * @var \Magento\Framework\Module\FullModuleList
+ */
+ private $moduleList;
+
/**
* @param \Magento\Framework\Filesystem $filesystem
* @param \Magento\Setup\Model\Navigation $navigation
- * @param ModelUpdater $updater
+ * @param \Magento\Setup\Model\Updater $updater
+ * @param \Magento\Framework\Module\FullModuleList $moduleList
*/
public function __construct(
\Magento\Framework\Filesystem $filesystem,
\Magento\Setup\Model\Navigation $navigation,
- ModelUpdater $updater
+ \Magento\Setup\Model\Updater $updater,
+ \Magento\Framework\Module\FullModuleList $moduleList
) {
$this->filesystem = $filesystem;
$this->navigation = $navigation;
$this->updater = $updater;
+ $this->moduleList = $moduleList;
}
/**
@@ -90,20 +99,26 @@ public function updateAction()
$packages = $postPayload[self::KEY_POST_PACKAGES];
$jobType = $postPayload[self::KEY_POST_JOB_TYPE];
$this->createTypeFlag($jobType, $postPayload[self::KEY_POST_HEADER_TITLE]);
+
$additionalOptions = [];
- if ($jobType == 'uninstall') {
- $additionalOptions = [
- JobComponentUninstall::DATA_OPTION => $postPayload[self::KEY_POST_DATA_OPTION]
- ];
- $cronTaskType = \Magento\Setup\Model\Cron\JobFactory::COMPONENT_UNINSTALL;
- } else {
- $cronTaskType = ModelUpdater::TASK_TYPE_UPDATE;
- }
+ $cronTaskType = '';
+ $this->getCronTaskConfigInfo($jobType, $postPayload, $additionalOptions, $cronTaskType);
+
$errorMessage .= $this->updater->createUpdaterTask(
$packages,
$cronTaskType,
$additionalOptions
);
+
+ // for module enable job types, we need to follow up with 'setup:upgrade' task to
+ // make sure enabled modules are properly registered
+ if ($jobType == 'enable') {
+ $errorMessage .= $this->updater->createUpdaterTask(
+ [],
+ \Magento\Setup\Model\Cron\JobFactory::JOB_UPGRADE,
+ []
+ );
+ }
}
} else {
$errorMessage .= 'Invalid request';
@@ -120,16 +135,52 @@ public function updateAction()
*/
private function validatePayload(array $postPayload)
{
- $errorMessage = '';
- $packages = $postPayload[self::KEY_POST_PACKAGES];
$jobType = $postPayload[self::KEY_POST_JOB_TYPE];
- if ($jobType == 'uninstall' && !isset($postPayload[self::KEY_POST_DATA_OPTION])) {
- $errorMessage .= 'Missing dataOption' . PHP_EOL;
+ $errorMessage = '';
+ switch($jobType) {
+ case 'uninstall':
+ $errorMessage = $this->validateUninstallPayload($postPayload);
+ break;
+
+ case 'update':
+ $errorMessage = $this->validateUpdatePayload($postPayload);
+ break;
+
+ case 'enable':
+ case 'disable':
+ $errorMessage = $this->validateEnableDisablePayload($postPayload);
+ break;
}
+ return $errorMessage;
+ }
+
+ /**
+ * Validate 'uninstall' job type payload
+ *
+ * @param array $postPayload
+ * @return string
+ */
+ private function validateUninstallPayload(array $postPayload)
+ {
+ $errorMessage = '';
+ if (!isset($postPayload[self::KEY_POST_DATA_OPTION])) {
+ $errorMessage = 'Missing dataOption' . PHP_EOL;
+ }
+ return $errorMessage;
+ }
+
+ /**
+ * Validate 'update' job type payload
+ *
+ * @param array $postPayload
+ * @return string
+ */
+ private function validateUpdatePayload(array $postPayload)
+ {
+ $errorMessage = '';
+ $packages = $postPayload[self::KEY_POST_PACKAGES];
foreach ($packages as $package) {
- if (!isset($package[self::KEY_POST_PACKAGE_NAME])
- || ($jobType != 'uninstall' && !isset($package[self::KEY_POST_PACKAGE_VERSION]))
- ) {
+ if ((!isset($package[self::KEY_POST_PACKAGE_NAME])) || (!isset($package[self::KEY_POST_PACKAGE_VERSION]))) {
$errorMessage .= 'Missing package information' . PHP_EOL;
break;
}
@@ -137,6 +188,25 @@ private function validatePayload(array $postPayload)
return $errorMessage;
}
+ /**
+ * Validate 'enable/disable' job type payload
+ *
+ * @param array $postPayload
+ * @return string
+ */
+ private function validateEnableDisablePayload(array $postPayload)
+ {
+ $errorMessage = '';
+ $packages = $postPayload[self::KEY_POST_PACKAGES];
+ foreach ($packages as $package) {
+ if (!$this->moduleList->has($package[self::KEY_POST_PACKAGE_NAME])) {
+ $errorMessage .= 'Invalid Magento module name: ' . $package[self::KEY_POST_PACKAGE_NAME] . PHP_EOL;
+ break;
+ }
+ }
+ return $errorMessage;
+ }
+
/**
* Create flag to be used in Updater
*
@@ -161,4 +231,39 @@ private function createTypeFlag($type, $title)
$directoryWrite = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
$directoryWrite->writeFile('.type.json', Json::encode($data));
}
+
+ /**
+ * Returns cron config info based on passed in job type
+ *
+ * @param string $jobType
+ * @param array $postPayload
+ * @param array $addtionalOptions
+ * @param string $cronTaskType
+ * @return void
+ */
+ private function getCronTaskConfigInfo($jobType, $postPayload, &$additionalOptions, &$cronTaskType)
+ {
+ $additionalOptions = [];
+ switch($jobType) {
+ case 'uninstall':
+ $additionalOptions = [
+ JobComponentUninstall::DATA_OPTION => $postPayload[self::KEY_POST_DATA_OPTION]
+ ];
+ $cronTaskType = \Magento\Setup\Model\Cron\JobFactory::JOB_COMPONENT_UNINSTALL;
+ break;
+
+ case 'upgrade':
+ case 'update':
+ $cronTaskType = \Magento\Setup\Model\Updater::TASK_TYPE_UPDATE;
+ break;
+
+ case 'enable':
+ $cronTaskType = \Magento\Setup\Model\Cron\JobFactory::JOB_MODULE_ENABLE;
+ break;
+
+ case 'disable':
+ $cronTaskType = \Magento\Setup\Model\Cron\JobFactory::JOB_MODULE_DISABLE;
+ break;
+ }
+ }
}
diff --git a/setup/src/Magento/Setup/Controller/Success.php b/setup/src/Magento/Setup/Controller/Success.php
index 02c7b4750982d..5bb2dd9f6e056 100644
--- a/setup/src/Magento/Setup/Controller/Success.php
+++ b/setup/src/Magento/Setup/Controller/Success.php
@@ -5,23 +5,31 @@
*/
namespace Magento\Setup\Controller;
+use Magento\Framework\Module\ModuleList;
+use Magento\Setup\Model\ObjectManagerProvider;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
-use Magento\Setup\Model\SampleData;
class Success extends AbstractActionController
{
/**
- * @var SampleData
+ * @var ModuleList
*/
- protected $sampleData;
+ protected $moduleList;
/**
- * @param SampleData $sampleData
+ * @var ObjectManagerProvider
*/
- public function __construct(SampleData $sampleData)
+ protected $objectManagerProvider;
+
+ /**
+ * @param ModuleList $moduleList
+ * @param ObjectManagerProvider $objectManagerProvider
+ */
+ public function __construct(ModuleList $moduleList, ObjectManagerProvider $objectManagerProvider)
{
- $this->sampleData = $sampleData;
+ $this->moduleList = $moduleList;
+ $this->objectManagerProvider = $objectManagerProvider;
}
/**
@@ -29,8 +37,15 @@ public function __construct(SampleData $sampleData)
*/
public function indexAction()
{
+ if ($this->moduleList->has('Magento_SampleData')) {
+ /** @var \Magento\SampleData\Model\SampleData $sampleData */
+ $sampleData = $this->objectManagerProvider->get()->get('Magento\SampleData\Model\SampleData');
+ $isSampleDataErrorInstallation = $sampleData->isInstallationError();
+ } else {
+ $isSampleDataErrorInstallation = false;
+ }
$view = new ViewModel([
- 'isSampleDataErrorInstallation' => $this->sampleData->isInstallationError()
+ 'isSampleDataErrorInstallation' => $isSampleDataErrorInstallation
]);
$view->setTerminal(true);
return $view;
diff --git a/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php b/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php
index 0112fd010caef..a5b6ad9b38dcf 100644
--- a/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php
+++ b/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php
@@ -654,7 +654,13 @@ public function execute()
/** @var \Magento\ImportExport\Model\Import $import */
$import = $this->fixtureModel->getObjectManager()->create(
'Magento\ImportExport\Model\Import',
- ['data' => ['entity' => 'catalog_product', 'behavior' => 'append']]
+ [
+ 'data' => [
+ 'entity' => 'catalog_product',
+ 'behavior' => 'append',
+ 'validation_strategy' => 'validation-stop-on-errors'
+ ]
+ ]
);
$source = new Generator($pattern, $configurablesCount);
diff --git a/setup/src/Magento/Setup/Fixtures/CustomersFixture.php b/setup/src/Magento/Setup/Fixtures/CustomersFixture.php
index c2390cd989164..2f65fe6f2301c 100644
--- a/setup/src/Magento/Setup/Fixtures/CustomersFixture.php
+++ b/setup/src/Magento/Setup/Fixtures/CustomersFixture.php
@@ -91,10 +91,16 @@ public function execute()
'_address_default_shipping_' => '1',
];
$generator = new Generator($pattern, $customersNumber);
- /** @var Magento\ImportExport\Model\Import $import */
+ /** @var \Magento\ImportExport\Model\Import $import */
$import = $this->fixtureModel->getObjectManager()->create(
'Magento\ImportExport\Model\Import',
- ['data' => ['entity' => 'customer_composite', 'behavior' => 'append']]
+ [
+ 'data' => [
+ 'entity' => 'customer_composite',
+ 'behavior' => 'append',
+ 'validation_strategy' => 'validation-stop-on-errors'
+ ]
+ ]
);
// it is not obvious, but the validateSource() will actually save import queue data to DB
$import->validateSource($generator);
diff --git a/setup/src/Magento/Setup/Fixtures/FixtureModel.php b/setup/src/Magento/Setup/Fixtures/FixtureModel.php
index a51eb57d44e42..9c3c3f424d2d9 100644
--- a/setup/src/Magento/Setup/Fixtures/FixtureModel.php
+++ b/setup/src/Magento/Setup/Fixtures/FixtureModel.php
@@ -171,9 +171,12 @@ public function getObjectManager()
*/
public function initObjectManager()
{
- $this->getObjectManager()->configure(
- $this->getObjectManager()->get('Magento\Framework\App\ObjectManager\ConfigLoader')->load(self::AREA_CODE)
- );
+ $this->getObjectManager()
+ ->configure(
+ $this->getObjectManager()
+ ->get('Magento\Framework\ObjectManager\ConfigLoaderInterface')
+ ->load(self::AREA_CODE)
+ );
$this->getObjectManager()->get('Magento\Framework\Config\ScopeInterface')->setCurrentScope(self::AREA_CODE);
return $this;
}
diff --git a/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php b/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php
index ab977626ac4d6..0c60626964571 100644
--- a/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php
+++ b/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php
@@ -84,7 +84,13 @@ public function execute()
/** @var \Magento\ImportExport\Model\Import $import */
$import = $this->fixtureModel->getObjectManager()->create(
'Magento\ImportExport\Model\Import',
- ['data' => ['entity' => 'catalog_product', 'behavior' => 'append']]
+ [
+ 'data' => [
+ 'entity' => 'catalog_product',
+ 'behavior' => 'append',
+ 'validation_strategy' => 'validation-stop-on-errors'
+ ]
+ ]
);
// it is not obvious, but the validateSource() will actually save import queue data to DB
$import->validateSource($generator);
diff --git a/setup/src/Magento/Setup/Model/ConfigGenerator.php b/setup/src/Magento/Setup/Model/ConfigGenerator.php
index 491f60d9d2643..db1e6727b703f 100644
--- a/setup/src/Magento/Setup/Model/ConfigGenerator.php
+++ b/setup/src/Magento/Setup/Model/ConfigGenerator.php
@@ -238,4 +238,30 @@ public function createModeConfig()
$configData->set(State::PARAM_MODE, State::MODE_DEFAULT);
return $configData;
}
+
+ /**
+ * Creates cache hosts config data
+ *
+ * @param array $data
+ * @return ConfigData
+ */
+ public function createCacheHostsConfig(array $data)
+ {
+ $configData = new ConfigData(ConfigFilePool::APP_ENV);
+ if (isset($data[ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS])) {
+ $hostData = explode(',', $data[ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS]);
+ $hosts = [];
+ foreach ($hostData as $data) {
+ $dataArray = explode(':', trim($data));
+ $host = [];
+ $host['host'] = $dataArray[0];
+ if (isset($dataArray[1])) {
+ $host['port'] = $dataArray[1];
+ }
+ $hosts[] = $host;
+ }
+ $configData->set(ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS, $hosts);
+ }
+ return $configData;
+ }
}
diff --git a/setup/src/Magento/Setup/Model/ConfigModel.php b/setup/src/Magento/Setup/Model/ConfigModel.php
index 5f481a0f5db80..8a4a82ef416f0 100644
--- a/setup/src/Magento/Setup/Model/ConfigModel.php
+++ b/setup/src/Magento/Setup/Model/ConfigModel.php
@@ -119,7 +119,7 @@ public function process($inputOptions)
}
- $this->writer->saveConfig($fileConfigStorage);
+ $this->writer->saveConfig($fileConfigStorage, true);
}
/**
diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList.php b/setup/src/Magento/Setup/Model/ConfigOptionsList.php
index 18d89da6394cb..1011731e112dc 100644
--- a/setup/src/Magento/Setup/Model/ConfigOptionsList.php
+++ b/setup/src/Magento/Setup/Model/ConfigOptionsList.php
@@ -47,6 +47,7 @@ public function __construct(ConfigGenerator $configGenerator, DbValidator $dbVal
/**
* {@inheritdoc}
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function getOptions()
{
@@ -141,6 +142,12 @@ public function getOptions()
'If specified, then db connection validation will be skipped',
'-s'
),
+ new TextConfigOption(
+ ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS,
+ TextConfigOption::FRONTEND_WIZARD_TEXT,
+ ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS,
+ 'http Cache hosts'
+ ),
];
}
@@ -161,6 +168,7 @@ public function createConfig(array $data, DeploymentConfig $deploymentConfig)
$configData[] = $this->configGenerator->createResourceConfig();
$configData[] = $this->configGenerator->createXFrameConfig();
$configData[] = $this->configGenerator->createModeConfig();
+ $configData[] = $this->configGenerator->createCacheHostsConfig($data);
return $configData;
}
@@ -171,35 +179,22 @@ public function validate(array $options, DeploymentConfig $deploymentConfig)
{
$errors = [];
- if (isset($options[ConfigOptionsListConstants::INPUT_KEY_DB_PREFIX])) {
- try {
- $this->dbValidator->checkDatabaseTablePrefix($options[ConfigOptionsListConstants::INPUT_KEY_DB_PREFIX]);
- } catch (\InvalidArgumentException $exception) {
- $errors[] = $exception->getMessage();
- }
+ if (isset($options[ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS])) {
+ $errors = array_merge(
+ $errors,
+ $this->validateHttpCacheHosts($options[ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS])
+ );
}
- if (!$options[ConfigOptionsListConstants::INPUT_KEY_SKIP_DB_VALIDATION] &&
- (
- $options[ConfigOptionsListConstants::INPUT_KEY_DB_NAME] !== null
- || $options[ConfigOptionsListConstants::INPUT_KEY_DB_HOST] !== null
- || $options[ConfigOptionsListConstants::INPUT_KEY_DB_USER] !== null
- || $options[ConfigOptionsListConstants::INPUT_KEY_DB_PASSWORD] !== null
- )
- ) {
- try {
-
- $options = $this->getDbSettings($options, $deploymentConfig);
+ if (isset($options[ConfigOptionsListConstants::INPUT_KEY_DB_PREFIX])) {
+ $errors = array_merge(
+ $errors,
+ $this->validateDbPrefix($options[ConfigOptionsListConstants::INPUT_KEY_DB_PREFIX])
+ );
+ }
- $this->dbValidator->checkDatabaseConnection(
- $options[ConfigOptionsListConstants::INPUT_KEY_DB_NAME],
- $options[ConfigOptionsListConstants::INPUT_KEY_DB_HOST],
- $options[ConfigOptionsListConstants::INPUT_KEY_DB_USER],
- $options[ConfigOptionsListConstants::INPUT_KEY_DB_PASSWORD]
- );
- } catch (\Exception $exception) {
- $errors[] = $exception->getMessage();
- }
+ if (!$options[ConfigOptionsListConstants::INPUT_KEY_SKIP_DB_VALIDATION]) {
+ $errors = array_merge($errors, $this->validateDbSettings($options, $deploymentConfig));
}
$errors = array_merge(
@@ -296,4 +291,70 @@ private function validateEncryptionKey(array $options)
return $errors;
}
+
+ /**
+ * Validate http cache hosts
+ *
+ * @param string $option
+ * @return string[]
+ */
+ private function validateHttpCacheHosts($option)
+ {
+ $errors = [];
+ if (!preg_match('/^[a-zA-Z0-9_:,.]+$/', $option)
+ ) {
+ $errors[] = "Invalid http cache hosts '{$option}'";
+ }
+ return $errors;
+ }
+
+ /**
+ * Validate Db table prefix
+ *
+ * @param string $option
+ * @return string[]
+ */
+ private function validateDbPrefix($option)
+ {
+ $errors = [];
+ try {
+ $this->dbValidator->checkDatabaseTablePrefix($option);
+ } catch (\InvalidArgumentException $exception) {
+ $errors[] = $exception->getMessage();
+ }
+ return $errors;
+ }
+
+ /**
+ * Validate Db settings
+ *
+ * @param array $options
+ * @param DeploymentConfig $deploymentConfig
+ * @return string[]
+ */
+ private function validateDbSettings(array $options, DeploymentConfig $deploymentConfig)
+ {
+ $errors = [];
+
+ if ($options[ConfigOptionsListConstants::INPUT_KEY_DB_NAME] !== null
+ || $options[ConfigOptionsListConstants::INPUT_KEY_DB_HOST] !== null
+ || $options[ConfigOptionsListConstants::INPUT_KEY_DB_USER] !== null
+ || $options[ConfigOptionsListConstants::INPUT_KEY_DB_PASSWORD] !== null
+ ) {
+ try {
+
+ $options = $this->getDbSettings($options, $deploymentConfig);
+
+ $this->dbValidator->checkDatabaseConnection(
+ $options[ConfigOptionsListConstants::INPUT_KEY_DB_NAME],
+ $options[ConfigOptionsListConstants::INPUT_KEY_DB_HOST],
+ $options[ConfigOptionsListConstants::INPUT_KEY_DB_USER],
+ $options[ConfigOptionsListConstants::INPUT_KEY_DB_PASSWORD]
+ );
+ } catch (\Exception $exception) {
+ $errors[] = $exception->getMessage();
+ }
+ }
+ return $errors;
+ }
}
diff --git a/setup/src/Magento/Setup/Model/Cron/AbstractJob.php b/setup/src/Magento/Setup/Model/Cron/AbstractJob.php
index 55945296a048f..a1f356cb3c7ed 100644
--- a/setup/src/Magento/Setup/Model/Cron/AbstractJob.php
+++ b/setup/src/Magento/Setup/Model/Cron/AbstractJob.php
@@ -7,6 +7,8 @@
use Magento\Setup\Console\Command\AbstractSetupCommand;
use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Framework\App\Cache;
+use Magento\Setup\Model\ObjectManagerProvider;
/**
* Abstract class for jobs run by setup:cron:run command
@@ -33,21 +35,46 @@ abstract class AbstractJob
*/
protected $params;
+ /**
+ * @var \Magento\Framework\App\Cache
+ */
+ protected $cache;
+
+ /**
+ * @var \Magento\Framework\App\State\CleanupFiles
+ */
+ protected $cleanupFiles;
+
+ /**
+ * @var Status
+ */
+ protected $status;
+
/**
* Constructor
*
* @param OutputInterface $output
* @param Status $status
+ * @param ObjectManagerProvider $objectManagerProvider
* @param string $name
* @param array $params
*/
- public function __construct(OutputInterface $output, Status $status, $name, array $params = [])
- {
+ public function __construct(
+ OutputInterface $output,
+ Status $status,
+ ObjectManagerProvider $objectManagerProvider,
+ $name,
+ array $params = []
+ ) {
$this->output = $output;
$this->status = $status;
$this->name = $name;
$this->params = $params;
+
+ $objectManager = $objectManagerProvider->get();
+ $this->cleanupFiles = $objectManager->get('Magento\Framework\App\State\CleanupFiles');
+ $this->cache = $objectManager->get('Magento\Framework\App\Cache');
}
/**
@@ -70,6 +97,21 @@ public function __toString()
return $this->name . ' ' . json_encode($this->params, JSON_UNESCAPED_SLASHES);
}
+ /**
+ * Do the cleanup
+ *
+ * @return void
+ */
+ protected function performCleanup()
+ {
+ $this->status->add('Cleaning generated files...');
+ $this->cleanupFiles->clearCodeGeneratedFiles();
+ $this->status->add('Complete!');
+ $this->status->add('Clearing cache...');
+ $this->cache->clean();
+ $this->status->add('Complete!');
+ }
+
/**
* Execute job
*
diff --git a/setup/src/Magento/Setup/Model/Cron/JobComponentUninstall.php b/setup/src/Magento/Setup/Model/Cron/JobComponentUninstall.php
index ce8e60c5b9124..c73e1b6785b39 100644
--- a/setup/src/Magento/Setup/Model/Cron/JobComponentUninstall.php
+++ b/setup/src/Magento/Setup/Model/Cron/JobComponentUninstall.php
@@ -89,7 +89,7 @@ public function __construct(
$this->themeUninstall = $themeUninstall;
$this->objectManager = $objectManagerProvider->get();
$this->updater = $updater;
- parent::__construct($output, $status, $name, $params);
+ parent::__construct($output, $status, $objectManagerProvider, $name, $params);
}
/**
@@ -101,6 +101,7 @@ public function __construct(
public function execute()
{
if (!isset($this->params['components']) || !is_array($this->params['components'])) {
+ $this->status->toggleUpdateError(true);
throw new \RunTimeException('Job parameter format is incorrect');
}
$components = $this->params['components'];
@@ -110,6 +111,7 @@ public function execute()
$this->cleanUp();
$errorMessage = $this->updater->createUpdaterTask($components, Updater::TASK_TYPE_UNINSTALL);
if ($errorMessage) {
+ $this->status->toggleUpdateError(true);
throw new \RuntimeException($errorMessage);
}
}
@@ -124,6 +126,7 @@ public function execute()
private function executeComponent(array $component)
{
if (!isset($component[self::COMPONENT_NAME])) {
+ $this->status->toggleUpdateError(true);
throw new \RuntimeException('Job parameter format is incorrect');
}
@@ -132,6 +135,7 @@ private function executeComponent(array $component)
if (isset($installedPackages[$componentName]['type'])) {
$type = $installedPackages[$componentName]['type'];
} else {
+ $this->status->toggleUpdateError(true);
throw new \RuntimeException('Component type not set');
}
@@ -141,6 +145,7 @@ private function executeComponent(array $component)
self::COMPONENT_LANGUAGE,
self::COMPONENT
])) {
+ $this->status->toggleUpdateError(true);
throw new \RuntimeException('Unknown component type');
}
diff --git a/setup/src/Magento/Setup/Model/Cron/JobDbRollback.php b/setup/src/Magento/Setup/Model/Cron/JobDbRollback.php
index 8b67ac629b9bc..ffb48a2085d90 100644
--- a/setup/src/Magento/Setup/Model/Cron/JobDbRollback.php
+++ b/setup/src/Magento/Setup/Model/Cron/JobDbRollback.php
@@ -23,22 +23,23 @@ class JobDbRollback extends AbstractJob
/**
* Constructor
- *
* @param BackupRollbackFactory $backupRollbackFactory
* @param OutputInterface $output
* @param Status $status
- * @param string $name
+ * @param ObjectManagerProvider $objectManagerProvider
+ * @param array $name
* @param array $params
*/
public function __construct(
BackupRollbackFactory $backupRollbackFactory,
OutputInterface $output,
Status $status,
+ ObjectManagerProvider $objectManagerProvider,
$name,
$params = []
) {
$this->backupRollbackFactory = $backupRollbackFactory;
- parent::__construct($output, $status, $name, $params);
+ parent::__construct($output, $status, $objectManagerProvider, $name, $params);
}
/**
diff --git a/setup/src/Magento/Setup/Model/Cron/JobFactory.php b/setup/src/Magento/Setup/Model/Cron/JobFactory.php
index 0128083f70fbe..5e8bb0d2101e5 100644
--- a/setup/src/Magento/Setup/Model/Cron/JobFactory.php
+++ b/setup/src/Magento/Setup/Model/Cron/JobFactory.php
@@ -15,9 +15,11 @@ class JobFactory
/**
* Name of jobs
*/
- const NAME_UPGRADE = 'setup:upgrade';
- const DB_ROLLBACK = 'setup:rollback';
- const COMPONENT_UNINSTALL = 'setup:component:uninstall';
+ const JOB_UPGRADE = 'setup:upgrade';
+ const JOB_DB_ROLLBACK = 'setup:rollback';
+ const JOB_COMPONENT_UNINSTALL = 'setup:component:uninstall';
+ const JOB_MODULE_ENABLE = 'setup:module:enable';
+ const JOB_MODULE_DISABLE = 'setup:module:disable';
/**
* @var ServiceLocatorInterface
@@ -52,7 +54,7 @@ public function create($name, array $params = [])
/** @var \Magento\Framework\ObjectManagerInterface $objectManager */
$objectManager = $objectManagerProvider->get();
switch ($name) {
- case self::NAME_UPGRADE:
+ case self::JOB_UPGRADE:
return new JobUpgrade(
$this->serviceLocator->get('Magento\Setup\Console\Command\UpgradeCommand'),
$objectManagerProvider,
@@ -62,16 +64,17 @@ public function create($name, array $params = [])
$params
);
break;
- case self::DB_ROLLBACK:
+ case self::JOB_DB_ROLLBACK:
return new JobDbRollback(
$objectManager->get('Magento\Framework\Setup\BackupRollbackFactory'),
$multipleStreamOutput,
$cronStatus,
+ $objectManagerProvider,
$name,
$params
);
break;
- case self::COMPONENT_UNINSTALL:
+ case self::JOB_COMPONENT_UNINSTALL:
$moduleUninstall = new Helper\ModuleUninstall(
$this->serviceLocator->get('Magento\Setup\Model\ModuleUninstaller'),
$this->serviceLocator->get('Magento\Setup\Model\ModuleRegistryUninstaller'),
@@ -92,8 +95,30 @@ public function create($name, array $params = [])
$name,
$params
);
+ break;
+ case self::JOB_MODULE_ENABLE:
+ return new JobModule(
+ $this->serviceLocator->get('Magento\Setup\Console\Command\ModuleEnableCommand'),
+ $objectManagerProvider,
+ $multipleStreamOutput,
+ $cronStatus,
+ $name,
+ $params
+ );
+ break;
+ case self::JOB_MODULE_DISABLE:
+ return new JobModule(
+ $this->serviceLocator->get('Magento\Setup\Console\Command\ModuleDisableCommand'),
+ $objectManagerProvider,
+ $multipleStreamOutput,
+ $cronStatus,
+ $name,
+ $params
+ );
+ break;
default:
throw new \RuntimeException(sprintf('"%s" job is not supported.', $name));
+ break;
}
}
}
diff --git a/setup/src/Magento/Setup/Model/Cron/JobModule.php b/setup/src/Magento/Setup/Model/Cron/JobModule.php
new file mode 100644
index 0000000000000..f4c3988d7327e
--- /dev/null
+++ b/setup/src/Magento/Setup/Model/Cron/JobModule.php
@@ -0,0 +1,103 @@
+command = $command;
+ $this->output = $output;
+ $this->status = $status;
+ parent::__construct($output, $status, $objectManagerProvider, $name, $params);
+
+ // map name to command string
+ $this->setCommandString($name);
+ }
+
+ /**
+ * Sets up the command to be run through bin/magento
+ *
+ * @param string $name
+ * @return void
+ */
+ private function setCommandString($name)
+ {
+ if ($name == 'setup:module:enable') {
+ $this->cmdString = 'module:enable';
+ } else {
+ $this->cmdString = 'module:disable';
+ }
+ }
+
+ /**
+ * Execute job
+ *
+ * @throws \RuntimeException
+ * @return void
+ */
+ public function execute()
+ {
+ try {
+ foreach ($this->params['components'] as $compObj) {
+ if (isset($compObj['name']) && (!empty($compObj['name']))) {
+ $moduleNames[] = $compObj['name'];
+ } else {
+ throw new \RuntimeException('component name is not set.');
+ }
+ }
+
+ // prepare the arguments to invoke Symfony run()
+ $arguments['command'] = $this->cmdString;
+ $arguments['module'] = $moduleNames;
+
+ $statusCode = $this->command->run(new ArrayInput($arguments), $this->output);
+
+ // check for return statusCode to catch any Symfony errors
+ if ($statusCode != 0) {
+ throw new \RuntimeException('Symfony run() returned StatusCode: ' . $statusCode);
+ }
+
+ //perform the generated file cleanup
+ $this->performCleanup();
+
+ } catch (\Exception $e) {
+ $this->status->toggleUpdateError(true);
+ throw new \RuntimeException(
+ sprintf('Could not complete %s successfully: %s', $this->cmdString, $e->getMessage())
+ );
+ }
+ }
+}
diff --git a/setup/src/Magento/Setup/Model/Cron/JobUpgrade.php b/setup/src/Magento/Setup/Model/Cron/JobUpgrade.php
index f297dc1aa59fc..e4b8b9bda907a 100644
--- a/setup/src/Magento/Setup/Model/Cron/JobUpgrade.php
+++ b/setup/src/Magento/Setup/Model/Cron/JobUpgrade.php
@@ -16,20 +16,6 @@
*/
class JobUpgrade extends AbstractJob
{
- /**
- * @var \Magento\Framework\App\Cache
- */
- private $cache;
-
- /**
- * @var \Magento\Framework\App\State\CleanupFiles
- */
- private $cleanupFiles;
-
- /**
- * @var Status
- */
- protected $status;
/**
* Constructor
@@ -49,13 +35,10 @@ public function __construct(
$name,
$params = []
) {
- $objectManager = $objectManagerProvider->get();
- $this->cleanupFiles = $objectManager->get('Magento\Framework\App\State\CleanupFiles');
- $this->cache = $objectManager->get('Magento\Framework\App\Cache');
$this->command = $command;
$this->output = $output;
$this->status = $status;
- parent::__construct($output, $status, $name, $params);
+ parent::__construct($output, $status, $objectManagerProvider, $name, $params);
}
/**
@@ -69,10 +52,7 @@ public function execute()
try {
$this->params['command'] = 'setup:upgrade';
$this->command->run(new ArrayInput($this->params), $this->output);
- $this->status->add('Cleaning generated files...');
- $this->cleanupFiles->clearCodeGeneratedFiles();
- $this->status->add('Clearing cache...');
- $this->cache->clean();
+ $this->performCleanup();
} catch (\Exception $e) {
$this->status->toggleUpdateError(true);
throw new \RuntimeException(sprintf('Could not complete %s successfully: %s', $this, $e->getMessage()));
diff --git a/setup/src/Magento/Setup/Model/CronScriptReadinessCheck.php b/setup/src/Magento/Setup/Model/CronScriptReadinessCheck.php
index 8277cc79ea7ac..ef427c3e4148b 100644
--- a/setup/src/Magento/Setup/Model/CronScriptReadinessCheck.php
+++ b/setup/src/Magento/Setup/Model/CronScriptReadinessCheck.php
@@ -38,6 +38,12 @@ class CronScriptReadinessCheck
*/
const UPDATER_KEY_FILE_PERMISSIONS_VERIFIED = 'file_permissions_verified';
+ /**
+ * Error message for dependant checks
+ */
+ const OTHER_CHECKS_WILL_FAIL_MSG =
+ ' Other checks will fail as a result (PHP version, PHP settings, and PHP extensions)';
+
/**
* @var Filesystem
*/
@@ -96,10 +102,9 @@ private function checkJson($type)
return ['success' => false, 'error' => 'Internal Error'];
}
} catch (\Magento\Framework\Exception\FileSystemException $e) {
- $error = 'Cron Job has not been configured yet';
+ $error = 'Cron job has not been configured yet';
if ($type == self::SETUP) {
- $error .= ' PHP Version, PHP Settings and PHP Extensions Check' .
- ' will fail because they depend on this check';
+ $error .= self::OTHER_CHECKS_WILL_FAIL_MSG;
}
return [
'success' => false,
@@ -115,10 +120,9 @@ private function checkJson($type)
}
return ['success' => false, 'error' => $jsonData[ReadinessCheck::KEY_READINESS_CHECKS]['error']];
}
- $error = 'Cron Job has not been configured yet';
+ $error = 'Cron job has not been configured yet';
if ($type == self::SETUP) {
- $error .= ' PHP Version, PHP Settings and PHP Extensions Check' .
- ' will fail because they depend on this check';
+ $error .= self::OTHER_CHECKS_WILL_FAIL_MSG;
}
return [
'success' => false,
@@ -144,13 +148,13 @@ private function checkCronTime(array $jsonData)
}
return [
'success' => true,
- 'notice' => 'It is recommended to schedule Cron to run every 1 minute'
+ 'notice' => 'We recommend you schedule cron to run every 1 minute'
];
}
return [
'success' => true,
- 'notice' => 'Unable to determine Cron time interval. ' .
- 'It is recommended to schedule Cron to run every 1 minute'
+ 'notice' => 'Unable to determine cron time interval. ' .
+ 'We recommend you schedule cron to run every 1 minute'
];
}
}
diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php
index 0e822e56f2dd5..51692aebce752 100644
--- a/setup/src/Magento/Setup/Model/Installer.php
+++ b/setup/src/Magento/Setup/Model/Installer.php
@@ -26,6 +26,8 @@
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Setup\Model\ConfigModel as SetupConfigModel;
+use Magento\Setup\Module\DataSetupFactory;
+use Magento\Setup\Module\SetupFactory;
use Magento\Store\Model\Store;
use Magento\Setup\Module\ConnectionFactory;
use Magento\Setup\Module\Setup;
@@ -163,11 +165,6 @@ class Installer
*/
private $deploymentConfig;
- /**
- * @var SampleData
- */
- private $sampleData;
-
/**
* @var ObjectManagerProvider
*/
@@ -193,6 +190,20 @@ class Installer
*/
private $dbValidator;
+ /**
+ * Factory to create \Magento\Setup\Module\Setup
+ *
+ * @var SetupFactory
+ */
+ private $setupFactory;
+
+ /**
+ * Factory to create \Magento\Setup\Module\DataSetup
+ *
+ * @var DataSetupFactory
+ */
+ private $dataSetupFactory;
+
/**
* Constructor
*
@@ -207,12 +218,13 @@ class Installer
* @param ConnectionFactory $connectionFactory
* @param MaintenanceMode $maintenanceMode
* @param Filesystem $filesystem
- * @param SampleData $sampleData
* @param ObjectManagerProvider $objectManagerProvider
* @param Context $context
* @param SetupConfigModel $setupConfigModel
* @param CleanupFiles $cleanupFiles
* @param DbValidator $dbValidator
+ * @param SetupFactory $setupFactory
+ * @param DataSetupFactory $dataSetupFactory
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
@@ -228,12 +240,13 @@ public function __construct(
ConnectionFactory $connectionFactory,
MaintenanceMode $maintenanceMode,
Filesystem $filesystem,
- SampleData $sampleData,
ObjectManagerProvider $objectManagerProvider,
Context $context,
SetupConfigModel $setupConfigModel,
CleanupFiles $cleanupFiles,
- DbValidator $dbValidator
+ DbValidator $dbValidator,
+ SetupFactory $setupFactory,
+ DataSetupFactory $dataSetupFactory
) {
$this->filePermissions = $filePermissions;
$this->deploymentConfigWriter = $deploymentConfigWriter;
@@ -245,7 +258,6 @@ public function __construct(
$this->connectionFactory = $connectionFactory;
$this->maintenanceMode = $maintenanceMode;
$this->filesystem = $filesystem;
- $this->sampleData = $sampleData;
$this->installInfo[self::INFO_MESSAGE] = [];
$this->deploymentConfig = $deploymentConfig;
$this->objectManagerProvider = $objectManagerProvider;
@@ -253,6 +265,8 @@ public function __construct(
$this->setupConfigModel = $setupConfigModel;
$this->cleanupFiles = $cleanupFiles;
$this->dbValidator = $dbValidator;
+ $this->setupFactory = $setupFactory;
+ $this->dataSetupFactory = $dataSetupFactory;
}
/**
@@ -282,7 +296,9 @@ public function install($request)
}
$script[] = ['Installing admin user...', 'installAdminUser', [$request]];
$script[] = ['Enabling caches:', 'enableCaches', []];
- if (!empty($request[InstallCommand::INPUT_KEY_USE_SAMPLE_DATA]) && $this->sampleData->isDeployed()) {
+ if (!empty($request[InstallCommand::INPUT_KEY_USE_SAMPLE_DATA])
+ && $this->filesystem->getDirectoryRead(DirectoryList::MODULES)->isExist('Magento/SampleData')
+ ) {
$script[] = ['Installing sample data:', 'installSampleData', [$request]];
}
$script[] = ['Disabling Maintenance Mode:', 'setMaintenanceMode', [0]];
@@ -690,10 +706,7 @@ private function setupFlagTable(
*/
public function installSchema()
{
- $setup = $this->objectManagerProvider->get()->create(
- 'Magento\Setup\Module\Setup',
- ['resource' => $this->context->getResources()]
- );
+ $setup = $this->setupFactory->create($this->context->getResources());
$this->setupModuleRegistry($setup);
$this->setupCoreTables($setup);
$this->log->log('Schema creation/updates:');
@@ -708,7 +721,7 @@ public function installSchema()
*/
public function installDataFixtures()
{
- $setup = $this->objectManagerProvider->get()->create('Magento\Setup\Module\DataSetup');
+ $setup = $this->dataSetupFactory->create();
$this->checkInstallationFilePermissions();
$this->log->log('Data install/update:');
$this->handleDBSchemaData($setup, 'data');
@@ -848,10 +861,7 @@ protected function createSchemaDataHandler($className, $interfaceName)
*/
private function installOrderIncrementPrefix($orderIncrementPrefix)
{
- $setup = $this->objectManagerProvider->get()->create(
- 'Magento\Setup\Module\Setup',
- ['resource' => $this->context->getResources()]
- );
+ $setup = $this->setupFactory->create($this->context->getResources());
$dbConnection = $setup->getConnection();
// get entity_type_id for order
@@ -894,10 +904,7 @@ private function installOrderIncrementPrefix($orderIncrementPrefix)
public function installAdminUser($data)
{
$this->assertDeploymentConfigExists();
- $setup = $this->objectManagerProvider->get()->create(
- 'Magento\Setup\Module\Setup',
- ['resource' => $this->context->getResources()]
- );
+ $setup = $this->setupFactory->create($this->context->getResources());
$adminAccount = $this->adminAccountFactory->create($setup, (array)$data);
$adminAccount->save();
}
@@ -915,6 +922,15 @@ public function updateModulesSequence()
$this->log->log('File system cleanup:');
$messages = $this->cleanupFiles->clearCodeGeneratedClasses();
+ // unload Magento autoloader because it may be using compiled definition
+ foreach (spl_autoload_functions() as $autoloader) {
+ if ($autoloader[0] instanceof \Magento\Framework\Code\Generator\Autoloader) {
+ spl_autoload_unregister([$autoloader[0], $autoloader[1]]);
+ break;
+ }
+ }
+ // Corrected Magento autoloader will be loaded upon next get() call on $this->objectManagerProvider
+ $this->objectManagerProvider->reset();
foreach ($messages as $message) {
$this->log->log($message);
}
@@ -1117,7 +1133,8 @@ private function installSampleData($request)
try {
$userName = isset($request[AdminAccount::KEY_USER]) ? $request[AdminAccount::KEY_USER] : '';
$this->objectManagerProvider->reset();
- $this->sampleData->install($this->objectManagerProvider->get(), $this->log, $userName);
+ $sampleData = $this->objectManagerProvider->get()->get('Magento\SampleData\Model\SampleData');
+ $sampleData->install($this->objectManagerProvider->get(), $this->log, $userName);
} catch (\Exception $e) {
throw new \Magento\Setup\SampleDataException(
"Error during sample data installation: {$e->getMessage()}",
diff --git a/setup/src/Magento/Setup/Model/InstallerFactory.php b/setup/src/Magento/Setup/Model/InstallerFactory.php
index 9af552e32d1fc..9d99342d21a19 100644
--- a/setup/src/Magento/Setup/Model/InstallerFactory.php
+++ b/setup/src/Magento/Setup/Model/InstallerFactory.php
@@ -61,7 +61,6 @@ public function create(LoggerInterface $log)
$this->serviceLocator->get('Magento\Setup\Module\ConnectionFactory'),
$this->serviceLocator->get('Magento\Framework\App\MaintenanceMode'),
$this->serviceLocator->get('Magento\Framework\Filesystem'),
- $this->serviceLocator->get('Magento\Setup\Model\SampleData'),
$this->serviceLocator->get('Magento\Setup\Model\ObjectManagerProvider'),
new \Magento\Framework\Model\Resource\Db\Context(
$this->getResource(),
@@ -70,7 +69,9 @@ public function create(LoggerInterface $log)
),
$this->serviceLocator->get('Magento\Setup\Model\ConfigModel'),
$this->serviceLocator->get('Magento\Framework\App\State\CleanupFiles'),
- $this->serviceLocator->get('Magento\Setup\Validator\DbValidator')
+ $this->serviceLocator->get('Magento\Setup\Validator\DbValidator'),
+ $this->serviceLocator->get('Magento\Setup\Module\SetupFactory'),
+ $this->serviceLocator->get('Magento\Setup\Module\DataSetupFactory')
);
}
diff --git a/setup/src/Magento/Setup/Model/ModuleStatusFactory.php b/setup/src/Magento/Setup/Model/ModuleStatusFactory.php
new file mode 100644
index 0000000000000..8982b65dba276
--- /dev/null
+++ b/setup/src/Magento/Setup/Model/ModuleStatusFactory.php
@@ -0,0 +1,40 @@
+objectManagerProvider = $objectManagerProvider;
+ }
+
+ /**
+ * Creates Status object
+ *
+ * @return Status
+ */
+ public function create()
+ {
+ return $this->objectManagerProvider->get()->get('Magento\Framework\Module\Status');
+ }
+}
diff --git a/setup/src/Magento/Setup/Model/SampleData.php b/setup/src/Magento/Setup/Model/SampleData.php
deleted file mode 100644
index c3e79ba7133b4..0000000000000
--- a/setup/src/Magento/Setup/Model/SampleData.php
+++ /dev/null
@@ -1,124 +0,0 @@
-directoryList = $directoryList;
- }
-
- /**
- * Check if Sample Data was deployed
- *
- * @return bool
- */
- public function isDeployed()
- {
- return file_exists($this->directoryList->getPath(DirectoryList::MODULES) . self::PATH);
- }
-
- /**
- * Get state object or null if state object cannot be initialized
- *
- * @return null|\Magento\SampleData\Helper\State
- */
- protected function getState()
- {
- if ($this->isDeployed() && class_exists('Magento\SampleData\Helper\State')) {
- return new \Magento\SampleData\Helper\State();
- }
- return null;
- }
-
- /**
- * Check whether installation of sample data was successful
- *
- * @return bool
- */
- public function isInstalledSuccessfully()
- {
- $state = $this->getState();
- if (!$state) {
- return false;
- }
- return \Magento\SampleData\Helper\State::STATE_FINISHED == $state->getState();
- }
-
- /**
- * Check whether there was unsuccessful attempt to install Sample data
- *
- * @return bool
- */
- public function isInstallationError()
- {
- $state = $this->getState();
- if (!$state) {
- return false;
- }
- return $state->isError();
- }
-
- /**
- * Installation routine for creating sample data
- *
- * @param ObjectManagerInterface $objectManager
- * @param LoggerInterface $logger
- * @param string $userName
- * @param array $modules
- * @throws \Exception
- * @return void
- */
- public function install(
- ObjectManagerInterface $objectManager,
- LoggerInterface $logger,
- $userName,
- array $modules = []
- ) {
- /** @var \Magento\SampleData\Model\Logger $sampleDataLogger */
- $sampleDataLogger = $objectManager->get('Magento\SampleData\Model\Logger');
- $sampleDataLogger->setSubject($logger);
-
- $areaCode = 'adminhtml';
- /** @var \Magento\Framework\App\State $appState */
- $appState = $objectManager->get('Magento\Framework\App\State');
- $appState->setAreaCode($areaCode);
- /** @var \Magento\Framework\App\ObjectManager\ConfigLoader $configLoader */
- $configLoader = $objectManager->get('Magento\Framework\App\ObjectManager\ConfigLoader');
- $objectManager->configure($configLoader->load($areaCode));
-
- /** @var \Magento\SampleData\Model\Installer $installer */
- $installer = $objectManager->get('Magento\SampleData\Model\Installer');
- $installer->run($userName, $modules);
- }
-}
diff --git a/setup/src/Magento/Setup/Model/Updater.php b/setup/src/Magento/Setup/Model/Updater.php
index cdf395321e73f..d7ccfcf9a88d1 100644
--- a/setup/src/Magento/Setup/Model/Updater.php
+++ b/setup/src/Magento/Setup/Model/Updater.php
@@ -48,9 +48,15 @@ public function createUpdaterTask(array $packages, $type, array $additionalOptio
{
try {
// write to .update_queue.json file
- $this->queue->addJobs(
- [['name' => $type, 'params' => array_merge(['components' => $packages], $additionalOptions)]]
- );
+ $params = [];
+ if (!empty($packages)) {
+ $params['components'] = $packages;
+ }
+ foreach ($additionalOptions as $key => $value) {
+ $params[$key] = $value;
+ }
+
+ $this->queue->addJobs([['name' => $type, 'params' => $params]]);
return '';
} catch (\Exception $e) {
return $e->getMessage();
diff --git a/setup/src/Magento/Setup/Module.php b/setup/src/Magento/Setup/Module.php
index b36805e5af2f2..8ad2589b9963f 100644
--- a/setup/src/Magento/Setup/Module.php
+++ b/setup/src/Magento/Setup/Module.php
@@ -67,6 +67,8 @@ public function getConfig()
include __DIR__ . '/../../../config/states.home.config.php',
include __DIR__ . '/../../../config/states.upgrade.config.php',
include __DIR__ . '/../../../config/states.uninstall.config.php',
+ include __DIR__ . '/../../../config/states.enable.config.php',
+ include __DIR__ . '/../../../config/states.disable.config.php',
include __DIR__ . '/../../../config/languages.config.php'
);
return $result;
diff --git a/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/AbstractFile.php b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/AbstractFile.php
index 599b806f09930..e5909fb68296f 100644
--- a/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/AbstractFile.php
+++ b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/AbstractFile.php
@@ -143,7 +143,7 @@ abstract protected function _getFileExtension();
* @param bool $recursive Allows the creation of nested directories specified in the $destinationPath
* @return void
*/
- protected function _createDirectoryIfNotExist($destinationPath, $mode = 0755, $recursive = true)
+ protected function _createDirectoryIfNotExist($destinationPath, $mode = 0750, $recursive = true)
{
if (!is_dir($destinationPath)) {
mkdir($destinationPath, $mode, $recursive);
diff --git a/setup/src/Magento/Setup/Module/SetupFactory.php b/setup/src/Magento/Setup/Module/SetupFactory.php
index 532d4bbcc7b1a..386fedd04a9f5 100644
--- a/setup/src/Magento/Setup/Module/SetupFactory.php
+++ b/setup/src/Magento/Setup/Module/SetupFactory.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Setup\Module;
+use Magento\Framework\App\Resource;
use Magento\Setup\Model\ObjectManagerProvider;
/**
@@ -28,13 +29,17 @@ public function __construct(ObjectManagerProvider $objectManagerProvider)
}
/**
- * Creates Setup
+ * Creates setup
*
+ * @param Resource $appResource
* @return Setup
*/
- public function create()
+ public function create(Resource $appResource = null)
{
$objectManager = $this->objectManagerProvider->get();
- return new Setup($objectManager->get('Magento\Framework\App\Resource'));
+ if ($appResource === null) {
+ $appResource = $objectManager->get('Magento\Framework\App\Resource');
+ }
+ return new Setup($appResource);
}
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/BackupCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/BackupCommandTest.php
index e676d1a0144ab..78b4bf38511ab 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/Command/BackupCommandTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/BackupCommandTest.php
@@ -121,8 +121,8 @@ public function testExecuteNoOptions()
->will($this->returnValue(false));
$this->tester->execute([]);
$expected = 'Enabling maintenance mode' . PHP_EOL
- . 'Not enough information provided to take backup.' . PHP_EOL
- . 'Disabling maintenance mode';
- $this->assertStringMatchesFormat($expected, $this->tester->getDisplay());
+ . 'Not enough information provided to take backup.' . PHP_EOL
+ . 'Disabling maintenance mode' . PHP_EOL;
+ $this->assertSame($expected, $this->tester->getDisplay());
}
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php
index a72e47b4111c8..d903716d85dc3 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php
@@ -106,12 +106,14 @@ public function executeDataProvider()
'enable, do not clear static content' => [
true,
false,
- '%amodules have been enabled%aMagento_Module1%aGenerated static view files were not cleared%a'
+ '%amodules have been enabled%aMagento_Module1%a' .
+ 'Info: Some modules might require static view files to be cleared.%a'
],
'disable, do not clear static content' => [
false,
false,
- '%amodules have been disabled%aMagento_Module1%aGenerated static view files were not cleared%a'
+ '%amodules have been disabled%aMagento_Module1%a' .
+ 'Info: Some modules might require static view files to be cleared.%a'
],
'enable, clear static content' => [
true,
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/RollbackCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/RollbackCommandTest.php
index dafa2e6e5e2de..02f9e9956bb57 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/Command/RollbackCommandTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/RollbackCommandTest.php
@@ -150,9 +150,9 @@ public function testExecuteNoOptions()
->will($this->returnValue(true));
$this->tester->execute([]);
$expected = 'Enabling maintenance mode' . PHP_EOL
- . 'Not enough information provided to roll back.' . PHP_EOL
- . 'Disabling maintenance mode';
- $this->assertStringMatchesFormat($expected, $this->tester->getDisplay());
+ . 'Not enough information provided to roll back.' . PHP_EOL
+ . 'Disabling maintenance mode' . PHP_EOL;
+ $this->assertSame($expected, $this->tester->getDisplay());
}
public function testInteraction()
diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/CustomizeYourStoreTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/CustomizeYourStoreTest.php
index f029c6ac15234..84a69a4f67a3e 100644
--- a/setup/src/Magento/Setup/Test/Unit/Controller/CustomizeYourStoreTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Controller/CustomizeYourStoreTest.php
@@ -16,7 +16,7 @@ class CustomizeYourStoreTest extends \PHPUnit_Framework_TestCase
private $controller;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Model\SampleData
+ * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\SampleData\Model\SampleData
*/
private $sampleData;
@@ -25,11 +25,31 @@ class CustomizeYourStoreTest extends \PHPUnit_Framework_TestCase
*/
private $lists;
+ /**
+ * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\ObjectManager
+ */
+ private $objectManager;
+
+ /**
+ * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Module\ModuleList
+ */
+ private $moduleList;
+
public function setup()
{
- $this->sampleData = $this->getMock('\Magento\Setup\Model\SampleData', [], [], '', false);
+ $objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+ $this->objectManager = $this->getMock('Magento\Framework\App\ObjectManager', [], [], '', false);
+ $objectManagerProvider->expects($this->any())->method('get')->willReturn($this->objectManager);
+ $this->sampleData = $this->getMock(
+ 'Magento\SampleData\Model\SampleData',
+ ['isInstalledSuccessfully', 'isInstallationError'],
+ [],
+ '',
+ false
+ );
$this->lists = $this->getMock('\Magento\Framework\Setup\Lists', [], [], '', false);
- $this->controller = new CustomizeYourStore($this->lists, $this->sampleData);
+ $this->moduleList = $this->getMock('Magento\Framework\Module\ModuleList', [], [], '', false);
+ $this->controller = new CustomizeYourStore($this->moduleList, $this->lists, $objectManagerProvider);
}
/**
@@ -39,11 +59,17 @@ public function setup()
*/
public function testIndexAction($expected)
{
- $this->sampleData->expects($this->once())->method('isDeployed')->willReturn($expected['isSampledataEnabled']);
- $this->sampleData->expects($this->once())->method('isInstalledSuccessfully')
- ->willReturn($expected['isSampleDataInstalled']);
- $this->sampleData->expects($this->once())->method('isInstallationError')
- ->willReturn($expected['isSampleDataErrorInstallation']);
+ if ($expected['isSampledataEnabled']) {
+ $this->moduleList->expects($this->once())->method('has')->willReturn(true);
+ $this->objectManager->expects($this->once())->method('get')->willReturn($this->sampleData);
+ $this->sampleData->expects($this->once())->method('isInstalledSuccessfully')
+ ->willReturn($expected['isSampleDataInstalled']);
+ $this->sampleData->expects($this->once())->method('isInstallationError')
+ ->willReturn($expected['isSampleDataErrorInstallation']);
+ } else {
+ $this->moduleList->expects($this->once())->method('has')->willReturn(false);
+ $this->objectManager->expects($this->never())->method('get');
+ }
$this->lists->expects($this->once())->method('getTimezoneList')->willReturn($expected['timezone']);
$this->lists->expects($this->once())->method('getCurrencyList')->willReturn($expected['currency']);
$this->lists->expects($this->once())->method('getLocaleList')->willReturn($expected['language']);
@@ -69,9 +95,9 @@ public function indexActionDataProvider()
$currency = ['currency' => ['USD'=>'US Dollar', 'EUR' => 'Euro']];
$language = ['language' => ['en_US'=>'English (USA)', 'en_UK' => 'English (UK)']];
$sampleData = [
- 'isSampledataEnabled' => null,
- 'isSampleDataInstalled' => null,
- 'isSampleDataErrorInstallation' => null
+ 'isSampledataEnabled' => false,
+ 'isSampleDataInstalled' => false,
+ 'isSampleDataErrorInstallation' => false
];
$sampleDataTrue = array_merge($sampleData, ['isSampledataEnabled' => true]);
$sampleDataFalse = array_merge($sampleData, ['isSampledataEnabled' => false]);
diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/EnvironmentTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/EnvironmentTest.php
index 8c4f5cf33adf3..fc3fee7684e9e 100644
--- a/setup/src/Magento/Setup/Test/Unit/Controller/EnvironmentTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Controller/EnvironmentTest.php
@@ -43,6 +43,11 @@ class EnvironmentTest extends \PHPUnit_Framework_TestCase
*/
protected $uninstallDependencyCheck;
+ /**
+ * @var \Magento\Setup\Model\ModuleStatusFactory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ protected $moduleStatusFactory;
+
/**
* @var Environment
*/
@@ -75,13 +80,21 @@ public function setUp()
'',
false
);
+ $this->moduleStatusFactory = $this->getMock(
+ 'Magento\Setup\Model\ModuleStatusFactory',
+ [],
+ [],
+ '',
+ false
+ );
$this->environment = new Environment(
$this->permissions,
$this->filesystem,
$this->cronScriptReadinessCheck,
$this->dependencyReadinessCheck,
$this->uninstallDependencyCheck,
- $this->phpReadinessCheck
+ $this->phpReadinessCheck,
+ $this->moduleStatusFactory
);
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/StartUpdaterTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/StartUpdaterTest.php
index f0a9d835070a0..c4a6040f065c8 100644
--- a/setup/src/Magento/Setup/Test/Unit/Controller/StartUpdaterTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Controller/StartUpdaterTest.php
@@ -16,6 +16,11 @@ class StartUpdaterTest extends \PHPUnit_Framework_TestCase
*/
private $updater;
+ /**
+ * @var \Magento\Framework\Module\FullModuleList|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $fullModuleList;
+
/**
* @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -49,12 +54,23 @@ class StartUpdaterTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
$this->updater = $this->getMock('Magento\Setup\Model\Updater', [], [], '', false);
+ $this->fullModuleList = $this->getMock('Magento\Framework\Module\FullModuleList', [], [], '', false);
$this->filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
$this->navigation = $this->getMock('Magento\Setup\Model\Navigation', [], [], '', false);
- $this->controller = new StartUpdater($this->filesystem, $this->navigation, $this->updater);
+ $this->controller = new StartUpdater(
+ $this->filesystem,
+ $this->navigation,
+ $this->updater,
+ $this->fullModuleList
+ );
$this->navigation->expects($this->any())
->method('getMenuItems')
- ->willReturn([['title' => 'A', 'type' => 'update'], ['title' => 'B', 'type' => 'upgrade']]);
+ ->willReturn([
+ ['title' => 'A', 'type' => 'update'],
+ ['title' => 'B', 'type' => 'upgrade'],
+ ['title' => 'C', 'type' => 'enable'],
+ ['title' => 'D', 'type' => 'disable'],
+ ]);
$this->request = $this->getMock('\Zend\Http\PhpEnvironment\Request', [], [], '', false);
$this->response = $this->getMock('\Zend\Http\PhpEnvironment\Response', [], [], '', false);
$routeMatch = $this->getMock('\Zend\Mvc\Router\RouteMatch', [], [], '', false);
@@ -160,4 +176,36 @@ public function testUpdateActionSuccessUpgrade()
$this->controller->dispatch($this->request, $this->response);
$this->controller->updateAction();
}
+
+ public function testUpdateActionSuccessEnable()
+ {
+ $content = '{"packages":[{"name":"vendor\/package"}],"type":"enable",'
+ . '"headerTitle": "Enable Package 1" }';
+ $this->request->expects($this->any())->method('getContent')->willReturn($content);
+ $this->fullModuleList->expects($this->once())->method('has')->willReturn(true);
+ $write = $this->getMockForAbstractClass('Magento\Framework\Filesystem\Directory\WriteInterface', [], '', false);
+ $this->filesystem->expects($this->once())->method('getDirectoryWrite')->willReturn($write);
+ $write->expects($this->once())
+ ->method('writeFile')
+ ->with('.type.json', '{"type":"enable","headerTitle":"Enable Package 1","titles":["C"]}');
+ $this->controller->setEvent($this->mvcEvent);
+ $this->controller->dispatch($this->request, $this->response);
+ $this->controller->updateAction();
+ }
+
+ public function testUpdateActionSuccessDisable()
+ {
+ $content = '{"packages":[{"name":"vendor\/package"}],"type":"disable",'
+ . '"headerTitle": "Disable Package 1" }';
+ $this->request->expects($this->any())->method('getContent')->willReturn($content);
+ $this->fullModuleList->expects($this->once())->method('has')->willReturn(true);
+ $write = $this->getMockForAbstractClass('Magento\Framework\Filesystem\Directory\WriteInterface', [], '', false);
+ $this->filesystem->expects($this->once())->method('getDirectoryWrite')->willReturn($write);
+ $write->expects($this->once())
+ ->method('writeFile')
+ ->with('.type.json', '{"type":"disable","headerTitle":"Disable Package 1","titles":["D"]}');
+ $this->controller->setEvent($this->mvcEvent);
+ $this->controller->dispatch($this->request, $this->response);
+ $this->controller->updateAction();
+ }
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php
index b9bccbc55b16d..e55d4430ee7cf 100644
--- a/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php
@@ -12,10 +12,16 @@ class SuccessTest extends \PHPUnit_Framework_TestCase
{
public function testIndexAction()
{
- $sampleData = $this->getMock('Magento\Setup\Model\SampleData', ['isDeployed'], [], '', false);
+ $moduleList = $this->getMock('Magento\Framework\Module\ModuleList', [], [], '', false);
+ $moduleList->expects($this->once())->method('has')->willReturn(true);
+ $objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+ $objectManager = $this->getMock('Magento\Framework\App\ObjectManager', [], [], '', false);
+ $objectManagerProvider->expects($this->once())->method('get')->willReturn($objectManager);
+ $sampleData = $this->getMock('Magento\Setup\Model\SampleData', ['isInstallationError'], [], '', false);
+ $objectManager->expects($this->once())->method('get')->willReturn($sampleData);
/** @var $controller Success */
- $controller = new Success($sampleData);
- $sampleData->expects($this->once())->method('isDeployed');
+ $controller = new Success($moduleList, $objectManagerProvider);
+ $sampleData->expects($this->once())->method('isInstallationError');
$viewModel = $controller->indexAction();
$this->assertInstanceOf('Zend\View\Model\ViewModel', $viewModel);
$this->assertTrue($viewModel->terminate());
diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php
index f0cd86010b237..0643f6cd40fec 100644
--- a/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php
@@ -80,7 +80,13 @@ public function testExecute()
$valueMap = [
[
'Magento\ImportExport\Model\Import',
- ['data' => ['entity' => 'catalog_product', 'behavior' => 'append']],
+ [
+ 'data' => [
+ 'entity' => 'catalog_product',
+ 'behavior' => 'append',
+ 'validation_strategy' => 'validation-stop-on-errors'
+ ]
+ ],
$importMock
],
['Magento\Store\Model\StoreManager', [], $storeManagerMock]
diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php
index 6761be9e0dbd5..53d3fc8b63200 100644
--- a/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php
@@ -52,7 +52,13 @@ public function testExecute()
$valueMap = [
[
'Magento\ImportExport\Model\Import',
- ['data' => ['entity' => 'customer_composite', 'behavior' => 'append']],
+ [
+ 'data' => [
+ 'entity' => 'customer_composite',
+ 'behavior' => 'append',
+ 'validation_strategy' => 'validation-stop-on-errors'
+ ]
+ ],
$importMock
],
['Magento\Store\Model\StoreManager', [], $storeManagerMock]
diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php
index 497a60768893c..163212dee20ef 100644
--- a/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php
@@ -80,7 +80,13 @@ public function testExecute()
$valueMap = [
[
'Magento\ImportExport\Model\Import',
- ['data' => ['entity' => 'catalog_product', 'behavior' => 'append']],
+ [
+ 'data' => [
+ 'entity' => 'catalog_product',
+ 'behavior' => 'append',
+ 'validation_strategy' => 'validation-stop-on-errors'
+ ]
+ ],
$importMock
],
['Magento\Store\Model\StoreManager', [], $storeManagerMock]
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php
index 12ce5af79e7dc..65df905990221 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php
@@ -38,4 +38,24 @@ public function testCreateXFrameConfig()
$configData = $this->model->createXFrameConfig();
$this->assertSame('SAMEORIGIN', $configData->getData()[ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT]);
}
+
+ public function testCreateCacheHostsConfig()
+ {
+ $data = [ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS => 'localhost:8080, website.com, 120.0.0.1:90'];
+ $expectedData = [
+ 0 => [
+ 'host' => 'localhost',
+ 'port' => '8080',
+ ],
+ 1 => [
+ 'host' => 'website.com',
+ ],
+ 2 => [
+ 'host' => '120.0.0.1',
+ 'port' => '90',
+ ],
+ ];
+ $configData = $this->model->createCacheHostsConfig($data);
+ $this->assertEquals($expectedData, $configData->getData()[ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS]);
+ }
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobDbRollbackTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobDbRollbackTest.php
index cf51bb8696ef0..0f18eccd1ef82 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobDbRollbackTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobDbRollbackTest.php
@@ -29,6 +29,11 @@ class JobDbRollbackTest extends \PHPUnit_Framework_TestCase
*/
private $status;
+ /**
+ * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Model\ObjectManagerProvider
+ */
+ private $objectManagerProvider;
+
public function setup()
{
$this->backupRollbackFactory = $this->getMock(
@@ -41,11 +46,16 @@ public function setup()
$this->backupRollback = $this->getMock('\Magento\Framework\Setup\BackupRollback', [], [], '', false);
$this->status = $this->getMock('Magento\Setup\Model\Cron\Status', [], [], '', false);
$output = $this->getMockForAbstractClass('Symfony\Component\Console\Output\OutputInterface', [], '', false);
+ $this->objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+
+ $objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface', [], '', false);
+ $this->objectManagerProvider->expects($this->once())->method('get')->willReturn($objectManager);
$this->jobDbRollback = new JobDbRollback(
$this->backupRollbackFactory,
$output,
$this->status,
+ $this->objectManagerProvider,
'setup:rollback',
['backup_file_name' => 'someFileName']
);
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobFactoryTest.php
index 01ff7898b44c7..30ba2d9fdb76e 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobFactoryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobFactoryTest.php
@@ -37,6 +37,8 @@ public function setUp()
$upgradeCommand = $this->getMock('Magento\Setup\Console\Command\UpgradeCommand', [], [], '', false);
$moduleUninstaller = $this->getMock('Magento\Setup\Model\ModuleUninstaller', [], [], '', false);
$moduleRegistryUninstaller = $this->getMock('Magento\Setup\Model\ModuleRegistryUninstaller', [], [], '', false);
+ $moduleEnabler = $this->getMock('Magento\Setup\Console\Command\ModuleEnableCommand', [], [], '', false);
+ $moduleDisabler = $this->getMock('Magento\Setup\Console\Command\ModuleDisableCommand', [], [], '', false);
$updater = $this->getMock('Magento\Setup\Model\Updater', [], [], '', false);
@@ -47,6 +49,8 @@ public function setUp()
['Magento\Setup\Model\ObjectManagerProvider', $objectManagerProvider],
['Magento\Setup\Model\ModuleUninstaller', $moduleUninstaller],
['Magento\Setup\Model\ModuleRegistryUninstaller', $moduleRegistryUninstaller],
+ ['Magento\Setup\Console\Command\ModuleDisableCommand', $moduleDisabler],
+ ['Magento\Setup\Console\Command\ModuleEnableCommand', $moduleEnabler]
];
$serviceManager->expects($this->atLeastOnce())
@@ -63,10 +67,24 @@ public function testUpgrade()
public function testRollback()
{
- $this->objectManager->expects($this->once())
+ $valueMap = [
+ [
+ 'Magento\Framework\App\State\CleanupFiles',
+ $this->getMock('Magento\Framework\App\State\CleanupFiles', [], [], '', false)
+ ],
+ [
+ 'Magento\Framework\App\Cache',
+ $this->getMock('Magento\Framework\App\Cache', [], [], '', false)
+ ],
+ [
+ 'Magento\Framework\Setup\BackupRollbackFactory',
+ $this->getMock('Magento\Framework\Setup\BackupRollbackFactory', [], [], '', false)
+ ],
+ ];
+ $this->objectManager->expects($this->any())
->method('get')
- ->with('Magento\Framework\Setup\BackupRollbackFactory')
- ->willReturn($this->getMock('Magento\Framework\Setup\BackupRollbackFactory', [], [], '', false));
+ ->will($this->returnValueMap($valueMap));
+
$this->assertInstanceOf(
'Magento\Setup\Model\Cron\AbstractJob',
$this->jobFactory->create('setup:rollback', [])
@@ -110,8 +128,45 @@ public function testCreateUnknownJob()
{
$this->jobFactory->create('unknown', []);
}
+
+ public function testModuleDisable()
+ {
+ $valueMap = [
+ [
+ 'Magento\Framework\Module\PackageInfoFactory',
+ $this->getMock('Magento\Framework\Module\PackageInfoFactory', [], [], '', false)
+ ],
+ ];
+ $this->objectManager->expects($this->any())
+ ->method('get')
+ ->will($this->returnValueMap($valueMap));
+
+ $this->assertInstanceOf(
+ 'Magento\Setup\Model\Cron\AbstractJob',
+ $this->jobFactory->create('setup:module:disable', [])
+ );
+ }
+
+ public function testModuleEnable()
+ {
+ $valueMap = [
+ [
+ 'Magento\Framework\Module\PackageInfoFactory',
+ $this->getMock('Magento\Framework\Module\PackageInfoFactory', [], [], '', false)
+ ],
+ ];
+ $this->objectManager->expects($this->any())
+ ->method('get')
+ ->will($this->returnValueMap($valueMap));
+
+ $this->assertInstanceOf(
+ 'Magento\Setup\Model\Cron\AbstractJob',
+ $this->jobFactory->create('setup:module:enable', [])
+ );
+ }
}
+
// functions to override native php functions
namespace Magento\Setup\Model\Cron;
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobModuleTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobModuleTest.php
new file mode 100644
index 0000000000000..2c028f72d61d8
--- /dev/null
+++ b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobModuleTest.php
@@ -0,0 +1,75 @@
+getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+ $objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface', [], '', false);
+ $cleanupFiles = $this->getMock('Magento\Framework\App\State\CleanupFiles', [], [], '', false);
+ $cleanupFiles->expects($this->once())->method('clearCodeGeneratedFiles');
+ $cache = $this->getMock('Magento\Framework\App\Cache', [], [], '', false);
+ $cache->expects($this->once())->method('clean');
+ $valueMap = [
+ ['Magento\Framework\Module\PackageInfoFactory'],
+ ['Magento\Framework\App\State\CleanupFiles', $cleanupFiles],
+ ['Magento\Framework\App\Cache', $cache],
+ ];
+ $objectManager->expects($this->atLeastOnce())->method('get')->will($this->returnValueMap($valueMap));
+ $objectManagerProvider->expects($this->once())->method('get')->willReturn($objectManager);
+ $command = $this->getMock('Magento\Setup\Console\Command\ModuleDisableCommand', [], [], '', false);
+ $command->expects($this->once())->method('run');
+ $status = $this->getMock('Magento\Setup\Model\Cron\Status', [], [], '', false);
+ $status->expects($this->atLeastOnce())->method('add');
+ $output = $this->getMockForAbstractClass('Symfony\Component\Console\Output\OutputInterface', [], '', false);
+ $params['components'][] = ['name' => 'vendor/module'];
+ $jobModuleDisable = new JobModule(
+ $command,
+ $objectManagerProvider,
+ $output,
+ $status,
+ 'setup:module:disable',
+ $params
+ );
+ $jobModuleDisable->execute();
+ }
+
+ public function testExecuteModuleEnable()
+ {
+ $objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+ $objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface', [], '', false);
+ $cleanupFiles = $this->getMock('Magento\Framework\App\State\CleanupFiles', [], [], '', false);
+ $cleanupFiles->expects($this->once())->method('clearCodeGeneratedFiles');
+ $cache = $this->getMock('Magento\Framework\App\Cache', [], [], '', false);
+ $cache->expects($this->once())->method('clean');
+ $valueMap = [
+ ['Magento\Framework\Module\PackageInfoFactory'],
+ ['Magento\Framework\App\State\CleanupFiles', $cleanupFiles],
+ ['Magento\Framework\App\Cache', $cache],
+ ];
+ $objectManager->expects($this->atLeastOnce())->method('get')->will($this->returnValueMap($valueMap));
+ $objectManagerProvider->expects($this->once())->method('get')->willReturn($objectManager);
+ $command = $this->getMock('Magento\Setup\Console\Command\ModuleEnableCommand', [], [], '', false);
+ $command->expects($this->once())->method('run');
+ $status = $this->getMock('Magento\Setup\Model\Cron\Status', [], [], '', false);
+ $status->expects($this->atLeastOnce())->method('add');
+ $output = $this->getMockForAbstractClass('Symfony\Component\Console\Output\OutputInterface', [], '', false);
+ $params['components'][] = ['name' => 'vendor/module'];
+ $jobModuleEnable = new JobModule(
+ $command,
+ $objectManagerProvider,
+ $output,
+ $status,
+ 'setup:module:enable',
+ $params
+ );
+ $jobModuleEnable->execute();
+ }
+}
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/CronScriptReadinessCheckTest.php b/setup/src/Magento/Setup/Test/Unit/Model/CronScriptReadinessCheckTest.php
index e36fe98d1c39e..de55f60784569 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/CronScriptReadinessCheckTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/CronScriptReadinessCheckTest.php
@@ -37,9 +37,7 @@ public function testCheckSetupNoStatusFile()
->willThrowException(new FileSystemException(new Phrase('')));
$expected = [
'success' => false,
- 'error' => 'Cron Job has not been configured yet' .
- ' PHP Version, PHP Settings and PHP Extensions Check' .
- ' will fail because they depend on this check'
+ 'error' => 'Cron job has not been configured yet' . CronScriptReadinessCheck::OTHER_CHECKS_WILL_FAIL_MSG
];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkSetup());
}
@@ -49,9 +47,7 @@ public function testCheckSetupNoCronConfigured()
$this->read->expects($this->once())->method('readFile')->willReturn('');
$expected = [
'success' => false,
- 'error' => 'Cron Job has not been configured yet' .
- ' PHP Version, PHP Settings and PHP Extensions Check' .
- ' will fail because they depend on this check'
+ 'error' => 'Cron job has not been configured yet' . CronScriptReadinessCheck::OTHER_CHECKS_WILL_FAIL_MSG
];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkSetup());
}
@@ -79,7 +75,7 @@ public function testCheckSetupBadTime()
$this->read->expects($this->once())->method('readFile')->willReturn(json_encode($json));
$expected = [
'success' => true,
- 'notice' => 'It is recommended to schedule Cron to run every 1 minute'
+ 'notice' => 'We recommend you schedule cron to run every 1 minute'
];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkSetup());
}
@@ -93,8 +89,8 @@ public function testCheckSetupUnknownTime()
$this->read->expects($this->once())->method('readFile')->willReturn(json_encode($json));
$expected = [
'success' => true,
- 'notice' => 'Unable to determine Cron time interval. ' .
- 'It is recommended to schedule Cron to run every 1 minute'
+ 'notice' => 'Unable to determine cron time interval. ' .
+ 'We recommend you schedule cron to run every 1 minute'
];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkSetup());
}
@@ -116,14 +112,14 @@ public function testCheckUpdaterNoStatusFile()
$this->read->expects($this->once())
->method('readFile')
->willThrowException(new FileSystemException(new Phrase('')));
- $expected = ['success' => false, 'error' => 'Cron Job has not been configured yet'];
+ $expected = ['success' => false, 'error' => 'Cron job has not been configured yet'];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkUpdater());
}
public function testCheckUpdaterNoCronConfigured()
{
$this->read->expects($this->once())->method('readFile')->willReturn('');
- $expected = ['success' => false, 'error' => 'Cron Job has not been configured yet'];
+ $expected = ['success' => false, 'error' => 'Cron job has not been configured yet'];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkUpdater());
}
@@ -152,7 +148,7 @@ public function testCheckUpdaterBadTime()
$this->read->expects($this->once())->method('readFile')->willReturn(json_encode($json));
$expected = [
'success' => true,
- 'notice' => 'It is recommended to schedule Cron to run every 1 minute'
+ 'notice' => 'We recommend you schedule cron to run every 1 minute'
];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkUpdater());
}
@@ -168,8 +164,8 @@ public function testCheckUpdaterUnknownTime()
$this->read->expects($this->once())->method('readFile')->willReturn(json_encode($json));
$expected = [
'success' => true,
- 'notice' => 'Unable to determine Cron time interval. ' .
- 'It is recommended to schedule Cron to run every 1 minute'
+ 'notice' => 'Unable to determine cron time interval. ' .
+ 'We recommend you schedule cron to run every 1 minute'
];
$this->assertEquals($expected, $this->cronScriptReadinessCheck->checkUpdater());
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php
index 28f5eea3921cc..30d4ba681439f 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php
@@ -53,10 +53,6 @@ public function testCreate()
'Magento\Framework\Filesystem',
$this->getMock('Magento\Framework\Filesystem', [], [], '', false),
],
- [
- 'Magento\Setup\Model\SampleData',
- $this->getMock('Magento\Setup\Model\SampleData', [], [], '', false),
- ],
[
'Magento\Setup\Model\ObjectManagerProvider',
$this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false),
@@ -81,6 +77,14 @@ public function testCreate()
'Magento\Setup\Validator\DbValidator',
$this->getMock('Magento\Setup\Validator\DbValidator', [], [], '', false),
],
+ [
+ 'Magento\Setup\Module\SetupFactory',
+ $this->getMock('Magento\Setup\Module\SetupFactory', [], [], '', false),
+ ],
+ [
+ 'Magento\Setup\Module\DataSetupFactory',
+ $this->getMock('Magento\Setup\Module\DataSetupFactory', [], [], '', false),
+ ],
];
$serviceLocatorMock = $this->getMockForAbstractClass('Zend\ServiceManager\ServiceLocatorInterface', ['get']);
$serviceLocatorMock
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php
index 295c572b9b550..ac7907be62fbf 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php
@@ -91,11 +91,6 @@ class InstallerTest extends \PHPUnit_Framework_TestCase
*/
private $filesystem;
- /**
- * @var \Magento\Setup\Model\SampleData|\PHPUnit_Framework_MockObject_MockObject
- */
- private $sampleData;
-
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
@@ -116,6 +111,16 @@ class InstallerTest extends \PHPUnit_Framework_TestCase
*/
private $dbValidator;
+ /**
+ * @var \Magento\Setup\Module\SetupFactory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $setupFactory;
+
+ /**
+ * @var \Magento\Setup\Module\DataSetupFactory|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $dataSetupFactory;
+
/**
* Sample DB configuration segment
*
@@ -155,12 +160,13 @@ protected function setUp()
$this->connection = $this->getMockForAbstractClass('Magento\Framework\DB\Adapter\AdapterInterface');
$this->maintenanceMode = $this->getMock('Magento\Framework\App\MaintenanceMode', [], [], '', false);
$this->filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
- $this->sampleData = $this->getMock('Magento\Setup\Model\SampleData', [], [], '', false);
$this->objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface');
$this->contextMock = $this->getMock('Magento\Framework\Model\Resource\Db\Context', [], [], '', false);
$this->configModel = $this->getMock('Magento\Setup\Model\ConfigModel', [], [], '', false);
$this->cleanupFiles = $this->getMock('Magento\Framework\App\State\CleanupFiles', [], [], '', false);
$this->dbValidator = $this->getMock('Magento\Setup\Validator\DbValidator', [], [], '', false);
+ $this->setupFactory = $this->getMock('Magento\Setup\Module\SetupFactory', [], [], '', false);
+ $this->dataSetupFactory = $this->getMock('Magento\Setup\Module\DataSetupFactory', [], [], '', false);
$this->object = $this->createObject();
}
@@ -194,12 +200,13 @@ private function createObject($connectionFactory = false, $objectManagerProvider
$connectionFactory,
$this->maintenanceMode,
$this->filesystem,
- $this->sampleData,
$objectManagerProvider,
$this->contextMock,
$this->configModel,
$this->cleanupFiles,
- $this->dbValidator
+ $this->dbValidator,
+ $this->setupFactory,
+ $this->dataSetupFactory
);
}
@@ -233,11 +240,11 @@ public function testInstall()
$appState = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
'Magento\Framework\App\State'
);
+ $this->setupFactory->expects($this->atLeastOnce())->method('create')->with($resource)->willReturn($setup);
+ $this->dataSetupFactory->expects($this->atLeastOnce())->method('create')->willReturn($dataSetup);
$this->objectManager->expects($this->any())
->method('create')
->will($this->returnValueMap([
- ['Magento\Setup\Module\Setup', ['resource' => $resource], $setup],
- ['Magento\Setup\Module\DataSetup', [], $dataSetup],
['Magento\Framework\App\Cache\Manager', [], $cacheManager],
['Magento\Framework\App\State', [], $appState],
]));
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ModuleStatusFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ModuleStatusFactoryTest.php
new file mode 100644
index 0000000000000..546734478d9f6
--- /dev/null
+++ b/setup/src/Magento/Setup/Test/Unit/Model/ModuleStatusFactoryTest.php
@@ -0,0 +1,48 @@
+objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+ $this->objectManager = $this->getMockForAbstractClass(
+ 'Magento\Framework\ObjectManagerInterface',
+ [],
+ '',
+ false
+ );
+ }
+
+ public function testCreate()
+ {
+ $this->objectManagerProvider->expects($this->once())->method('get')->willReturn($this->objectManager);
+ $this->objectManager->expects($this->once())
+ ->method('get')
+ ->with('Magento\Framework\Module\Status');
+ $this->moduleStatusFactory = new ModuleStatusFactory($this->objectManagerProvider);
+ $this->moduleStatusFactory->create();
+ }
+}
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/SampleDataTest.php b/setup/src/Magento/Setup/Test/Unit/Model/SampleDataTest.php
deleted file mode 100644
index 711fa29d62465..0000000000000
--- a/setup/src/Magento/Setup/Test/Unit/Model/SampleDataTest.php
+++ /dev/null
@@ -1,58 +0,0 @@
-loggerInterface = $this->getMock('Magento\Framework\Setup\LoggerInterface');
- $this->directoryList = $this->getMock('Magento\Framework\App\Filesystem\DirectoryList', [], [], '', false);
- $this->sampleDataInstall = new SampleData($this->directoryList);
- }
-
- public function testIsDeployed()
- {
- $this->directoryList->expects($this->once())->method('getPath')->with('code');
- $this->sampleDataInstall->isDeployed();
- }
-
- /**
- * Test SampleData installation check method.
- * Can be tested only negative case because file_exists method used in the tested class
- */
- public function testIsInstalledSuccessfully()
- {
- $this->assertFalse($this->sampleDataInstall->isInstalledSuccessfully());
- }
-
- public function testIsInstallationError()
- {
- $this->directoryList->expects($this->once())->method('getPath')->with('code')->willReturn(null);
- $this->assertFalse($this->sampleDataInstall->isInstalledSuccessfully());
- }
-}
diff --git a/setup/src/Magento/Setup/Test/Unit/Module/ConfigOptionsListTest.php b/setup/src/Magento/Setup/Test/Unit/Module/ConfigOptionsListTest.php
index e2952dd17327c..15c6de640bc60 100644
--- a/setup/src/Magento/Setup/Test/Unit/Module/ConfigOptionsListTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/ConfigOptionsListTest.php
@@ -71,7 +71,9 @@ public function testGetOptions()
'If specified, then db connection validation will be skipped',
$options[11]->getDescription()
);
- $this->assertEquals(12, count($options));
+ $this->assertInstanceOf('Magento\Framework\Setup\Option\TextConfigOption', $options[12]);
+ $this->assertSame('http Cache hosts', $options[12]->getDescription());
+ $this->assertEquals(13, count($options));
}
public function testCreateOptions()
@@ -84,8 +86,9 @@ public function testCreateOptions()
$this->generator->expects($this->once())->method('createDbConfig')->willReturn($configDataMock);
$this->generator->expects($this->once())->method('createResourceConfig')->willReturn($configDataMock);
$this->generator->expects($this->once())->method('createXFrameConfig')->willReturn($configDataMock);
+ $this->generator->expects($this->once())->method('createCacheHostsConfig')->willReturn($configDataMock);
$configData = $this->object->createConfig([], $this->deploymentConfig);
- $this->assertEquals(8, count($configData));
+ $this->assertEquals(9, count($configData));
}
public function testCreateOptionsWithOptionalNull()
@@ -98,8 +101,9 @@ public function testCreateOptionsWithOptionalNull()
$this->generator->expects($this->once())->method('createDbConfig')->willReturn($configDataMock);
$this->generator->expects($this->once())->method('createResourceConfig')->willReturn($configDataMock);
$this->generator->expects($this->once())->method('createXFrameConfig')->willReturn($configDataMock);
+ $this->generator->expects($this->once())->method('createCacheHostsConfig')->willReturn($configDataMock);
$configData = $this->object->createConfig([], $this->deploymentConfig);
- $this->assertEquals(7, count($configData));
+ $this->assertEquals(8, count($configData));
}
public function testValidate()
@@ -118,4 +122,37 @@ public function testValidate()
$result = $this->object->validate($options, $this->deploymentConfig);
$this->assertEquals([], $result);
}
+
+ /**
+ * @param string $hosts
+ * @param bool $expectedError
+ * @dataProvider validateCacheHostsDataProvider
+ */
+ public function testValidateCacheHosts($hosts, $expectedError)
+ {
+ $options = [
+ ConfigOptionsListConstants::INPUT_KEY_SKIP_DB_VALIDATION => true,
+ ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS => $hosts
+ ];
+ $result = $this->object->validate($options, $this->deploymentConfig);
+ if ($expectedError) {
+ $this->assertCount(1, $result);
+ $this->assertEquals("Invalid http cache hosts '$hosts'", $result[0]);
+ } else {
+ $this->assertCount(0, $result);
+ }
+
+ }
+
+ public function validateCacheHostsDataProvider()
+ {
+ return [
+ ['localhost', false],
+ ['122.11.2.34:800', false],
+ ['122.11.2.34:800,localhost', false],
+ ['website.com:9000', false],
+ ['website.com/m2ce:9000', true],
+ ['website.com+:9000', true],
+ ];
+ }
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Module/SetupFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/SetupFactoryTest.php
index 750f40555eefa..84223f475c199 100644
--- a/setup/src/Magento/Setup/Test/Unit/Module/SetupFactoryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/SetupFactoryTest.php
@@ -21,4 +21,15 @@ public function testCreate()
$factory = new SetupFactory($objectManagerProvider);
$this->assertInstanceOf('Magento\Setup\Module\Setup', $factory->create());
}
+
+ public function testCreateWithParam()
+ {
+ $objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface', [], '', false);
+ $objectManager->expects($this->never())->method('get');
+ $resource = $this->getMock('Magento\Framework\App\Resource', [], [], '', false);
+ $objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+ $objectManagerProvider->expects($this->once())->method('get')->willReturn($objectManager);
+ $factory = new SetupFactory($objectManagerProvider);
+ $this->assertInstanceOf('Magento\Setup\Module\Setup', $factory->create($resource));
+ }
}
diff --git a/setup/view/magento/setup/complete-backup/progress.phtml b/setup/view/magento/setup/complete-backup/progress.phtml
index 7879d75fd4dad..030290da9cf4d 100644
--- a/setup/view/magento/setup/complete-backup/progress.phtml
+++ b/setup/view/magento/setup/complete-backup/progress.phtml
@@ -42,7 +42,7 @@
-
Checking available space in disk for taking backups...
+ Checking available disk space for backups
@@ -66,7 +66,7 @@
Check disk space availability
- Check available disk space for backup and try again.
+ Insufficient disk space available. Free up some space and try the backup again.
Error received from server:
@@ -97,8 +97,8 @@
Store in maintenance mode
- Your store will be in maintenance mode until you complete the {{type}}
- and maintenance mode is automatically lifted.
+ Your store is in maintenance mode and will automatically
+ return online after the {{type}}.
diff --git a/setup/view/magento/setup/component-grid.phtml b/setup/view/magento/setup/component-grid.phtml
index 8472d5e72af62..4b8e5a6ce1385 100644
--- a/setup/view/magento/setup/component-grid.phtml
+++ b/setup/view/magento/setup/component-grid.phtml
@@ -147,12 +147,20 @@
Select
@@ -125,7 +128,10 @@
-
For additional assistance, see
+
For additional assistance, see
+ cron scripts help .
+
@@ -164,7 +170,11 @@
- For additional assistance, see
+ For additional assistance, see
+ component dependency help
+ .
+
@@ -217,9 +227,9 @@
- Download and install PHP version {{version.data.required}} from www.php.net using this PHP Documentation .
+ Download and install PHP from www.php.net using this PHP Documentation .
- If you need more help please call your hosting provider.
+ For additional assistance, contact your hosting provider.
@@ -273,6 +283,13 @@
+
+ For additional assistance, see
+ PHP settings check help
+ .
+
+
@@ -345,10 +362,10 @@
The best way to resolve this is to install the correct missing extensions. The exact fix depends on our server, your host, and other system variables.
- Our PHP Extension Help can get you started.
+ Our PHP extension help can get you started.
- If you need more help, please call your hosting provider.
+ For additional assistance, contact your hosting provider.
The best way to resolve this is to allow write permissions for the following Magento directories. The exact fix depends on your server, your host, and other system variables.
- Our File Permission Help can get you started.
+ Our File Permission Help can get you started.
If you need more help, please call your hosting provider.
diff --git a/setup/view/magento/setup/select-version.phtml b/setup/view/magento/setup/select-version.phtml
index 28bbdce6e3e0c..7a2f7db61910a 100644
--- a/setup/view/magento/setup/select-version.phtml
+++ b/setup/view/magento/setup/select-version.phtml
@@ -114,8 +114,8 @@
- The other components below will be upgraded.
- If you don't want some components updated, please de-select them.
+ We'll update the following components for you at the same time.
+ If you don't want some components updated, change the slider to No.
diff --git a/setup/view/magento/setup/start-updater.phtml b/setup/view/magento/setup/start-updater.phtml
index 7cf049af600fe..0459ff9d45ee6 100644
--- a/setup/view/magento/setup/start-updater.phtml
+++ b/setup/view/magento/setup/start-updater.phtml
@@ -24,8 +24,8 @@
Store in maintenance mode
- Your store will be in maintenance mode until you complete the {{type}}
- and maintenance mode is automatically lifted.
+ Your store is in maintenance mode and will automatically
+ return online after the {{type}}.
@@ -50,8 +50,7 @@
ng-show="maintenanceCalled == maintenanceStatus"
>
-
{{package.name}} is ready to be
- {{successPageAction}}{{package.version ? ' to ' + package.version : ''}}.
+
We're ready to {{type}} {{package.name}}{{package.version ? ' to ' + package.version : ''}}.