Skip to content

Commit

Permalink
Merge pull request #257 from magento-folks/bugs
Browse files Browse the repository at this point in the history
[Folks] Bugfix
  • Loading branch information
Akimov, Alexander(aakimov) committed Dec 23, 2015
2 parents 5d531a6 + 0822de9 commit e65e0a1
Show file tree
Hide file tree
Showing 22 changed files with 340 additions and 55 deletions.
141 changes: 141 additions & 0 deletions app/code/Magento/Catalog/Console/Command/ProductAttributesCleanUp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Catalog\Console\Command;

use Magento\Framework\DB\Adapter\AdapterInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class ProductAttributesCleanUp extends \Symfony\Component\Console\Command\Command
{
/**
* @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
*/
protected $productAttributeRepository;

/**
* @var \Magento\Framework\Api\SearchCriteriaBuilder
*/
protected $searchCriteriaBuilder;

/**
* @var \Magento\Catalog\Model\ResourceModel\Attribute
*/
protected $attributeResource;

/**
* @var \Magento\Framework\App\State
*/
protected $appState;

/**
* @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository
* @param \Magento\Catalog\Model\ResourceModel\Attribute $attributeResource
* @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
* @param \Magento\Framework\App\State $appState
*/
public function __construct(
\Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository,
\Magento\Catalog\Model\ResourceModel\Attribute $attributeResource,
\Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder,
\Magento\Framework\App\State $appState
) {
$this->productAttributeRepository = $productAttributeRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->attributeResource = $attributeResource;
$this->appState = $appState;
parent::__construct();
}

/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('catalog:product:attributes:cleanup');
$this->setDescription('Removes unused product attributes.');
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->setDecorated(true);
$this->appState->setAreaCode('catalog');
$connection = $this->attributeResource->getConnection();
$attributeTables = $this->getAttributeTables();

$progress = new \Symfony\Component\Console\Helper\ProgressBar($output, count($attributeTables));
$progress->setFormat('<comment>%message%</comment> %current%/%max% [%bar%] %percent:3s%% %elapsed%');

$this->attributeResource->beginTransaction();
try {
// Find and remove unused attributes
foreach ($attributeTables as $attributeTable) {
$progress->setMessage($attributeTable . ' ');
$affectedIds = $this->getAffectedAttributeIds($connection, $attributeTable);
if (count($affectedIds) > 0) {
$connection->delete($attributeTable, ['value_id in (?)' => $affectedIds]);
}
$progress->advance();
}
$this->attributeResource->commit();

$output->writeln("");
$output->writeln("<info>Unused product attributes successfully cleaned up:</info>");
$output->writeln("<comment> " . implode("\n ", $attributeTables) . "</comment>");
} catch (\Exception $exception) {
$this->attributeResource->rollBack();

$output->writeln("");
$output->writeln("<error>{$exception->getMessage()}</error>");
}
}

/**
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
*/
private function getAttributeTables()
{
$searchResult = $this->productAttributeRepository->getList($this->searchCriteriaBuilder->create());
$attributeTables = [];

/** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $productAttribute */
foreach ($searchResult->getItems() as $productAttribute) {
$attributeTable = $productAttribute->getBackend()->getTable();
if (!in_array($attributeTable, $attributeTables)
&& $attributeTable != $this->attributeResource->getTable('catalog_product_entity')
) {
$attributeTables[] = $attributeTable;
}
}
return $attributeTables;
}

/**
* @param AdapterInterface $connection
* @param string $attributeTableName
* @return array
* @throws \Zend_Db_Statement_Exception
*/
private function getAffectedAttributeIds(AdapterInterface $connection, $attributeTableName)
{
$select = $connection->select()->reset();
$select->from(['e' => $this->attributeResource->getTable('catalog_product_entity')], 'ei.value_id');
$select->join(['ei' => $attributeTableName], 'ei.entity_id = e.entity_id AND ei.store_id != 0', '');
$select->join(['s' => $this->attributeResource->getTable('store')], 's.store_id = ei.store_id', '');
$select->join(['sg' => $this->attributeResource->getTable('store_group')], 'sg.group_id = s.group_id', '');
$select->joinLeft(
['pw' => $this->attributeResource->getTable('catalog_product_website')],
'pw.website_id = sg.website_id AND pw.product_id = e.entity_id',
''
);
$select->where('pw.product_id is null');
return $connection->fetchCol($select);
}
}
1 change: 1 addition & 0 deletions app/code/Magento/Catalog/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@
<arguments>
<argument name="commands" xsi:type="array">
<item name="imagesResizeCommand" xsi:type="object">Magento\Catalog\Console\Command\ImagesResizeCommand</item>
<item name="productAttributesCleanUp" xsi:type="object">Magento\Catalog\Console\Command\ProductAttributesCleanUp</item>
</argument>
</arguments>
</type>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ private function processPaymentConfiguration(array &$configuration, array $eleme
'customEntry' => 'billingAddress' . $paymentCode . '.region',
],
'validation' => [
'validate-select' => true,
'required-entry' => true,
],
'filterBy' => [
'target' => '${ $.provider }:${ $.parentScope }.country_id',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@
<item name="customEntry" xsi:type="string">shippingAddress.region</item>
</item>
<item name="validation" xsi:type="array">
<item name="validate-select" xsi:type="string">true</item>
<item name="required-entry" xsi:type="boolean">true</item>
</item>
<!-- Value of region_id field is filtered by the value of county_id attribute -->
<item name="filterBy" xsi:type="array">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ define(
stepNavigator.registerStep(
'payment',
null,
'Review & Payments',
$t('Review & Payments'),
this.isVisible,
_.bind(this.navigate, this),
20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ define(
stepNavigator.registerStep(
'shipping',
'',
'Shipping',
$t('Shipping'),
this.visible, _.bind(this.navigate, this),
10
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-->
<tr class="grand totals">
<th class="mark" colspan="1" scope="row">
<strong data-bind="text: title"></strong>
<strong data-bind="i18n: title"></strong>
</th>
<td class="amount" data-th="Order Total">
<strong><span class="price" data-bind="text: getValue()"></span></strong>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
-->
<tr class="totals sub">
<th class="mark" colspan="1" scope="row" data-bind="text: title"></th>
<th class="mark" colspan="1" scope="row" data-bind="i18n: title"></th>
<td class="amount" data-th="Subtotal">
<span class="price" data-bind="text: getValue()"></span>
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
-->
<li id="payment" role="presentation" class="checkout-payment-method" data-bind="fadeVisible: isVisible">
<div class="step-title" data-bind="text: title" data-role="title"></div>
<div class="step-title" data-bind="i18n: title" data-role="title"></div>
<div id="checkout-step-payment"
class="step-content"
data-role="content"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<!-- ko if: quoteIsVirtual == 0 -->
<tr class="totals shipping excl">
<th class="mark" scope="row">
<span class="label" data-bind="text: title"></span>
<span class="label" data-bind="i18n: title"></span>
<span class="value" data-bind="text: getShippingMethodTitle()"></span>
</th>
<td class="amount">
Expand Down
31 changes: 18 additions & 13 deletions app/code/Magento/GiftMessage/Model/GiftMessageConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ public function getConfig()
$configuration['isOrderLevelGiftOptionsEnabled'] = (bool)$this->isQuoteVirtual() ? false : true;
$configuration['giftMessage']['orderLevel'] = $orderMessages === null ? true : $orderMessages->getData();
}
if ($itemLevelGiftMessageConfiguration) {
$itemMessages = $this->getItemLevelGiftMessages();
$configuration['isItemLevelGiftOptionsEnabled'] = true;
$configuration['giftMessage']['itemLevel'] = $itemMessages === null ? true : $itemMessages;
}

$itemMessages = $this->getItemLevelGiftMessages();
$configuration['isItemLevelGiftOptionsEnabled'] = $itemLevelGiftMessageConfiguration;
$configuration['giftMessage']['itemLevel'] = $itemMessages === null ? true : $itemMessages;

$configuration['priceFormat'] = $this->localeFormat->getPriceFormat(
null,
$this->checkoutSession->getQuote()->getQuoteCurrencyCode()
Expand Down Expand Up @@ -166,22 +166,27 @@ protected function getOrderLevelGiftMessages()
}

/**
* Load already specified item level gift messages.
* Load already specified item level gift messages and related configuration.
*
* @return \Magento\GiftMessage\Api\Data\MessageInterface[]|null
*/
protected function getItemLevelGiftMessages()
{
$itemMessages = [];
$cartId = $this->checkoutSession->getQuoteId();
$items = $this->checkoutSession->getQuote()->getAllVisibleItems();
foreach ($items as $item) {
$itemLevelConfig = [];
$quote = $this->checkoutSession->getQuote();
foreach ($quote->getAllVisibleItems() as $item) {
$itemId = $item->getId();
$message = $this->itemRepository->get($cartId, $itemId);
$itemLevelConfig[$itemId] = [];
$isMessageAvailable = $item->getProduct()->getGiftMessageAvailable();
// use gift message product setting if it is available
if ($isMessageAvailable !== null) {
$itemLevelConfig[$itemId]['is_available'] = (bool)$isMessageAvailable;
}
$message = $this->itemRepository->get($quote->getId(), $itemId);
if ($message) {
$itemMessages[$itemId] = $message->getData();
$itemLevelConfig[$itemId]['message'] = $message->getData();
}
}
return count($itemMessages) === 0 ? null : $itemMessages;
return count($itemLevelConfig) === 0 ? null : $itemLevelConfig;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public function testGetConfig()
$isFrontUrlSecure = true;
$baseUrl = 'https://magento.com/';
$quoteItemMock = $this->getMock('Magento\Quote\Model\Quote\Item', [], [], '', false);
$productMock = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false);
$storeMock = $this->getMock(
'Magento\Store\Model\Store',
['isFrontUrlSecure', 'getBaseUrl', 'getCode'],
Expand All @@ -118,7 +119,7 @@ public function testGetConfig()
);
$quoteMock = $this->getMock(
'Magento\Quote\Model\Quote',
['getQuoteCurrencyCode', 'getStore', 'getIsVirtual', 'getAllVisibleItems'],
['getQuoteCurrencyCode', 'getStore', 'getIsVirtual', 'getAllVisibleItems', 'getId'],
[],
'',
false
Expand All @@ -142,18 +143,17 @@ public function testGetConfig()

$this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuoteId')->willReturn($quoteId);
$this->cartRepositoryMock->expects($this->once())->method('get')->with($quoteId)->willReturn($messageMock);

$this->checkoutSessionMock->expects($this->once())->method('loadCustomerQuote')->willReturnSelf();
$this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuote')->willReturn($quoteMock);
$quoteMock->expects($this->any())->method('getId')->willReturn($quoteId);
$quoteMock->expects($this->once())->method('getIsVirtual')->willReturn(false);

$messageMock->expects($this->atLeastOnce())->method('getData')->willReturn($messageDataMock);

$quoteMock->expects($this->once())->method('getAllVisibleItems')->willReturn([$quoteItemMock]);
$quoteItemMock->expects($this->once())->method('getId')->willReturn($itemId);
$quoteItemMock->expects($this->any())->method('getProduct')->willReturn($productMock);
$productMock->expects($this->any())->method('getGiftMessageAvailable')->willReturn(false);
$this->itemRepositoryMock->expects($this->once())->method('get')->with($quoteId, $itemId)
->willReturn($messageMock);

$quoteMock->expects($this->once())->method('getQuoteCurrencyCode')->willReturn($currencyCode);
$this->localeFormatMock->expects($this->once())->method('getPriceFormat')->with(null, $currencyCode)
->willReturn($priceFormat);
Expand All @@ -172,7 +172,12 @@ public function testGetConfig()
$expectedResult = [
'giftMessage' => [
'orderLevel' => $messageDataMock,
'itemLevel' => [$itemId => $messageDataMock]
'itemLevel' => [
$itemId => [
'is_available' => false,
'message' => $messageDataMock,
],
]
],
'isOrderLevelGiftOptionsEnabled' => $orderLevel,
'isItemLevelGiftOptionsEnabled' => $itemLevel,
Expand All @@ -182,7 +187,6 @@ public function testGetConfig()
'formKey' => $formKey,
'baseUrl' => $baseUrl
];

$this->assertSame($expectedResult, $this->model->getConfig());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ define(['uiElement', 'underscore', 'mage/url'],
message =
window.giftOptionsConfig.giftMessage.hasOwnProperty('itemLevel')
&& window.giftOptionsConfig.giftMessage['itemLevel'].hasOwnProperty(this.itemId)
? window.giftOptionsConfig.giftMessage['itemLevel'][this.itemId]
? window.giftOptionsConfig.giftMessage['itemLevel'][this.itemId]['message']
: null;
}
if (_.isObject(message)) {
Expand Down Expand Up @@ -103,6 +103,32 @@ define(['uiElement', 'underscore', 'mage/url'],
}
});
return params;
},

/**
* Check if gift message can be displayed
*
* @returns {Boolean}
*/
isGiftMessageAvailable: function () {
var isGloballyAvailable,
giftMessageConfig,
itemConfig;

// itemId represent gift message level: 'orderLevel' constant or cart item ID
if (this.itemId === 'orderLevel') {
return this.getConfigValue('isOrderLevelGiftOptionsEnabled');
}

// gift message product configuration must override system configuration
isGloballyAvailable = this.getConfigValue('isItemLevelGiftOptionsEnabled');
giftMessageConfig = window.giftOptionsConfig.giftMessage;
itemConfig = giftMessageConfig.hasOwnProperty('itemLevel') &&
giftMessageConfig.itemLevel.hasOwnProperty(this.itemId) ?
giftMessageConfig.itemLevel[this.itemId] :
{};

return itemConfig.hasOwnProperty('is_available') ? itemConfig['is_available'] : isGloballyAvailable;
}
};
model.initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,7 @@ define([
return false;
},
isActive: function() {
switch (this.itemId) {
case 'orderLevel':
return this.model.getConfigValue('isOrderLevelGiftOptionsEnabled') == true;
default:
return this.model.getConfigValue('isItemLevelGiftOptionsEnabled') == true;
}
return this.model.isGiftMessageAvailable();
},
submitOptions: function() {
giftOptionsService(this.model);
Expand Down
Loading

0 comments on commit e65e0a1

Please sign in to comment.