diff --git a/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml b/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml index bf674f8d5f3b480f0892b7273a04e82e2fb804ed..cb7200cad183c26c1d5c5ec8d4baae1477d57feb 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml +++ b/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml @@ -35,8 +35,12 @@ $ccExpYear = $block->getInfoData('cc_exp_year'); </label> <div class="admin__field-control"> <select id="<?php /* @noEscape */ echo $code; ?>_cc_type" name="payment[cc_type]" - class="required-entry validate-cc-type-select admin__control-select"> - <option value=""></option> + class="admin__control-select" + data-validate="{ + 'required':true, + 'validate-cc-type-select':'#<?php /* @noEscape */ echo $code; ?>_cc_number' + }"> + <option value=""><?php echo $block->escapeHtml(__('Please Select')); ?></option> <?php foreach ($block->getCcAvailableTypes() as $typeCode => $typeName): ?> <option value="<?php echo $block->escapeHtml($typeCode); ?>" <?php if ($typeCode == $ccType): ?>selected="selected"<?php endif; ?>> @@ -46,19 +50,25 @@ $ccExpYear = $block->getInfoData('cc_exp_year'); </select> </div> </div> + <div class="admin__field _required"> <label for="<?php /* @noEscape */ echo $code; ?>_cc_number" class="admin__field-label"> <span><?php echo $block->escapeHtml(__('Credit Card Number')); ?></span> </label> - <div class="admin__field-control"> <input type="text" id="<?php /* @noEscape */ echo $code; ?>_cc_number" name="payment[cc_number]" - class="input-text required-entry validate-cc-number admin__control-text" + data-validate="{ + 'required-number':true, + 'validate-cc-number':'#<?php /* @noEscape */ echo $code; ?>_cc_type', + 'validate-cc-type':'#<?php /* @noEscape */ echo $code; ?>_cc_type' + }" + class="admin__control-text" value="<?php /* @noEscape */ echo $block->getInfoData('cc_number'); ?>"/> </div> </div> - <div class="admin__field _required"> + + <div class="admin__field _required field-date" id="<?php /* @noEscape */ echo $code; ?>_cc_type_exp_div"> <label for="<?php /* @noEscape */ echo $code; ?>_expiration" class="admin__field-label"> <span><?php echo $block->escapeHtml(__('Expiration Date')); ?></span> </label> @@ -66,7 +76,11 @@ $ccExpYear = $block->getInfoData('cc_exp_year'); <div class="admin__field-control"> <select id="<?php /* @noEscape */ echo $code; ?>_expiration" name="payment[cc_exp_month]" - class="validate-cc-exp required-entry admin__control-select admin__control-select-month"> + class="admin__control-select admin__control-select-month" + data-validate="{ + 'required':true, + 'validate-cc-exp':'#<?php /* @noEscape */ echo $code; ?>_expiration_yr' + }"> <?php foreach ($block->getCcMonths() as $k => $v): ?> <option value="<?php echo $block->escapeHtml($k); ?>" <?php if ($k == $ccExpMonth): ?>selected="selected"<?php endif; ?>> @@ -76,7 +90,9 @@ $ccExpYear = $block->getInfoData('cc_exp_year'); </select> <select id="<?php /* @noEscape */ echo $code; ?>_expiration_yr" name="payment[cc_exp_year]" - class="required-entry admin__control-select admin__control-select-year"> + class="admin__control-select admin__control-select-year" + data-container="<?php /* @noEscape */ echo $code; ?>-cc-year" + data-validate="{required:true}"> <?php foreach ($block->getCcYears() as $k => $v): ?> <option value="<?php /* @noEscape */ echo $k ? $block->escapeHtml($k) : ''; ?>" <?php if ($k == $ccExpYear): ?>selected="selected"<?php endif; ?>> @@ -86,17 +102,27 @@ $ccExpYear = $block->getInfoData('cc_exp_year'); </select> </div> </div> + <?php if ($block->hasVerification()): ?> - <div class="admin__field _required"> - <label for="<?php /* @noEscape */ echo $code; ?>_cc_cid"> + <div class="admin__field _required field-cvv"> + <label class="admin__field-label" + for="<?php /* @noEscape */ echo $code; ?>_cc_cid" + id="<?php /* @noEscape */ echo $code; ?>_cc_type_cvv_div"> <span><?php echo $block->escapeHtml(__('Card Verification Number')); ?></span> </label> <div class="admin__field-control"> <input type="text" - class="required-entry input-text validate-cc-cvn admin__control-text" + data-container="<?php /* @noEscape */ echo $code; ?>-cc-cvv" + title="<?php echo $block->escapeHtml(__('Card Verification Number')); ?>" + class="admin__control-text cvv" id="<?php /* @noEscape */ echo $code; ?>_cc_cid" name="payment[cc_cid]" - value="<?php /* @noEscape */ echo $block->getInfoData('cc_cid') ?>"/> + value="<?php /* @noEscape */ echo $block->getInfoData('cc_cid') ?>" + data-validate="{ + 'required-number':true, + 'validate-cc-cvn':'#<?php /* @noEscape */ echo $code; ?>_cc_type' + }" + autocomplete="off"/> </div> </div> <?php endif; ?> @@ -105,7 +131,7 @@ $ccExpYear = $block->getInfoData('cc_exp_year'); require([ 'prototype', 'Magento_Sales/order/create/scripts', - "Magento_Sales/order/create/form", + 'Magento_Sales/order/create/form', 'Magento_Authorizenet/js/direct-post' ], function(){ diff --git a/app/code/Magento/Catalog/Helper/Product/Compare.php b/app/code/Magento/Catalog/Helper/Product/Compare.php index 3a7ce70cbff528239712a353cb5f939f9a0878c4..69f4a613a5b9555e2c46038c2a6cc620b291ef60 100644 --- a/app/code/Magento/Catalog/Helper/Product/Compare.php +++ b/app/code/Magento/Catalog/Helper/Product/Compare.php @@ -231,6 +231,8 @@ class Compare extends \Magento\Framework\Url\Helper\Data $data = [ \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => '', 'product' => $product->getId(), + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove this item from your Compare Products list?') ]; return $this->postHelper->getPostData($this->getRemoveUrl(), $data); } @@ -254,6 +256,8 @@ class Compare extends \Magento\Framework\Url\Helper\Data { $params = [ \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => '', + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove all items from your Compare Products list?'), ]; return $this->postHelper->getPostData($this->getClearListUrl(), $params); } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php index 39a67f9722e185894640178329d008de10cb574e..42456a396178c1a1001c45f49a0150612cdd566f 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php @@ -33,6 +33,11 @@ class Value extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb */ protected $_config; + /** + * @var \Magento\Framework\Locale\FormatInterface + */ + private $localeFormat; + /** * Class constructor * @@ -91,8 +96,9 @@ class Value extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb protected function _saveValuePrices(\Magento\Framework\Model\AbstractModel $object) { $priceTable = $this->getTable('catalog_product_option_type_price'); + $formattedPrice = $this->getLocaleFormatter()->getNumber($object->getPrice()); - $price = (double)sprintf('%F', $object->getPrice()); + $price = (double)sprintf('%F', $formattedPrice); $priceType = $object->getPriceType(); if ($object->getPrice() && $priceType) { @@ -410,4 +416,19 @@ class Value extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb return $object; } + + /** + * Get FormatInterface to convert price from string to number format + * + * @return \Magento\Framework\Locale\FormatInterface + * @deprecated + */ + private function getLocaleFormatter() + { + if ($this->localeFormat === null) { + $this->localeFormat = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Locale\FormatInterface::class); + } + return $this->localeFormat; + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php index 9f4d41aefd6bb8d1fd02d8990bcdd12c33191035..51388c3725ba9dc430137514ba3c3fc103237d1f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php @@ -115,7 +115,9 @@ class CompareTest extends \PHPUnit_Framework_TestCase $removeUrl = 'catalog/product_compare/remove'; $postParams = [ Action::PARAM_NAME_URL_ENCODED => '', - 'product' => $productId + 'product' => $productId, + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove this item from your Compare Products list?'), ]; //Verification @@ -156,7 +158,9 @@ class CompareTest extends \PHPUnit_Framework_TestCase //Data $clearUrl = 'catalog/product_compare/clear'; $postParams = [ - Action::PARAM_NAME_URL_ENCODED => '' + Action::PARAM_NAME_URL_ENCODED => '', + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove all items from your Compare Products list?'), ]; //Verification diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php index dd858fa571ae1d10ce6021f7f257579bc803cf5a..b586436b5680d942daa4f9fc6f884138f0a7eeb5 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php @@ -831,20 +831,6 @@ class ProductTest extends \PHPUnit_Framework_TestCase ]; } - public function testStatusAfterLoad() - { - $this->resource->expects($this->once())->method('load')->with($this->model, 1, null); - $this->eventManagerMock->expects($this->exactly(4))->method('dispatch'); - $this->model->load(1); - $this->assertEquals( - Status::STATUS_ENABLED, - $this->model->getData(\Magento\Catalog\Model\Product::STATUS) - ); - $this->assertFalse($this->model->hasDataChanges()); - $this->model->setStatus(Status::STATUS_DISABLED); - $this->assertTrue($this->model->hasDataChanges()); - } - /** * Test retrieving price Info */ diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php index 33c8cea3262a4d589a1d5b37b66ece85e614a2c3..53360de08b434b4a0314fe341760c55fef476ef4 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php @@ -493,7 +493,6 @@ class AdvancedPricing extends AbstractModifier 'data' => [ 'config' => [ 'componentType' => Field::NAME, - 'component' => 'Magento_Catalog/js/form/element/price-input', 'formElement' => Input::NAME, 'dataType' => Price::NAME, 'label' => __('Price'), diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js index fd69874c318e21606361d503cc55ea900ad604cf..e67bde152475f62769d6eaff73548893f98ed7d0 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js @@ -4,8 +4,9 @@ */ define([ + 'underscore', 'Magento_Ui/js/form/element/textarea' -], function (Textarea) { +], function (_, Textarea) { 'use strict'; return Textarea.extend({ @@ -123,24 +124,21 @@ define([ * Update field value, if it's allowed */ updateValue: function () { - var str = this.mask, + var str = this.mask || '', nonEmptyValueFlag = false, - placeholder, - property, tmpElement; if (!this.allowImport) { return; } - for (property in this.values) { - if (this.values.hasOwnProperty(property)) { - placeholder = ''; - placeholder = placeholder.concat('{{', property, '}}'); - str = str.replace(placeholder, this.values[property]); - nonEmptyValueFlag = nonEmptyValueFlag || !!this.values[property]; - } + if (str) { + _.each(this.values, function (propertyValue, propertyName) { + str = str.replace('{{' + propertyName + '}}', propertyValue); + nonEmptyValueFlag = nonEmptyValueFlag || !!propertyValue; + }); } + // strip tags tmpElement = document.createElement('div'); tmpElement.innerHTML = str; diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/price-input.js b/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/price-input.js deleted file mode 100644 index 0939619809a460b49cc7f254702797357c3b06f5..0000000000000000000000000000000000000000 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/price-input.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -define([ - 'Magento_Ui/js/form/element/abstract' -], function (Abstract) { - 'use strict'; - - return Abstract.extend({ - defaults: { - elementTmpl: 'Magento_Catalog/form/element/price-input' - } - }); -}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/price-input.html b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/price-input.html deleted file mode 100644 index ce8ae751e6702ff11099db5a06c8dbb8d4b1cbb9..0000000000000000000000000000000000000000 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/price-input.html +++ /dev/null @@ -1,22 +0,0 @@ -<!-- -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<input class="admin__control-text" type="text" - data-bind=" - event: { - change: userChanges, - input: onInput - }, - value: value, - hasFocus: focused, - valueUpdate: valueUpdate, - attr: { - name: inputName, - placeholder: placeholder, - 'aria-describedby': noticeId, - id: uid, - disabled: disabled - }"/> diff --git a/app/code/Magento/Catalog/view/frontend/requirejs-config.js b/app/code/Magento/Catalog/view/frontend/requirejs-config.js index c0d05a322b7cd9e0a0603cdbef8505963ead80fa..6c7a8d3a969fff3090e0c24bbb431eebf83b9e6b 100644 --- a/app/code/Magento/Catalog/view/frontend/requirejs-config.js +++ b/app/code/Magento/Catalog/view/frontend/requirejs-config.js @@ -6,7 +6,6 @@ var config = { map: { '*': { - compareItems: 'Magento_Catalog/js/compare', compareList: 'Magento_Catalog/js/list', relatedProducts: 'Magento_Catalog/js/related-products', upsellProducts: 'Magento_Catalog/js/upsell-products', diff --git a/app/code/Magento/Catalog/view/frontend/web/js/compare.js b/app/code/Magento/Catalog/view/frontend/web/js/compare.js deleted file mode 100644 index 66f8767bf2b8830c4229588d7c0a7ac5a8b6a422..0000000000000000000000000000000000000000 --- a/app/code/Magento/Catalog/view/frontend/web/js/compare.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -/*jshint browser:true jquery:true*/ -/*global confirm:true*/ -define([ - "jquery", - "jquery/ui", - "mage/decorate" -], function($){ - "use strict"; - - $.widget('mage.compareItems', { - _create: function() { - this.element.decorate('list', true); - this._confirm(this.options.removeSelector, this.options.removeConfirmMessage); - this._confirm(this.options.clearAllSelector, this.options.clearAllConfirmMessage); - }, - - /** - * Set up a click event on the given selector to display a confirmation request message - * and ask for that confirmation. - * @param selector Selector for the confirmation on click event - * @param message Message to display asking for confirmation to perform action - * @private - */ - _confirm: function(selector, message) { - $(selector).on('click', function() { - return confirm(message); - }); - } - }); - - return $.mage.compareItems; -}); \ No newline at end of file diff --git a/app/code/Magento/Catalog/view/frontend/web/js/view/compare-products.js b/app/code/Magento/Catalog/view/frontend/web/js/view/compare-products.js index 5dba397d9bc43d7e149887fe5519c54469d09b0e..9662b3fc7268b7366b9a448e90ca75690506b13a 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/view/compare-products.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/view/compare-products.js @@ -2,37 +2,32 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ + define([ 'uiComponent', 'Magento_Customer/js/customer-data', - 'mage/translate' -], function (Component, customerData) { + 'jquery', + 'mage/mage', + 'mage/decorate' +], function (Component, customerData, $) { 'use strict'; var sidebarInitialized = false; + /** + * Initialize sidebar + */ function initSidebar() { if (sidebarInitialized) { return; } - sidebarInitialized = true; - require([ - 'jquery', - 'mage/mage' - ], function ($) { - /*eslint-disable max-len*/ - $('[data-role=compare-products-sidebar]').mage('compareItems', { - 'removeConfirmMessage': $.mage.__('Are you sure you want to remove this item from your Compare Products list?'), - 'removeSelector': '#compare-items a.action.delete', - 'clearAllConfirmMessage': $.mage.__('Are you sure you want to remove all items from your Compare Products list?'), - 'clearAllSelector': '#compare-clear-all' - }); - /*eslint-enable max-len*/ - }); + sidebarInitialized = true; + $('[data-role=compare-products-sidebar]').decorate('list', true); } return Component.extend({ + /** @inheritdoc */ initialize: function () { this._super(); this.compareProducts = customerData.get('compare-products'); diff --git a/app/code/Magento/CatalogSearch/Block/Advanced/Result.php b/app/code/Magento/CatalogSearch/Block/Advanced/Result.php index 7b720c8c7c87a33bb55cd51e50deac5472e56ebf..4351b134e4a1100f2decc3b5e1d8f39a0bead78f 100644 --- a/app/code/Magento/CatalogSearch/Block/Advanced/Result.php +++ b/app/code/Magento/CatalogSearch/Block/Advanced/Result.php @@ -64,6 +64,7 @@ class Result extends Template */ protected function _prepareLayout() { + $this->pageConfig->getTitle()->set($this->getPageTitle()); $breadcrumbs = $this->getLayout()->getBlock('breadcrumbs'); if ($breadcrumbs) { $breadcrumbs->addCrumb( @@ -84,6 +85,16 @@ class Result extends Template return parent::_prepareLayout(); } + /** + * Get page title + * + * @return \Magento\Framework\Phrase + */ + private function getPageTitle() + { + return __('Advanced Search Results'); + } + /** * Set order options * diff --git a/app/code/Magento/CatalogSearch/Model/Advanced.php b/app/code/Magento/CatalogSearch/Model/Advanced.php index ef332a675e8a84f2aeb85a9c1b8443713ca57afa..f469820b3bb2db88821119e6435fe20adb4d1279 100644 --- a/app/code/Magento/CatalogSearch/Model/Advanced.php +++ b/app/code/Magento/CatalogSearch/Model/Advanced.php @@ -368,9 +368,11 @@ class Advanced extends \Magento\Framework\Model\AbstractModel $value = $value['label']; } } elseif ($attribute->getFrontendInput() == 'boolean') { - $value = $value == 1 - ? __('Yes') - : __('No'); + if (is_numeric($value)) { + $value = $value == 1 ? __('Yes') : __('No'); + } else { + $value = false; + } } return $value; diff --git a/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator.php b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator.php index 2ca347aae83c29ee3b10923245fe618d84d54a6c..1dc33743d76c187b2f20dec9149c3bd10dd2ddd3 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator.php +++ b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator.php @@ -8,7 +8,8 @@ namespace Magento\CatalogSearch\Model\Search; use Magento\Catalog\Api\Data\EavAttributeInterface; use Magento\Catalog\Model\Entity\Attribute; use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory; -use Magento\Framework\Search\Request\BucketInterface; +use Magento\CatalogSearch\Model\Search\RequestGenerator\GeneratorResolver; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Search\Request\FilterInterface; use Magento\Framework\Search\Request\QueryInterface; @@ -25,12 +26,22 @@ class RequestGenerator */ private $productAttributeCollectionFactory; + /** + * @var GeneratorResolver + */ + private $generatorResolver; + /** * @param CollectionFactory $productAttributeCollectionFactory + * @param GeneratorResolver $generatorResolver */ - public function __construct(CollectionFactory $productAttributeCollectionFactory) - { + public function __construct( + CollectionFactory $productAttributeCollectionFactory, + GeneratorResolver $generatorResolver = null + ) { $this->productAttributeCollectionFactory = $productAttributeCollectionFactory; + $this->generatorResolver = $generatorResolver + ?: ObjectManager::getInstance()->get(GeneratorResolver::class); } /** @@ -62,7 +73,7 @@ class RequestGenerator $request = []; foreach ($this->getSearchableAttributes() as $attribute) { if ($attribute->getData($attributeType)) { - if (!in_array($attribute->getAttributeCode(), ['price', 'category_ids'])) { + if (!in_array($attribute->getAttributeCode(), ['price', 'category_ids'], true)) { $queryName = $attribute->getAttributeCode() . '_query'; $request['queries'][$container]['queryReference'][] = [ @@ -76,58 +87,33 @@ class RequestGenerator 'filterReference' => [['ref' => $filterName]], ]; $bucketName = $attribute->getAttributeCode() . self::BUCKET_SUFFIX; - if ($attribute->getBackendType() == 'decimal') { - $request['filters'][$filterName] = [ - 'type' => FilterInterface::TYPE_RANGE, - 'name' => $filterName, - 'field' => $attribute->getAttributeCode(), - 'from' => '$' . $attribute->getAttributeCode() . '.from$', - 'to' => '$' . $attribute->getAttributeCode() . '.to$', - ]; - $request['aggregations'][$bucketName] = [ - 'type' => BucketInterface::TYPE_DYNAMIC, - 'name' => $bucketName, - 'field' => $attribute->getAttributeCode(), - 'method' => 'manual', - 'metric' => [["type" => "count"]], - ]; - } else { - $request['filters'][$filterName] = [ - 'type' => FilterInterface::TYPE_TERM, - 'name' => $filterName, - 'field' => $attribute->getAttributeCode(), - 'value' => '$' . $attribute->getAttributeCode() . '$', - ]; - $request['aggregations'][$bucketName] = [ - 'type' => BucketInterface::TYPE_TERM, - 'name' => $bucketName, - 'field' => $attribute->getAttributeCode(), - 'metric' => [["type" => "count"]], - ]; - } + $generator = $this->generatorResolver->getGeneratorForType($attribute->getBackendType()); + $request['filters'][$filterName] = $generator->getFilterData($attribute, $filterName); + $request['aggregations'][$bucketName] = $generator->getAggregationData($attribute, $bucketName); } } /** @var $attribute Attribute */ - if (in_array($attribute->getAttributeCode(), ['price', 'sku']) - || !$attribute->getIsSearchable() - ) { - //same fields have special semantics + if (!$attribute->getIsSearchable() || in_array($attribute->getAttributeCode(), ['price', 'sku'], true)) { + // Some fields have their own specific handlers continue; } - if ($useFulltext) { + + // Match search by custom price attribute isn't supported + if ($useFulltext && $attribute->getFrontendInput() !== 'price') { $request['queries']['search']['match'][] = [ 'field' => $attribute->getAttributeCode(), 'boost' => $attribute->getSearchWeight() ?: 1, ]; } } + return $request; } /** * Retrieve searchable attributes * - * @return \Magento\Catalog\Model\Entity\Attribute[] + * @return \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection */ protected function getSearchableAttributes() { @@ -231,6 +217,7 @@ class RequestGenerator ]; } } + return $request; } } diff --git a/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/Decimal.php b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/Decimal.php new file mode 100644 index 0000000000000000000000000000000000000000..52cab1c6ff942b3a94418a808ac96ff6ff5f678a --- /dev/null +++ b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/Decimal.php @@ -0,0 +1,44 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Model\Search\RequestGenerator; + + +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; +use Magento\Framework\Search\Request\BucketInterface; +use Magento\Framework\Search\Request\FilterInterface; + +class Decimal implements GeneratorInterface +{ + + /** + * {@inheritdoc} + */ + public function getFilterData(Attribute $attribute, $filterName) + { + return [ + 'type' => FilterInterface::TYPE_RANGE, + 'name' => $filterName, + 'field' => $attribute->getAttributeCode(), + 'from' => '$' . $attribute->getAttributeCode() . '.from$', + 'to' => '$' . $attribute->getAttributeCode() . '.to$', + ]; + } + + /** + * {@inheritdoc} + */ + public function getAggregationData(Attribute $attribute, $bucketName) + { + return [ + 'type' => BucketInterface::TYPE_DYNAMIC, + 'name' => $bucketName, + 'field' => $attribute->getAttributeCode(), + 'method' => 'manual', + 'metric' => [['type' => 'count']], + ]; + } +} diff --git a/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/General.php b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/General.php new file mode 100644 index 0000000000000000000000000000000000000000..96362ce484b1ee8981d45c0661b760d62b1b7303 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/General.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Model\Search\RequestGenerator; + + +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; +use Magento\Framework\Search\Request\BucketInterface; +use Magento\Framework\Search\Request\FilterInterface; + +class General implements GeneratorInterface +{ + + /** + * {@inheritdoc} + */ + public function getFilterData(Attribute $attribute, $filterName) + { + return [ + 'type' => FilterInterface::TYPE_TERM, + 'name' => $filterName, + 'field' => $attribute->getAttributeCode(), + 'value' => '$' . $attribute->getAttributeCode() . '$', + ]; + } + + /** + * {@inheritdoc} + */ + public function getAggregationData(Attribute $attribute, $bucketName) + { + return [ + 'type' => BucketInterface::TYPE_TERM, + 'name' => $bucketName, + 'field' => $attribute->getAttributeCode(), + 'metric' => [['type' => 'count']], + ]; + } +} diff --git a/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/GeneratorInterface.php b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/GeneratorInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..c43786db2b6968761e4586f40bba9e4a8628f30a --- /dev/null +++ b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/GeneratorInterface.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Model\Search\RequestGenerator; + + +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; + +interface GeneratorInterface +{ + /** + * Get filter data for specific attribute + * @param Attribute $attribute + * @param string $filterName + * @return array + */ + public function getFilterData(Attribute $attribute, $filterName); + + /** + * Get aggregation data for specific attribute + * @param Attribute $attribute + * @param string $bucketName + * @return array + */ + public function getAggregationData(Attribute $attribute, $bucketName); +} diff --git a/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/GeneratorResolver.php b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/GeneratorResolver.php new file mode 100644 index 0000000000000000000000000000000000000000..129a036ff2544fe4c84a70da98cbf0bb31ace4cb --- /dev/null +++ b/app/code/Magento/CatalogSearch/Model/Search/RequestGenerator/GeneratorResolver.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Model\Search\RequestGenerator; + +class GeneratorResolver +{ + /** + * @var GeneratorInterface[] + */ + private $generators; + + /** + * @var GeneratorInterface + */ + private $defaultGenerator; + + /** + * @param GeneratorInterface $defaultGenerator + * @param GeneratorInterface[] $generators + */ + public function __construct(GeneratorInterface $defaultGenerator, array $generators) + { + $this->defaultGenerator = $defaultGenerator; + $this->generators = $generators; + } + + /** + * @param string $type + * @return GeneratorInterface + * @throws \InvalidArgumentException + */ + public function getGeneratorForType($type) + { + $generator = isset($this->generators[$type]) ? $this->generators[$type] : $this->defaultGenerator; + if (!($generator instanceof GeneratorInterface)) { + throw new \InvalidArgumentException( + 'Generator must implement ' . GeneratorInterface::class + ); + } + return $generator; + } +} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/AdvancedTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/AdvancedTest.php index e15b9b7818181180a22f55417e269d0dece2362e..afff7722fdec7b2eea34a590c85e048080489395 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/AdvancedTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/AdvancedTest.php @@ -170,7 +170,7 @@ class AdvancedTest extends \PHPUnit_Framework_TestCase 'static' ) ], - 'values' => ['is_active' => false], + 'values' => ['is_active' => 0], 'currentCurrencyCode' => 'GBP', 'baseCurrencyCode' => 'USD' ], diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/DecimalTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/DecimalTest.php new file mode 100644 index 0000000000000000000000000000000000000000..67a991f51856516ce3e2678bf768729f1d0aa86f --- /dev/null +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/DecimalTest.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Test\Unit\Model\Search\RequestGenerator; + +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; +use Magento\CatalogSearch\Model\Search\RequestGenerator\Decimal; +use Magento\Framework\Search\Request\BucketInterface; +use Magento\Framework\Search\Request\FilterInterface; + +class DecimalTest extends \PHPUnit_Framework_TestCase +{ + /** @var Decimal */ + private $decimal; + + /** @var Attribute|\PHPUnit_Framework_MockObject_MockObject */ + private $attribute; + + protected function setUp() + { + $this->attribute = $this->getMockBuilder(Attribute::class) + ->disableOriginalConstructor() + ->setMethods(['getAttributeCode']) + ->getMockForAbstractClass(); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->decimal = $objectManager->getObject(Decimal::class); + } + + public function testGetFilterData() + { + $filterName = 'test_filter_name'; + $attributeCode = 'test_attribute_code'; + $expected = [ + 'type' => FilterInterface::TYPE_RANGE, + 'name' => $filterName, + 'field' => $attributeCode, + 'from' => '$' . $attributeCode . '.from$', + 'to' => '$' . $attributeCode . '.to$', + ]; + $this->attribute->expects($this->atLeastOnce()) + ->method('getAttributeCode') + ->willReturn($attributeCode); + $actual = $this->decimal->getFilterData($this->attribute, $filterName); + $this->assertEquals($expected, $actual); + } + + public function testGetAggregationData() + { + $bucketName = 'test_bucket_name'; + $attributeCode = 'test_attribute_code'; + $expected = [ + 'type' => BucketInterface::TYPE_DYNAMIC, + 'name' => $bucketName, + 'field' => $attributeCode, + 'method' => 'manual', + 'metric' => [['type' => 'count']], + ]; + $this->attribute->expects($this->atLeastOnce()) + ->method('getAttributeCode') + ->willReturn($attributeCode); + $actual = $this->decimal->getAggregationData($this->attribute, $bucketName); + $this->assertEquals($expected, $actual); + } +} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/GeneralTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/GeneralTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d40829e6e53de8883b8f0b4ec4abb2b6d980da68 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/GeneralTest.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Test\Unit\Model\Search\RequestGenerator; + +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; +use Magento\CatalogSearch\Model\Search\RequestGenerator\General; +use Magento\Framework\Search\Request\BucketInterface; +use Magento\Framework\Search\Request\FilterInterface; + +class GeneralTest extends \PHPUnit_Framework_TestCase +{ + /** @var General */ + private $general; + + /** @var Attribute|\PHPUnit_Framework_MockObject_MockObject */ + private $attribute; + + protected function setUp() + { + $this->attribute = $this->getMockBuilder(Attribute::class) + ->disableOriginalConstructor() + ->setMethods(['getAttributeCode']) + ->getMockForAbstractClass(); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->general = $objectManager->getObject(General::class); + } + + public function testGetFilterData() + { + $filterName = 'test_general_filter_name'; + $attributeCode = 'test_general_attribute_code'; + $expected = [ + 'type' => FilterInterface::TYPE_TERM, + 'name' => $filterName, + 'field' => $attributeCode, + 'value' => '$' . $attributeCode . '$', + ]; + $this->attribute->expects($this->atLeastOnce()) + ->method('getAttributeCode') + ->willReturn($attributeCode); + $actual = $this->general->getFilterData($this->attribute, $filterName); + $this->assertEquals($expected, $actual); + } + + public function testGetAggregationData() + { + $bucketName = 'test_bucket_name'; + $attributeCode = 'test_attribute_code'; + $expected = [ + 'type' => BucketInterface::TYPE_TERM, + 'name' => $bucketName, + 'field' => $attributeCode, + 'metric' => [['type' => 'count']], + ]; + $this->attribute->expects($this->atLeastOnce()) + ->method('getAttributeCode') + ->willReturn($attributeCode); + $actual = $this->general->getAggregationData($this->attribute, $bucketName); + $this->assertEquals($expected, $actual); + } +} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/GeneratorResolverTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/GeneratorResolverTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0b8bf882b850e05d9a5eac0d4887d8756cf56331 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGenerator/GeneratorResolverTest.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\CatalogSearch\Test\Unit\Model\Search\RequestGenerator; + + +use Magento\CatalogSearch\Model\Search\RequestGenerator\GeneratorResolver; +use Magento\CatalogSearch\Model\Search\RequestGenerator\GeneratorInterface; + +class GeneratorResolverTest extends \PHPUnit_Framework_TestCase +{ + /** @var GeneratorResolver */ + private $resolver; + + /** @var GeneratorInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $defaultGenerator; + + /** @var GeneratorInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $datetimeGenerator; + + /** @var GeneratorInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $rangeGenerator; + + protected function setUp() + { + $this->defaultGenerator = $this->getMockBuilder(GeneratorInterface::class) + ->setMethods([]) + ->getMockForAbstractClass(); + + $this->datetimeGenerator = $this->getMockBuilder(GeneratorInterface::class) + ->setMethods([]) + ->getMockForAbstractClass(); + + $this->rangeGenerator = $this->getMockBuilder(GeneratorInterface::class) + ->setMethods([]) + ->getMockForAbstractClass(); + + $invalidTypeGenerator = $this->getMockBuilder(\stdClass::class) + ->setMethods([]); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->resolver = $objectManager->getObject( + GeneratorResolver::class, + [ + 'defaultGenerator' => $this->defaultGenerator, + 'generators' => [ + 'datetime' => $this->datetimeGenerator, + 'range' => $this->datetimeGenerator, + 'invalid_type' => $invalidTypeGenerator, + ], + ] + ); + } + + public function testGetSpecificGenerator() + { + $this->assertEquals($this->rangeGenerator, $this->resolver->getGeneratorForType('range')); + $this->assertEquals($this->datetimeGenerator, $this->resolver->getGeneratorForType('datetime')); + } + + public function testGetFallbackGenerator() + { + $this->assertEquals($this->defaultGenerator, $this->resolver->getGeneratorForType('unknown_type')); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testGetInvalidGeneratorType() + { + $this->resolver->getGeneratorForType('invalid_type'); + } +} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGeneratorTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGeneratorTest.php index f66bacfad306a0cd41cfc1a44206c3f0e60e6aa7..ca56dd83444b2b01d92b6c8e65023acdeeea277f 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGeneratorTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Search/RequestGeneratorTest.php @@ -6,6 +6,8 @@ namespace Magento\CatalogSearch\Test\Unit\Model\Search; use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory; +use Magento\CatalogSearch\Model\Search\RequestGenerator\GeneratorResolver; +use Magento\CatalogSearch\Model\Search\RequestGenerator\GeneratorInterface; class RequestGeneratorTest extends \PHPUnit_Framework_TestCase { @@ -25,11 +27,29 @@ class RequestGeneratorTest extends \PHPUnit_Framework_TestCase ->setMethods(['create']) ->disableOriginalConstructor() ->getMock(); + $generatorResolver = $this->getMockBuilder(GeneratorResolver::class) + ->disableOriginalConstructor() + ->setMethods(['getGeneratorForType']) + ->getMock(); + $generator = $this->getMockBuilder(GeneratorInterface::class) + ->setMethods(['getFilterData', 'getAggregationData']) + ->getMockForAbstractClass(); + $generator->expects($this->any()) + ->method('getFilterData') + ->willReturn(['some filter data goes here']); + $generator->expects($this->any()) + ->method('getAggregationData') + ->willReturn(['some aggregation data goes here']); + $generatorResolver->method('getGeneratorForType') + ->willReturn($generator); $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->object = $this->objectManagerHelper->getObject( \Magento\CatalogSearch\Model\Search\RequestGenerator::class, - ['productAttributeCollectionFactory' => $this->productAttributeCollectionFactory] + [ + 'productAttributeCollectionFactory' => $this->productAttributeCollectionFactory, + 'generatorResolver' => $generatorResolver + ] ); } @@ -87,6 +107,14 @@ class RequestGeneratorTest extends \PHPUnit_Framework_TestCase ], ['attr_int', 'int', 0, 1, 0] ], + [ + [ + 'quick_search_container' => ['queries' => 2, 'filters' => 1, 'aggregations' => 1], + 'advanced_search_container' => ['queries' => 0, 'filters' => 0, 'aggregations' => 0], + 'catalog_view_container' => ['queries' => 0, 'filters' => 0, 'aggregations' => 0], + ], + ['custom_price_attr', 'price', 0, 1, 0], + ], ]; } @@ -124,19 +152,23 @@ class RequestGeneratorTest extends \PHPUnit_Framework_TestCase $this->assertEquals( $countResult['quick_search_container']['queries'], - $this->countVal($result['quick_search_container']['queries']) + $this->countVal($result['quick_search_container']['queries']), + 'Queries count for "quick_search_container" doesn\'t match' ); $this->assertEquals( $countResult['advanced_search_container']['queries'], - $this->countVal($result['advanced_search_container']['queries']) + $this->countVal($result['advanced_search_container']['queries']), + 'Queries count for "advanced_search_container" doesn\'t match' ); $this->assertEquals( $countResult['advanced_search_container']['filters'], - $this->countVal($result['advanced_search_container']['filters']) + $this->countVal($result['advanced_search_container']['filters']), + 'Filters count for "advanced_search_container" doesn\'t match' ); $this->assertEquals( $countResult['catalog_view_container']['queries'], - $this->countVal($result['catalog_view_container']['queries']) + $this->countVal($result['catalog_view_container']['queries']), + 'Queries count for "catalog_view_container" doesn\'t match' ); } @@ -144,11 +176,12 @@ class RequestGeneratorTest extends \PHPUnit_Framework_TestCase * Create attribute mock * * @param $attributeOptions - * @return \PHPUnit_Framework_MockObject_MockObject + * @return \Magento\Catalog\Model\Entity\Attribute|\PHPUnit_Framework_MockObject_MockObject */ private function createAttributeMock($attributeOptions) { - $attribute = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Attribute::class) + /** @var \Magento\Catalog\Model\Entity\Attribute|\PHPUnit_Framework_MockObject_MockObject $attribute */ + $attribute = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) ->disableOriginalConstructor() ->setMethods( [ @@ -184,8 +217,8 @@ class RequestGeneratorTest extends \PHPUnit_Framework_TestCase ->method('getData') ->willReturnMap( [ - ['is_filterable', $attributeOptions[2]], - ['is_filterable_in_search', $attributeOptions[3]] + ['is_filterable', null, $attributeOptions[2]], + ['is_filterable_in_search', null, $attributeOptions[3]], ] ); diff --git a/app/code/Magento/CatalogSearch/etc/di.xml b/app/code/Magento/CatalogSearch/etc/di.xml index e715b5fea7cd05edc4f1fa50e894f685d9747bd2..f62b4e47767a25230c5c2ad8372f99acc6bda2eb 100644 --- a/app/code/Magento/CatalogSearch/etc/di.xml +++ b/app/code/Magento/CatalogSearch/etc/di.xml @@ -237,4 +237,12 @@ </argument> </arguments> </type> + <type name="Magento\CatalogSearch\Model\Search\RequestGenerator\GeneratorResolver"> + <arguments> + <argument name="defaultGenerator" xsi:type="object">\Magento\CatalogSearch\Model\Search\RequestGenerator\General</argument> + <argument name="generators" xsi:type="array"> + <item name="decimal" xsi:type="object">Magento\CatalogSearch\Model\Search\RequestGenerator\Decimal</item> + </argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_configure.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_configure.xml index 403e07c64d3ede27b5830a44ccdffbcaa5961273..c255f17cd36974518b8dc932e2a74e6726e6a266 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_configure.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_configure.xml @@ -6,6 +6,9 @@ */ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <head> + <link src="Magento_Checkout::js/view/configure/product-customer-data.js"/> + </head> <update handle="catalog_product_view"/> <body> <referenceBlock name="head.components"> diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml index fe39e9c44ada8b421966103b8d1810d82c21bc7b..0f221a393f5eb181f31a778ce4d01da1b0cc109b 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml @@ -17,7 +17,7 @@ <div class="field qty"> <label class="label" for="qty"><span><?php /* @escapeNotVerified */ echo __('Qty') ?></span></label> <div class="control"> - <input type="number" name="qty" id="qty" maxlength="12" value="<?php /* @escapeNotVerified */ echo $block->getProductDefaultQty() * 1 ?>" title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" data-validate="{'required-number':true,digits:true}"/> + <input type="number" name="qty" id="qty" maxlength="12" value="" title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" data-validate="{'required-number':true,digits:true}"/> </div> </div> <?php endif; ?> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/configure/product-customer-data.js b/app/code/Magento/Checkout/view/frontend/web/js/view/configure/product-customer-data.js new file mode 100644 index 0000000000000000000000000000000000000000..a612b5e2dc6b7d38fa365911b81d67e5a3ca2aaa --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/configure/product-customer-data.js @@ -0,0 +1,59 @@ +require([ + 'jquery', + 'Magento_Customer/js/customer-data' +], function ($, customerData) { + 'use strict'; + + var selectors = { + qtySelector: '#product_addtocart_form [name="qty"]', + productIdSelector: '#product_addtocart_form [name="product"]' + }, + cartData = customerData.get('cart'), + productId = $(selectors.productIdSelector).val(), + productQty, + productQtyInput, + + /** + * Updates product's qty input value according to actual data + */ + updateQty = function () { + + if (productQty || productQty === 0) { + productQtyInput = productQtyInput || $(selectors.qtySelector); + + if (productQtyInput && productQty.toString() !== productQtyInput.val()) { + productQtyInput.val(productQty); + } + } + }, + + /** + * Sets productQty according to cart data from customer-data + * + * @param {Object} data - cart data from customer-data + */ + setProductQty = function (data) { + var product; + + if (!(data && data.items && data.items.length && productId)) { + return; + } + product = data.items.find(function (item) { + return item['product_id'] === productId || + item['item_id'] === productId; + }); + + if (!product) { + return; + } + productQty = product.qty; + }; + + cartData.subscribe(function (updateCartData) { + setProductQty(updateCartData); + updateQty(); + }); + + setProductQty(cartData()); + updateQty(); +}); diff --git a/app/code/Magento/Customer/view/frontend/requirejs-config.js b/app/code/Magento/Customer/view/frontend/requirejs-config.js index 53f12373bfd928a1fcea86ee50ba4038caf0cf6a..508737742cafe2e2cf9905571ae3655bba440ad5 100644 --- a/app/code/Magento/Customer/view/frontend/requirejs-config.js +++ b/app/code/Magento/Customer/view/frontend/requirejs-config.js @@ -10,7 +10,8 @@ var config = { address: 'Magento_Customer/address', changeEmailPassword: 'Magento_Customer/change-email-password', passwordStrengthIndicator: 'Magento_Customer/js/password-strength-indicator', - zxcvbn: 'Magento_Customer/js/zxcvbn' + zxcvbn: 'Magento_Customer/js/zxcvbn', + addressValidation: 'Magento_Customer/js/addressValidation' } } }; diff --git a/app/code/Magento/Customer/view/frontend/templates/address/edit.phtml b/app/code/Magento/Customer/view/frontend/templates/address/edit.phtml index 2de971bf6a9c05d1c07cb5745272fcad7a135e23..17d7c9852fc4b5e0efa4ba8342a9bcff0d97d805 100644 --- a/app/code/Magento/Customer/view/frontend/templates/address/edit.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/address/edit.phtml @@ -203,7 +203,7 @@ <script type="text/x-magento-init"> { "#form-validate": { - "validation": {} + "addressValidation": {} }, "#country": { "regionUpdater": { diff --git a/app/code/Magento/Customer/view/frontend/web/js/addressValidation.js b/app/code/Magento/Customer/view/frontend/web/js/addressValidation.js new file mode 100644 index 0000000000000000000000000000000000000000..c01463b4046aebc4277fcaf6d8765d1d7a785893 --- /dev/null +++ b/app/code/Magento/Customer/view/frontend/web/js/addressValidation.js @@ -0,0 +1,43 @@ +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +define([ + 'jquery', + 'jquery/ui', + 'validation' +], function ($) { + 'use strict'; + + $.widget('mage.addressValidation', { + options: { + selectors: { + button: '[data-action=save-address]' + } + }, + + /** + * Validation creation + * @protected + */ + _create: function () { + var button = $(this.options.selectors.button, this.element); + + this.element.validation({ + + /** + * Submit Handler + * @param {Element} form - address form + */ + submitHandler: function (form) { + + button.attr('disabled', true); + form.submit(); + } + }); + } + }); + + return $.mage.addressValidation; +}); diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php index c3e5a4b0c4d462b2f7e6576e7c8666e71b18be58..878ddf812028825267297aac958c22c14070f7b9 100644 --- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php +++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php @@ -950,6 +950,7 @@ abstract class AbstractEntity extends AbstractResource implements EntityInterfac /** * Load object base row data */ + $object->beforeLoad($entityId); $select = $this->_getLoadRowSelect($object, $entityId); $row = $this->getConnection()->fetchRow($select); @@ -962,11 +963,10 @@ abstract class AbstractEntity extends AbstractResource implements EntityInterfac $this->loadAttributesMetadata($attributes); $this->_loadModelAttributes($object); - - $object->setOrigData(); - $this->_afterLoad($object); - + $object->afterLoad(); + $object->setOrigData(); + $object->setHasDataChanges(false); \Magento\Framework\Profiler::stop('EAV:load_entity'); return $this; } diff --git a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php index c4d9657a322dab4b48a1668f908021de223f050b..d176b5be6a4551d9d7162ebf5d9436f99aadcd37 100644 --- a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php +++ b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php @@ -151,25 +151,28 @@ class Tablerate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implemen $request->setPackageQty($oldQty); if (!empty($rate) && $rate['price'] >= 0) { - /** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */ - $method = $this->_resultMethodFactory->create(); - - $method->setCarrier('tablerate'); - $method->setCarrierTitle($this->getConfigData('title')); - - $method->setMethod('bestway'); - $method->setMethodTitle($this->getConfigData('name')); - if ($request->getFreeShipping() === true || $request->getPackageQty() == $freeQty) { $shippingPrice = 0; } else { $shippingPrice = $this->getFinalPriceWithHandlingFee($rate['price']); } - - $method->setPrice($shippingPrice); - $method->setCost($rate['cost']); - + $method = $this->createShippingMethod($shippingPrice, $rate['cost']); $result->append($method); + } elseif (empty($rate) && $request->getFreeShipping() === true || $request->getPackageQty() == $freeQty) { + + /** + * Promotion rule was applied for the whole cart. + * In this case all other shipping methods could be omitted + * Table rate shipping method with 0$ price must be shown if grand total is more than minimal value. + * Free package weight has been already taken into account. + */ + $request->setPackageValue($freePackageValue); + $request->setPackageQty($freeQty); + $rate = $this->getRate($request); + if (!empty($rate) && $rate['price'] >= 0) { + $method = $this->createShippingMethod(0, 0); + $result->append($method); + } } else { /** @var \Magento\Quote\Model\Quote\Address\RateResult\Error $error */ $error = $this->_rateErrorFactory->create( @@ -241,4 +244,27 @@ class Tablerate extends \Magento\Shipping\Model\Carrier\AbstractCarrier implemen { return ['bestway' => $this->getConfigData('name')]; } + + /** + * Get the method object based on the shipping price and cost + * + * @param float $shippingPrice + * @param float $cost + * @return \Magento\Quote\Model\Quote\Address\RateResult\Method + */ + private function createShippingMethod($shippingPrice, $cost) + { + /** @var \Magento\Quote\Model\Quote\Address\RateResult\Method $method */ + $method = $this->_resultMethodFactory->create(); + + $method->setCarrier('tablerate'); + $method->setCarrierTitle($this->getConfigData('title')); + + $method->setMethod('bestway'); + $method->setMethodTitle($this->getConfigData('name')); + + $method->setPrice($shippingPrice); + $method->setCost($cost); + return $method; + } } diff --git a/app/code/Magento/Payment/view/adminhtml/web/transparent.js b/app/code/Magento/Payment/view/adminhtml/web/transparent.js index 583945d39612e67ad99318dafca192a9355bd453..b94e9bd4b2673465e807fda1c54edf6af36f5980 100644 --- a/app/code/Magento/Payment/view/adminhtml/web/transparent.js +++ b/app/code/Magento/Payment/view/adminhtml/web/transparent.js @@ -6,12 +6,14 @@ define([ 'jquery', 'mage/template', - 'Magento_Ui/js/modal/alert' + 'Magento_Ui/js/modal/alert', + 'Magento_Payment/js/model/credit-card-validation/validator' ], function ($, mageTemplate, alert) { 'use strict'; $.widget('mage.transparent', { options: { + editFormSelector: '#edit_form', hiddenFormTmpl: '<form target="<%= data.target %>" action="<%= data.action %>"' + 'method="POST" hidden' + @@ -33,37 +35,51 @@ define([ * @private */ _create: function () { + this.hiddenFormTmpl = mageTemplate(this.options.hiddenFormTmpl); - /** - * @param {Object} event - * @param {String} method - */ - var prepare = function (event, method) { - if (method === this.options.gateway) { - $('#edit_form') - .off('submitOrder') - .on('submitOrder.' + this.options.gateway, this._orderSave.bind(this)); - } else { - $('#edit_form') - .off('submitOrder.' + this.options.gateway); - } - }, - $editForm = $('#edit_form'); + $(this.options.editFormSelector).on('changePaymentMethod', this._setPlaceOrderHandler.bind(this)); + $(this.options.editFormSelector).trigger('changePaymentMethod', [ + $(this.options.editFormSelector).find(':radio[name="payment[method]"]:checked').val() + ]); + }, - this.hiddenFormTmpl = mageTemplate(this.options.hiddenFormTmpl); - $editForm.on('changePaymentMethod', prepare.bind(this)); - - $editForm.trigger( - 'changePaymentMethod', - [ - $editForm.find(':radio[name="payment[method]"]:checked').val() - ] - ); + /** + * Handler for form submit. + * + * @param {Object} event + * @param {String} method + */ + _setPlaceOrderHandler: function (event, method) { + if (method === this.options.gateway) { + $(this.options.editFormSelector) + .off('submitOrder') + .on('submitOrder.' + this.options.gateway, this._placeOrderHandler.bind(this)); + } else { + $(this.options.editFormSelector) + .off('submitOrder.' + this.options.gateway); + } + }, + + /** + * Handler for form submit to call gateway for credit card validation. + * + * @return {Boolean} + * @private + */ + _placeOrderHandler: function () { + if ($(this.options.editFormSelector).valid()) { + this._orderSave(); + } else { + $('body').trigger('processStop'); + } + + return false; }, /** - * handler for Place Order button to call gateway for credit card validation - * Save order and generate post data for gateway call + * Handler for Place Order button to call gateway for credit card validation. + * Save order and generate post data for gateway call. + * * @private */ _orderSave: function () { @@ -99,7 +115,8 @@ define([ }, /** - * Post data to gateway for credit card validation + * Post data to gateway for credit card validation. + * * @param {Object} response * @private */ @@ -136,7 +153,7 @@ define([ }, /** - * Add credit card fields to post data for gateway + * Add credit card fields to post data for gateway. * * @param {Object} response * @private diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-data.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-data.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/cvv-validator.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/cvv-validator.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js diff --git a/app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js b/app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js similarity index 100% rename from app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js rename to app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js diff --git a/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml b/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml index b1a50bcb1bf73db9232cf3457e26215bebe92eff..4c1a3d8e4a41007ade8e32ebf1371c1b55278c32 100644 --- a/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml +++ b/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml @@ -129,12 +129,12 @@ $ccExpMonth = $block->getInfoData('cc_exp_month'); <?php endif; ?> <?php if($block->isVaultEnabled()): ?> - <div class="field-tooltip-content"> + <div class="admin__field admin__field-option field-tooltip-content"> <input type="checkbox" id="<?php /* @noEscape */ echo $code; ?>_vault" name="payment[is_active_payment_token_enabler]" class="admin__control-checkbox"/> - <label class="label" for="<?php /* @noEscape */ echo $code; ?>_vault"> + <label class="admin__field-label" for="<?php /* @noEscape */ echo $code; ?>_vault"> <span><?php echo $block->escapeHtml('Save for later use.'); ?></span> </label> </div> diff --git a/app/code/Magento/Review/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ReviewTest.php b/app/code/Magento/Review/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ReviewTest.php index 7685fc0fed94df32b0e0638e65d6d15f6de1d5ce..b93cb70fdda3d9cc9b6d8d9f7bb565d576392de4 100644 --- a/app/code/Magento/Review/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ReviewTest.php +++ b/app/code/Magento/Review/Test/Unit/Ui/DataProvider/Product/Form/Modifier/ReviewTest.php @@ -8,6 +8,8 @@ namespace Magento\Review\Test\Unit\Ui\DataProvider\Product\Form\Modifier; use Magento\Catalog\Test\Unit\Ui\DataProvider\Product\Form\Modifier\AbstractModifierTest; use Magento\Framework\UrlInterface; use Magento\Review\Ui\DataProvider\Product\Form\Modifier\Review; +use Magento\Framework\Module\Manager as ModuleManager; +use Magento\Ui\DataProvider\Modifier\ModifierInterface; /** * Class ReviewTest @@ -19,36 +21,73 @@ class ReviewTest extends AbstractModifierTest */ protected $urlBuilderMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $moduleManagerMock; + protected function setUp() { parent::setUp(); $this->urlBuilderMock = $this->getMockBuilder(UrlInterface::class) ->getMockForAbstractClass(); + $this->moduleManagerMock = $this->getMock(ModuleManager::class, [], [], '', false); } + /** + * @return ModifierInterface + */ protected function createModel() { - return $this->objectManager->getObject(Review::class, [ + $model = $this->objectManager->getObject(Review::class, [ 'locator' => $this->locatorMock, 'urlBuilder' => $this->urlBuilderMock, ]); + + $reviewClass = new \ReflectionClass(Review::class); + $moduleManagerProperty = $reviewClass->getProperty('moduleManager'); + $moduleManagerProperty->setAccessible(true); + $moduleManagerProperty->setValue( + $model, + $this->moduleManagerMock + ); + + return $model; } - public function testModifyMetaToBeEmpty() + public function testModifyMetaDoesNotAddReviewSectionForNewProduct() + { + $this->productMock->expects($this->once()) + ->method('getId'); + + $this->assertSame([], $this->getModel()->modifyMeta([])); + } + + public function testModifyMetaDoesNotAddReviewSectionIfReviewModuleOutputIsDisabled() { $this->productMock->expects($this->once()) ->method('getId') - ->willReturn(0); + ->willReturn(1); + + $this->moduleManagerMock->expects($this->any()) + ->method('isOutputEnabled') + ->with('Magento_Review') + ->willReturn(false); $this->assertSame([], $this->getModel()->modifyMeta([])); } - public function testModifyMeta() + public function testModifyMetaAddsReviewSectionForExistingProductIfReviewModuleOutputIsEnabled() { $this->productMock->expects($this->once()) ->method('getId') ->willReturn(1); + $this->moduleManagerMock->expects($this->any()) + ->method('isOutputEnabled') + ->with('Magento_Review') + ->willReturn(true); + $this->assertArrayHasKey(Review::GROUP_REVIEW, $this->getModel()->modifyMeta([])); } diff --git a/app/code/Magento/Review/Ui/DataProvider/Product/Form/Modifier/Review.php b/app/code/Magento/Review/Ui/DataProvider/Product/Form/Modifier/Review.php index 82141b5ab2f12a03e44463555e7b0a302630b0d2..0ef1057eb4be7ffd23fe794bef67663dc247b5c6 100644 --- a/app/code/Magento/Review/Ui/DataProvider/Product/Form/Modifier/Review.php +++ b/app/code/Magento/Review/Ui/DataProvider/Product/Form/Modifier/Review.php @@ -12,6 +12,8 @@ use Magento\Catalog\Model\Locator\LocatorInterface; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Ui\Component\Form; use Magento\Framework\UrlInterface; +use Magento\Framework\Module\Manager as ModuleManager; +use Magento\Framework\App\ObjectManager; /** * Class Review @@ -34,6 +36,11 @@ class Review extends AbstractModifier */ protected $urlBuilder; + /** + * @var ModuleManager + */ + private $moduleManager; + /** * @param LocatorInterface $locator * @param UrlInterface $urlBuilder @@ -51,7 +58,7 @@ class Review extends AbstractModifier */ public function modifyMeta(array $meta) { - if (!$this->locator->getProduct()->getId()) { + if (!$this->locator->getProduct()->getId() || !$this->getModuleManager()->isOutputEnabled('Magento_Review')) { return $meta; } @@ -114,4 +121,19 @@ class Review extends AbstractModifier return $data; } + + /** + * Retrieve module manager instance using dependency lookup to keep this class backward compatible. + * + * @return ModuleManager + * + * @deprecated + */ + private function getModuleManager() + { + if ($this->moduleManager === null) { + $this->moduleManager = ObjectManager::getInstance()->get(ModuleManager::class); + } + return $this->moduleManager; + } } diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/History.php b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/History.php index 8a6674aa154b060cf1030101ff1fb1a9c3e0b6cc..a68c543acf731f5f435eaea029c57e069acd5e87 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/History.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/History.php @@ -157,13 +157,10 @@ class History extends \Magento\Backend\Block\Template implements \Magento\Backen if (!isset($item['created_at'])) { return ''; } - $date = $item['created_at'] instanceof \DateTimeInterface - ? $item['created_at'] - : new \DateTime($item['created_at']); if ('date' === $dateType) { - return $this->_localeDate->formatDateTime($date, $format, $format); + return $this->formatDate($item['created_at'], $format); } - return $this->_localeDate->formatDateTime($date, \IntlDateFormatter::NONE, $format); + return $this->formatTime($item['created_at'], $format); } /** diff --git a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/HistoryTest.php b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/HistoryTest.php index 6445fd36dd14669afda748c05a0d9b558f1c31e0..0edeac71709290d7a3f3a8ace81604e35dd92feb 100644 --- a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/HistoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/HistoryTest.php @@ -30,6 +30,16 @@ class HistoryTest extends \PHPUnit_Framework_TestCase */ protected $coreRegistryMock; + /** + * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $localeDateMock; + + /** + * @var \Magento\Backend\Block\Template\Context|\PHPUnit_Framework_MockObject_MockObject + */ + protected $contextMock; + protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -37,11 +47,25 @@ class HistoryTest extends \PHPUnit_Framework_TestCase $this->coreRegistryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); $this->adminHelperMock = $this->getMock(\Magento\Sales\Helper\Admin::class, [], [], '', false); + $this->contextMock = $this->getMockBuilder(\Magento\Backend\Block\Template\Context::class) + ->disableOriginalConstructor() + ->setMethods(['getLocaleDate']) + ->getMock(); + + $this->localeDateMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class) + ->getMock(); + + $this->contextMock->expects($this->any())->method('getLocaleDate')->will( + $this->returnValue($this->localeDateMock) + ); + $this->commentsHistory = $this->objectManager->getObject( \Magento\Sales\Block\Adminhtml\Order\View\Tab\History::class, [ 'adminHelper' => $this->adminHelperMock, - 'registry' => $this->coreRegistryMock + 'registry' => $this->coreRegistryMock, + 'context' => $this->contextMock, + 'localeDate' => $this->localeDateMock ] ); } @@ -63,4 +87,39 @@ class HistoryTest extends \PHPUnit_Framework_TestCase $this->adminHelperMock->expects($this->never())->method('escapeHtmlWithLinks'); $this->assertEquals('', $this->commentsHistory->getItemComment($item)); } + + public function testGetItemCreatedAtDate() + { + $date = new \DateTime; + $item = ['created_at' => $date ]; + + $this->localeDateMock->expects($this->once()) + ->method('formatDateTime') + ->with($date, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE) + ->willReturn('date'); + + $this->assertEquals('date', $this->commentsHistory->getItemCreatedAt($item)); + } + + public function testGetItemCreatedAtTime() + { + $date = new \DateTime; + $item = ['created_at' => $date ]; + + $this->localeDateMock->expects($this->once()) + ->method('formatDateTime') + ->with($date, \IntlDateFormatter::NONE, \IntlDateFormatter::MEDIUM) + ->willReturn('time'); + + $this->assertEquals('time', $this->commentsHistory->getItemCreatedAt($item, 'time')); + } + + public function testGetItemCreatedAtEmpty() + { + $item = ['title' => "Test" ]; + + $this->localeDateMock->expects($this->never())->method('formatDateTime'); + $this->assertEquals('', $this->commentsHistory->getItemCreatedAt($item)); + $this->assertEquals('', $this->commentsHistory->getItemCreatedAt($item, 'time')); + } } diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form.phtml index 4b53e0ccb1e9fefd91ea23c555dc64c7f617ca72..fe212490a2fd00c9e18fc6fea8ab28b01e34e45d 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form.phtml @@ -8,7 +8,7 @@ /** @var \Magento\Sales\Block\Adminhtml\Order\Create\Form $block */ ?> -<form id="edit_form" data-order-config='<?php /* @escapeNotVerified */ echo $block->getOrderDataJson() ?>' data-load-base-url="<?php /* @escapeNotVerified */ echo $block->getLoadBlockUrl() ?>" action="<?php /* @escapeNotVerified */ echo $block->getSaveUrl() ?>" method="post" enctype="multipart/form-data"> +<form id="edit_form" data-order-config='<?php echo $block->escapeHtml($block->getOrderDataJson()) ?>' data-load-base-url="<?php /* @escapeNotVerified */ echo $block->getLoadBlockUrl() ?>" action="<?php /* @escapeNotVerified */ echo $block->getSaveUrl() ?>" method="post" enctype="multipart/form-data"> <?php echo $block->getBlockHtml('formkey')?> <div id="order-message"> <?php echo $block->getChildHtml('message') ?> diff --git a/app/code/Magento/SalesRule/etc/di.xml b/app/code/Magento/SalesRule/etc/di.xml index 2c731823b778fabe6faab37024f4e9ea60247538..83364f924397d857030a9f039ed1ab59dc0fd5f0 100644 --- a/app/code/Magento/SalesRule/etc/di.xml +++ b/app/code/Magento/SalesRule/etc/di.xml @@ -78,7 +78,7 @@ <type name="Magento\Framework\Model\Entity\RepositoryFactory"> <arguments> <argument name="entities" xsi:type="array"> - <item name="Magento\SalesRule\Api\Data\RuleInterface" xsi:type="string">Magento\SalesRule\Api\RuleRepositoryInterface</item> + <item name="Magento\SalesRule\Api\Data\RuleInterface" xsi:type="string">Magento\SalesRule\Model\ResourceModel\Rule</item> </argument> </arguments> </type> diff --git a/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/MetaTest.php b/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/MetaTest.php index 42f4d098ebcba34d91b6eac8944ebb5072040af3..7a842b8d1c908309c887b2fb5dc5f85f1e36213a 100644 --- a/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/MetaTest.php +++ b/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/MetaTest.php @@ -161,6 +161,7 @@ class MetaTest extends \PHPUnit_Framework_TestCase ->willReturn($metaId); $this->metaFactory->expects($this->once())->method('create')->willReturn($this->meta); $this->stepCheckSaveWithActiveProfile($metaData); + $this->meta->expects($this->once())->method('beforeLoad'); $this->assertEquals($this->meta, $this->resource->loadByEntityTypeAndStore($entityType, $storeId)); } @@ -177,7 +178,5 @@ class MetaTest extends \PHPUnit_Framework_TestCase ->method('quoteIdentifier'); $this->connectionMock->expects($this->once())->method('fetchRow')->willReturn($metaData); $this->resourceProfile->expects($this->once())->method('loadActiveProfile')->willReturn($this->profile); - $this->meta->expects($this->at(0))->method('setData')->with($metaData); - $this->meta->expects($this->at(2))->method('setData')->with('active_profile', $this->profile); } } diff --git a/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/ProfileTest.php b/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/ProfileTest.php index c3c827ba2f97a4e795a8f4d5633ebbf0736ba58e..b17445e7014fa618d2eb9c014f5a6b9bbc7d7f43 100644 --- a/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/ProfileTest.php +++ b/app/code/Magento/SalesSequence/Test/Unit/Model/ResourceModel/ProfileTest.php @@ -156,7 +156,7 @@ class ProfileTest extends \PHPUnit_Framework_TestCase $this->connectionMock->expects($this->any()) ->method('quoteIdentifier'); $this->connectionMock->expects($this->once())->method('fetchRow')->willReturn($profileData); - $this->profile->expects($this->at(0))->method('setData')->with($profileData); + $this->profile->expects($this->at(1))->method('setData')->with($profileData); $this->assertEquals($this->profile, $this->resource->loadActiveProfile($metaId)); } } diff --git a/app/code/Magento/Ui/view/base/layout/default.xml b/app/code/Magento/Ui/view/base/layout/default.xml index 7f2efbd8558728f386856acb5dd38bd1c4dcbb31..64d5f1483a2f307b85966eccb316ad8ee782507a 100644 --- a/app/code/Magento/Ui/view/base/layout/default.xml +++ b/app/code/Magento/Ui/view/base/layout/default.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="after.body.start"> <block class="Magento\Ui\Block\Logger" name="logger" template="Magento_Ui::logger.phtml"/> diff --git a/composer.json b/composer.json index a5f4b8c427ffffcbf85d9be78bcd89bf0928625a..63d02e7c0a8b47dcadcd7444faa17a2d0435950c 100644 --- a/composer.json +++ b/composer.json @@ -31,9 +31,9 @@ "zendframework/zend-serializer": "~2.4.6", "zendframework/zend-log": "~2.4.6", "zendframework/zend-http": "~2.4.6", - "magento/zendframework1": "1.12.16", + "magento/zendframework1": "~1.12.16", "colinmollenhour/credis": "1.6", - "colinmollenhour/php-redis-session-abstract": "1.1", + "colinmollenhour/php-redis-session-abstract": "1.2", "colinmollenhour/cache-backend-redis": "1.9", "colinmollenhour/cache-backend-file": "1.4", "composer/composer": "1.0.0-beta1", diff --git a/composer.lock b/composer.lock index d842cdec858b705c27295b5b1b1d6e89ae5a6b19..54a2b572c024bda51e7c7c2458fab8c45e2acb37 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "1c5d7ca4fa68bea1ab7490cb8ac62342", - "content-hash": "ecfa548096f500a6a98a5fc41c21e53b", + "hash": "0cd85c424e865c554b2f8db093192cfd", + "content-hash": "d74ec028da2018e1a161a2e1b70d3f87", "packages": [ { "name": "braintree/braintree_php", @@ -167,21 +167,21 @@ }, { "name": "colinmollenhour/php-redis-session-abstract", - "version": "v1.1", + "version": "v1.2", "source": { "type": "git", "url": "https://github.com/colinmollenhour/php-redis-session-abstract.git", - "reference": "95330b7f29663dab81f53d1a438e4d927b6c5f66" + "reference": "2b552c9bbe06967329dd41e1bd3e0aed02313ddb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/php-redis-session-abstract/zipball/95330b7f29663dab81f53d1a438e4d927b6c5f66", - "reference": "95330b7f29663dab81f53d1a438e4d927b6c5f66", + "url": "https://api.github.com/repos/colinmollenhour/php-redis-session-abstract/zipball/2b552c9bbe06967329dd41e1bd3e0aed02313ddb", + "reference": "2b552c9bbe06967329dd41e1bd3e0aed02313ddb", "shasum": "" }, "require": { "colinmollenhour/credis": "1.6", - "magento/zendframework1": "1.12.16", + "magento/zendframework1": "~1.12.0", "php": "~5.5.0|~5.6.0|~7.0.0" }, "type": "library", @@ -201,7 +201,7 @@ ], "description": "A Redis-based session handler with optimistic locking", "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", - "time": "2016-02-03 18:13:49" + "time": "2016-08-04 18:05:51" }, { "name": "composer/composer", @@ -280,16 +280,16 @@ }, { "name": "composer/semver", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98" + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", - "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", + "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", "shasum": "" }, "require": { @@ -338,7 +338,7 @@ "validation", "versioning" ], - "time": "2016-06-02 09:04:51" + "time": "2016-08-30 16:08:34" }, { "name": "composer/spdx-licenses", @@ -633,16 +633,16 @@ }, { "name": "magento/zendframework1", - "version": "1.12.16", + "version": "1.12.16-patch1", "source": { "type": "git", "url": "https://github.com/magento/zf1.git", - "reference": "c9d607bfd9454bc18b9deff737ccd5d044e2ab10" + "reference": "b4502f38f88ff2bc22a906c108cc3da18dcce12f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/zf1/zipball/c9d607bfd9454bc18b9deff737ccd5d044e2ab10", - "reference": "c9d607bfd9454bc18b9deff737ccd5d044e2ab10", + "url": "https://api.github.com/repos/magento/zf1/zipball/b4502f38f88ff2bc22a906c108cc3da18dcce12f", + "reference": "b4502f38f88ff2bc22a906c108cc3da18dcce12f", "shasum": "" }, "require": { @@ -676,7 +676,7 @@ "ZF1", "framework" ], - "time": "2015-10-29 14:34:55" + "time": "2016-09-14 12:04:33" }, { "name": "monolog/monolog", @@ -1014,22 +1014,30 @@ }, { "name": "psr/log", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + "reference": "5277094ed527a1c4477177d102fe4c53551953e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0", + "reference": "5277094ed527a1c4477177d102fe4c53551953e0", "shasum": "" }, + "require": { + "php": ">=5.3.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "psr-0": { - "Psr\\Log\\": "" + "psr-4": { + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1043,12 +1051,13 @@ } ], "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ "log", "psr", "psr-3" ], - "time": "2012-12-21 11:40:51" + "time": "2016-09-19 16:02:08" }, { "name": "ramsey/uuid", @@ -1180,16 +1189,16 @@ }, { "name": "seld/jsonlint", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "66834d3e3566bb5798db7294619388786ae99394" + "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", - "reference": "66834d3e3566bb5798db7294619388786ae99394", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/e827b5254d3e58c736ea2c5616710983d80b0b70", + "reference": "e827b5254d3e58c736ea2c5616710983d80b0b70", "shasum": "" }, "require": { @@ -1222,7 +1231,7 @@ "parser", "validator" ], - "time": "2015-11-21 02:21:41" + "time": "2016-09-14 15:17:56" }, { "name": "seld/phar-utils", @@ -1381,7 +1390,7 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -1441,16 +1450,16 @@ }, { "name": "symfony/filesystem", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd" + "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ab4c3f085c8f5a56536845bf985c4cef30bf75fd", - "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/44b499521defddf2eae17a18c811bbdae4f98bdf", + "reference": "44b499521defddf2eae17a18c811bbdae4f98bdf", "shasum": "" }, "require": { @@ -1486,20 +1495,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-07-20 05:41:28" + "time": "2016-09-06 10:55:00" }, { "name": "symfony/finder", - "version": "v3.1.3", + "version": "v3.1.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7" + "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8201978de88a9fa0923e18601bb17f1df9c721e7", - "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7", + "url": "https://api.github.com/repos/symfony/finder/zipball/e568ef1784f447a0e54dcb6f6de30b9747b0f577", + "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577", "shasum": "" }, "require": { @@ -1535,20 +1544,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "time": "2016-08-26 12:04:02" }, { "name": "symfony/process", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c" + "reference": "05a03ed27073638658cab9405d99a67dd1014987" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d20332e43e8774ff8870b394f3dd6020cc7f8e0c", - "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c", + "url": "https://api.github.com/repos/symfony/process/zipball/05a03ed27073638658cab9405d99a67dd1014987", + "reference": "05a03ed27073638658cab9405d99a67dd1014987", "shasum": "" }, "require": { @@ -1584,7 +1593,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-07-28 11:13:19" + "time": "2016-09-06 10:55:00" }, { "name": "tedivm/jshrink", @@ -3233,16 +3242,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v1.12.0", + "version": "v1.12.1", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "ddac737e1c06a310a0bb4b3da755a094a31a916a" + "reference": "d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/ddac737e1c06a310a0bb4b3da755a094a31a916a", - "reference": "ddac737e1c06a310a0bb4b3da755a094a31a916a", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf", + "reference": "d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf", "shasum": "" }, "require": { @@ -3287,7 +3296,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2016-08-17 00:17:27" + "time": "2016-09-07 06:48:24" }, { "name": "lusitanian/oauth", @@ -4320,16 +4329,16 @@ }, { "name": "symfony/config", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4" + "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4275ef5b59f18959df0eee3991e9ca0cc208ffd4", - "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4", + "url": "https://api.github.com/repos/symfony/config/zipball/005bf10c156335ede2e89fb9a9ee10a0b742bc84", + "reference": "005bf10c156335ede2e89fb9a9ee10a0b742bc84", "shasum": "" }, "require": { @@ -4369,20 +4378,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-07-26 08:02:44" + "time": "2016-08-16 14:56:08" }, { "name": "symfony/dependency-injection", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12" + "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f2b5a00d176f6a201dc430375c0ef37706ea3d12", - "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0a732a9cafc30e54077967da4d019e1d618a8cb9", + "reference": "0a732a9cafc30e54077967da4d019e1d618a8cb9", "shasum": "" }, "require": { @@ -4432,11 +4441,11 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:20:35" + "time": "2016-09-06 23:19:39" }, { "name": "symfony/stopwatch", - "version": "v3.1.3", + "version": "v3.1.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -4485,16 +4494,16 @@ }, { "name": "symfony/yaml", - "version": "v2.8.9", + "version": "v2.8.11", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d" + "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0ceab136f43ed9d3e97b3eea32a7855dc50c121d", - "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e7540734bad981fe59f8ef14b6fc194ae9df8d9c", + "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c", "shasum": "" }, "require": { @@ -4530,7 +4539,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-07-17 09:06:15" + "time": "2016-09-02 01:57:56" }, { "name": "theseer/fdomdocument", diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/ListCompare.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/ListCompare.php index 546b055b0045b29d6cfe216b1b0efdc7407ebc0a..4de51f3e2ca9b8d5089cb6818d380f0ac9465e46 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/ListCompare.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/ListCompare.php @@ -86,6 +86,13 @@ class ListCompare extends Block */ protected $messageBlock = '#messages'; + /** + * Selector for confirm. + * + * @var string + */ + protected $confirmModal = '.confirm._show[data-role=modal]'; + /** * Get product info. * @@ -189,6 +196,13 @@ class ListCompare extends Block public function removeProduct($index = 1) { $this->_rootElement->find(sprintf($this->removeButton, $index), Locator::SELECTOR_XPATH)->click(); + $modalElement = $this->browser->find($this->confirmModal); + /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ + $modal = $this->blockFactory->create( + \Magento\Ui\Test\Block\Adminhtml\Modal::class, + ['element' => $modalElement] + ); + $modal->acceptAlert(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php index 596dbd38664b3b097302e6f6f0e62d13fbe96017..ab65865af6534c2b2478490b7f08fd7f108496fe 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php @@ -32,6 +32,13 @@ class Sidebar extends ListCompare */ protected $clearAll = '#compare-clear-all'; + /** + * Selector for confirm. + * + * @var string + */ + protected $confirmModal = '.confirm._show[data-role=modal]'; + /** * Get compare products block content. * @@ -79,5 +86,12 @@ class Sidebar extends ListCompare } ); $this->_rootElement->find($this->clearAll)->click(); + $modalElement = $this->browser->find($this->confirmModal); + /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ + $modal = $this->blockFactory->create( + \Magento\Ui\Test\Block\Adminhtml\Modal::class, + ['element' => $modalElement] + ); + $modal->acceptAlert(); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml index 0b3452cc147824b89443c33ca86d29cbebcb7ae7..9ae1e2ebfacca405f8505496f546cf2182e2dd3f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml @@ -23,5 +23,16 @@ <item name="value" xsi:type="number">0</item> </field> </dataset> + <dataset name="empty_product_mask_sku"> + <field name="catalog/fields_masks/sku" xsi:type="array"> + <item name="value" xsi:type="string"/> + </field> + </dataset> + <dataset name="empty_product_mask_sku_rollback"> + <field name="catalog/fields_masks/sku" xsi:type="array"> + <item name="value" xsi:type="string">{{name}}</item> + <item name="inherit" xsi:type="number">1</item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml index e46ad32551e7496f8ffb443543612567304ce5ee..77d4ee802e1373570a77f5e136c18c5ba393ae4d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.xml @@ -461,5 +461,22 @@ <data name="product/data/country_of_manufacture" xsi:type="string">Antarctica</data> <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" /> </variation> + <variation name="CreateSimpleProductEntityWithEmptySkuMaskTest1" summary="Create Simple Product Entity With Empty Sku Mask" ticketId="MAGETWO-58951"> + <data name="configData" xsi:type="string">empty_product_mask_sku</data> + <data name="description" xsi:type="string">Create product with custom options(fixed price)</data> + <data name="product/data/url_key" xsi:type="string">simple-product-%isolation%</data> + <data name="product/data/name" xsi:type="string">Simple Product %isolation%</data> + <data name="product/data/sku" xsi:type="string">simple_sku_%isolation%</data> + <data name="product/data/price/value" xsi:type="string">10000</data> + <data name="product/data/weight" xsi:type="string">50</data> + <data name="product/data/quantity_and_stock_status/qty" xsi:type="string">657</data> + <data name="product/data/checkout_data/dataset" xsi:type="string">simple_drop_down_with_one_option_fixed_price</data> + <data name="product/data/price/dataset" xsi:type="string">drop_down_with_one_option_fixed_price</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductInGrid" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductInCategory" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductPage" /> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductInCart" /> + </variation> </testCase> </config> diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml index 58435b066261ed28cc7f33ff01fc250940b6eb17..da44fd2eaf99e55e925d9c946b6d7e8ee8370408 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml @@ -110,7 +110,7 @@ <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertConfigurableProductPage" /> </variation> <variation name="CreateConfigurableProductEntityTestVariation6" summary="Create Configurable Product with Creating New Category and New Attribute (Required Fields Only)" ticketId="MAGETWO-13361"> - <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test, stable:no</data> <data name="product/data/configurable_attributes_data/dataset" xsi:type="string">two_searchable_options</data> <data name="product/data/name" xsi:type="string">Configurable Product %isolation%</data> <data name="product/data/sku" xsi:type="string">configurable_sku_%isolation%</data> diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php new file mode 100644 index 0000000000000000000000000000000000000000..2b1d9bdcf2df8fdb32869731b7b3af05d47bc417 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Payment\Test\Constraint; + +use Magento\Mtf\Constraint\AbstractConstraint; +use Magento\Payment\Test\Repository\CreditCardAdmin; +use Magento\Sales\Test\Page\Adminhtml\OrderCreateIndex; + +/** + * Class AssertCardRequiredFields + * + * Assert that fields are active. + */ +class AssertCardRequiredFields extends AbstractConstraint +{ + /** + * Expected required field message. + */ + const REQUIRE_MESSAGE = 'This is a required field.'; + + /** + * Expected required valid number message. + */ + const VALID_NUMBER_MESSAGE = 'Please enter a valid number in this field.'; + + /** + * Assert required fields on credit card payment method in backend. + * @param OrderCreateIndex $orderCreateIndex + * @param CreditCardAdmin $creditCard + * @return void + */ + public function processAssert(OrderCreateIndex $orderCreateIndex, CreditCardAdmin $creditCard) + { + $actualRequiredFields = $orderCreateIndex->getCreateBlock()->getBillingMethodBlock() + ->getJsErrors(); + $creditCardEmpty = $creditCard->get('visa_empty'); + foreach (array_keys($creditCardEmpty) as $field) { + \PHPUnit_Framework_Assert::assertTrue( + isset($actualRequiredFields[$field]), + "Field '$field' is not highlighted with an JS error." + ); + $expected = self::REQUIRE_MESSAGE; + if (in_array($field, ['cc_number', 'cc_cid'])) { + $expected = self::VALID_NUMBER_MESSAGE; + } + \PHPUnit_Framework_Assert::assertEquals( + $expected, + $actualRequiredFields[$field], + "Field '$field' is not highlighted as required." + ); + } + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'All required fields on customer form are highlighted.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml index 1109b70eec7cc14dd343e06fb21c8d8f0eb9c52b..371c8f350c6af028ddc544c23142f2886d699dbd 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml @@ -22,5 +22,11 @@ <field name="cc_exp_year" xsi:type="string">2020</field> <field name="cc_cid" xsi:type="string">123</field> </dataset> + <dataset name="visa_empty"> + <field name="cc_type" xsi:type="string">Please Select</field> + <field name="cc_number" xsi:type="string" /> + <field name="cc_exp_month" xsi:type="string">Month</field> + <field name="cc_cid" xsi:type="string" /> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.php new file mode 100644 index 0000000000000000000000000000000000000000..d4ec11acd51bf53c38de3be6e927b8a24037c1d8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Paypal\Test\TestCase; + +use Magento\Mtf\TestCase\Scenario; + +/** + * Preconditions: + * 1. Create customer. + * 2. Create product. + * + * Steps: + * 1. Open Backend. + * 2. Open Sales -> Orders. + * 3. Click Create New Order. + * 4. Select Customer created in preconditions. + * 5. Add Product. + * 6. Fill data according dataset. + * 7. Click Update Product qty. + * 8. Fill data according dataset. + * 9. Click Get Shipping Method and rates. + * 10. Fill data according dataset. + * 11. Select payment method Credit Card (PayFlow Pro) + * 12. Leave empty required fields for credit card + * 13. Click Submit order button + * + * @group PayPal + * @ZephyrId MAGETWO-58934 + */ +class CreatePayFlowOrderBackendNegativeTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + /* end tags */ + + /** + * Runs sales order on backend. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..04b34813e59ceacd332657d66366d2789f469e71 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Paypal\Test\TestCase\CreatePayFlowOrderBackendNegativeTest" summary="Verify required fields validation for PayPal Payflow Pro credit card on admin order creation" ticketId="MAGETWO-58934"> + <variation name="CreatePayFlowOrderBackendNegativeTestPayflowProVariation1" summary="Verify required fields validation for credit card on admin order creation" ticketId="MAGETWO-58934"> + <data name="tag" xsi:type="string">test_type:3rd_party_test</data> + <data name="products/0" xsi:type="string">catalogProductSimple::product_10_dollar</data> + <data name="customer/dataset" xsi:type="string">default</data> + <data name="billingAddress/dataset" xsi:type="string">US_address_1_without_email</data> + <data name="saveAddress" xsi:type="string">No</data> + <data name="shipping/shipping_service" xsi:type="string">Flat Rate</data> + <data name="shipping/shipping_method" xsi:type="string">Fixed</data> + <data name="prices" xsi:type="array"> + <item name="grandTotal" xsi:type="string">15.00</item> + </data> + <data name="payment/method" xsi:type="string">payflowpro</data> + <data name="creditCardClass" xsi:type="string">credit_card_admin</data> + <data name="creditCard/dataset" xsi:type="string">visa_empty</data> + <data name="creditCardSave" xsi:type="string">Yes</data> + <data name="configData" xsi:type="string">payflowpro, payflowpro_use_vault</data> + <constraint name="Magento\Payment\Test\Constraint\AssertCardRequiredFields" /> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml index f361530def8617d5e4d13451b24e329d31794ef2..53f10b10d38b6329a9b5119088e89443fb85105c 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml @@ -69,4 +69,19 @@ <step name="checkPayflowProConfig" module="Magento_Paypal" next="checkPayflowLinkConfig" /> <step name="checkPayflowLinkConfig" module="Magento_Paypal" /> </scenario> + <scenario name="CreatePayFlowOrderBackendNegativeTest" firstStep="setupConfiguration"> + <step name="setupConfiguration" module="Magento_Config" next="createProducts" /> + <step name="createProducts" module="Magento_Catalog" next="createCustomer" /> + <step name="createCustomer" module="Magento_Customer" next="openSalesOrders" /> + <step name="openSalesOrders" module="Magento_Sales" next="createNewOrder" /> + <step name="createNewOrder" module="Magento_Sales" next="selectCustomerOrder" /> + <step name="selectCustomerOrder" module="Magento_Sales" next="selectStore" /> + <step name="selectStore" module="Magento_Sales" next="addProducts" /> + <step name="addProducts" module="Magento_Sales" next="fillAccountInformation" /> + <step name="fillAccountInformation" module="Magento_Sales" next="fillBillingAddress" /> + <step name="fillBillingAddress" module="Magento_Sales" next="selectShippingMethodForOrder" /> + <step name="selectShippingMethodForOrder" module="Magento_Sales" next="saveCreditCardOnBackend" /> + <step name="saveCreditCardOnBackend" module="Magento_Vault" next="submitOrderNegative" /> + <step name="submitOrderNegative" module="Magento_Sales" /> + </scenario> </config> diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php index 874fe2844c476cd530b682143b3099c41646e28d..ae6631eff9a24c9f323bee5bdc91b99dc355972b 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php @@ -165,7 +165,7 @@ class Create extends Block * * @return \Magento\Sales\Test\Block\Adminhtml\Order\Create\Billing\Method */ - protected function getBillingMethodBlock() + public function getBillingMethodBlock() { return $this->blockFactory->create( \Magento\Sales\Test\Block\Adminhtml\Order\Create\Billing\Method::class, diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php index 280211c7ef20f54e43f31227551a2b832d7c1ea6..8477af0087fd47e07b8fee3e6c5138c690369d05 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php @@ -8,6 +8,7 @@ namespace Magento\Sales\Test\Block\Adminhtml\Order\Create\Billing; use Magento\Mtf\Block\Block; use Magento\Mtf\Fixture\InjectableFixture; +use Magento\Mtf\Client\Locator; /** * Adminhtml sales order create payment method block. @@ -42,6 +43,20 @@ class Method extends Block */ protected $loader = '[data-role=loader]'; + /** + * Field with Mage error. + * + * @var string + */ + protected $mageErrorField = '//fieldset/*[contains(@class,"field ")][.//*[contains(@class,"error")]]'; + + /** + * Mage error text. + * + * @var string + */ + protected $mageErrorText = './/label[contains(@class,"error")]'; + /** * Select payment method. * @@ -69,4 +84,23 @@ class Method extends Block $formBlock->fill($creditCard); } } + + /** + * @return array + */ + public function getJsErrors() + { + $data = []; + $elements = $this->_rootElement->getElements($this->mageErrorField, Locator::SELECTOR_XPATH); + foreach ($elements as $element) { + $error = $element->find($this->mageErrorText, Locator::SELECTOR_XPATH); + if ($error->isVisible()) { + $label = $element->find('.//*[contains(@name,"payment")]', Locator::SELECTOR_XPATH); + $label = $label->getAttribute('name'); + $label = preg_replace('/payment\[(.*)\]/u', '$1', $label); + $data[$label] = $error->getText(); + } + } + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SubmitOrderNegativeStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SubmitOrderNegativeStep.php new file mode 100644 index 0000000000000000000000000000000000000000..ece554eee9c9c32fdc94c74c48589e804aa9090f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SubmitOrderNegativeStep.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Sales\Test\TestStep; + +use Magento\Sales\Test\Page\Adminhtml\OrderCreateIndex; +use Magento\Mtf\TestStep\TestStepInterface; + +/** + * Submit Order step. + */ +class SubmitOrderNegativeStep implements TestStepInterface +{ + /** + * Sales order create index page. + * + * @var OrderCreateIndex + */ + protected $orderCreateIndex; + + /** + * @constructor + * @param OrderCreateIndex $orderCreateIndex + */ + public function __construct( + OrderCreateIndex $orderCreateIndex + ) { + $this->orderCreateIndex = $orderCreateIndex; + } + + /** + * Fill Sales Data. + * + * @return void + */ + public function run() + { + $this->orderCreateIndex->getCreateBlock()->submitOrder(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php index f610ee5e15473c89cc2f4fe4f6f3cc9e92a48eac..3c27a65c4a74385f546c108c077c128ebb4edcfb 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php @@ -476,13 +476,24 @@ class ProductTest extends \PHPUnit_Framework_TestCase } /** - * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_options.php * @magentoAppIsolation enabled */ public function testGetOptions() { - $this->_model = $this->productRepository->get('simple'); - - $this->assertEquals(4, count($this->_model->getOptions())); + $this->_model = $this->productRepository->get('simple_with_custom_options'); + $options = $this->_model->getOptions(); + $this->assertNotEmpty($options); + $expectedValue = [ + '3-1-select' => 3000.00, + '3-2-select' => 5000.00, + '4-1-radio' => 600.234, + '4-2-radio' => 40000.00 + ]; + foreach ($options as $option) { + foreach ($option->getValues() as $value) { + $this->assertEquals($expectedValue[$value->getSku()], floatval($value->getPrice())); + } + } } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php new file mode 100644 index 0000000000000000000000000000000000000000..0366e90cd9772036315678f6e3b10d1f59b615fb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +\Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize(); + +/** @var \Magento\TestFramework\ObjectManager $objectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */ +$categoryLinkManagement = $objectManager->create(\Magento\Catalog\Api\CategoryLinkManagementInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('simple_with_custom_options') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with <b>html tag</b>') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + )->setCanSaveCustomOptions(true) + ->setHasOptions(true); + +$oldOptions = [ + [ + 'previous_group' => 'select', + 'title' => 'Test Select', + 'type' => 'drop_down', + 'is_require' => 1, + 'sort_order' => 0, + 'values' => [ + [ + 'option_type_id' => -1, + 'title' => 'Option 1', + 'price' => '3,000.00', + 'price_type' => 'fixed', + 'sku' => '3-1-select', + ], + [ + 'option_type_id' => -1, + 'title' => 'Option 2', + 'price' => '5,000.00', + 'price_type' => 'fixed', + 'sku' => '3-2-select', + ], + ] + ], + [ + 'previous_group' => 'select', + 'title' => 'Test Radio', + 'type' => 'radio', + 'is_require' => 1, + 'sort_order' => 0, + 'values' => [ + [ + 'option_type_id' => -1, + 'title' => 'Option 1', + 'price' => '600.234', + 'price_type' => 'fixed', + 'sku' => '4-1-radio', + ], + [ + 'option_type_id' => -1, + 'title' => 'Option 2', + 'price' => '40,000.00', + 'price_type' => 'fixed', + 'sku' => '4-2-radio', + ], + ] + ] +]; + +$options = []; + +/** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory $customOptionFactory */ +$customOptionFactory = $objectManager->create(\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory::class); + +foreach ($oldOptions as $option) { + /** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterface $option */ + $option = $customOptionFactory->create(['data' => $option]); + $option->setProductSku($product->getSku()); + + $options[] = $option; +} + +$product->setOptions($options); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepositoryFactory */ +$productRepositoryFactory = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$productRepositoryFactory->save($product); + +$categoryLinkManagement->assignProductToCategories( + $product->getSku(), + [2] +); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options_rollback.php new file mode 100644 index 0000000000000000000000000000000000000000..88e0fb198576060eb8295e633a985d9d6e3ff96a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options_rollback.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\Framework\Exception\NoSuchEntityException; + +\Magento\TestFramework\Helper\Bootstrap::getInstance()->getInstance()->reinitialize(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); +try { + $product = $productRepository->get('simple_with_custom_options', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates.php b/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates.php new file mode 100644 index 0000000000000000000000000000000000000000..5cac40809565e1ed28df9529446550975b39f9f3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$resource = $objectManager->get(\Magento\Framework\App\ResourceConnection::class); +$connection = $resource->getConnection(); +$resourceModel = $objectManager->create(\Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate::class); +$entityTable = $resourceModel->getTable('shipping_tablerate'); +$data = + [ + 'website_id' => 1, + 'dest_country_id' => 'US', + 'dest_region_id' => 0, + 'dest_zip' => '*', + 'condition_name' => 'package_qty', + 'condition_value' => 1, + 'price' => 10, + 'cost' => 10 + ]; +$connection->query( + "INSERT INTO {$entityTable} (`website_id`, `dest_country_id`, `dest_region_id`, `dest_zip`, `condition_name`," + . "`condition_value`, `price`, `cost`) VALUES (:website_id, :dest_country_id, :dest_region_id, :dest_zip," + . " :condition_name, :condition_value, :price, :cost);", + $data +); diff --git a/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates_rollback.php b/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates_rollback.php new file mode 100644 index 0000000000000000000000000000000000000000..10f5563eee8aae9c826a8967e93658b59d9c2eca --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates_rollback.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$resource = $objectManager->get(\Magento\Framework\App\ResourceConnection::class); +$connection = $resource->getConnection(); +$resourceModel = $objectManager->create(\Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate::class); +$entityTable = $resourceModel->getTable('shipping_tablerate'); +$connection->query("DELETE FROM {$entityTable};"); diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7ed966d0c9b998a23145bde4f2432019628a3c6f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php @@ -0,0 +1,95 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Quote\Model; + +/** + * Class ShippingMethodManagementTest + */ +class ShippingMethodManagementTest extends \PHPUnit_Framework_TestCase +{ + + /** + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @magentoConfigFixture current_store carriers/tablerate/active 1 + * @magentoConfigFixture current_store carriers/tablerate/condition_name package_qty + * @magentoDataFixture Magento/SalesRule/_files/cart_rule_free_shipping.php + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/OfflineShipping/_files/tablerates.php + */ + public function testEstimateByAddressWithCartPriceRule() + { + $this->executeTestFlow(0, 0); + } + + /** + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @magentoConfigFixture current_store carriers/tablerate/active 1 + * @magentoConfigFixture current_store carriers/tablerate/condition_name package_qty + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/OfflineShipping/_files/tablerates.php + */ + public function testEstimateByAddress() + { + $this->executeTestFlow(5, 10); + } + + /** + * Provide testing of shipping method estimation based on address + * + * @param int $flatRateAmount + * @param int $tableRateAmount + */ + private function executeTestFlow($flatRateAmount, $tableRateAmount) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $objectManager->get(\Magento\Quote\Model\Quote::class); + $quote->load('test01', 'reserved_order_id'); + $cartId = $quote->getId(); + if (!$cartId) { + $this->fail('quote fixture failed'); + } + /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ + $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + ->create(); + $quoteIdMask->load($cartId, 'quote_id'); + //Use masked cart Id + $cartId = $quoteIdMask->getMaskedId(); + $data = [ + 'data' => [ + 'country_id' => "US", + 'postcode' => null, + 'region' => null, + 'region_id' => null + ] + ]; + /** @var \Magento\Quote\Api\Data\EstimateAddressInterface $address */ + $address = $objectManager->create(\Magento\Quote\Api\Data\EstimateAddressInterface::class, $data); + /** @var \Magento\Quote\Api\GuestShippingMethodManagementInterface $shippingEstimation */ + $shippingEstimation = $objectManager->get(\Magento\Quote\Api\GuestShippingMethodManagementInterface::class); + $result = $shippingEstimation->estimateByAddress($cartId, $address); + $this->assertNotEmpty($result); + $expectedResult = [ + 'tablerate' => + [ + 'method_code' => 'bestway', + 'amount' => $tableRateAmount + ], + 'flatrate' => [ + 'method_code' => 'flatrate', + 'amount' => $flatRateAmount + ] + ]; + foreach ($result as $rate) { + $this->assertEquals($expectedResult[$rate->getCarrierCode()]['amount'], $rate->getAmount()); + $this->assertEquals($expectedResult[$rate->getCarrierCode()]['method_code'], $rate->getMethodCode()); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php index 358786901713b987d897e2147a6f574a590fc832..b47d45e3815e7c55334ca24ef73788a929497506 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php @@ -27,6 +27,14 @@ class FixtureModelTest extends \Magento\TestFramework\Indexer\TestCase public static function setUpBeforeClass() { + $db = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getBootstrap() + ->getApplication() + ->getDbInstance(); + if (!$db->isDbDumpExists()) { + throw new \LogicException('DB dump does not exist.'); + } + $db->restoreFromDbDump(); + self::$_generatorWorkingDir = realpath(__DIR__ . '/../../../../../../../setup/src/Magento/Setup/Fixtures'); copy( self::$_generatorWorkingDir . '/tax_rates.csv', @@ -72,38 +80,4 @@ class FixtureModelTest extends \Magento\TestFramework\Indexer\TestCase ] ); } - - /** - * Apply fixture file - * - * @param string $fixtureFilename - */ - public function applyFixture($fixtureFilename) - { - require $fixtureFilename; - } - - /** - * Get object manager - * - * @return \Magento\Framework\ObjectManagerInterface - */ - public function getObjectManager() - { - if (!$this->_objectManager) { - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - } - return $this->_objectManager; - } - - /** - * Reset object manager - * - * @return \Magento\Framework\ObjectManagerInterface - */ - public function resetObjectManager() - { - $this->_objectManager = null; - return $this; - } } diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt index 77cf93864b0bd4e172da599e9ad854c7b14a5b0a..29b5280ec6693f70c8d65a1f40e25c644897ace1 100644 --- a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt @@ -41,13 +41,11 @@ app/code/Magento/Catalog/view/base/web/js/price-utils.js app/code/Magento/Catalog/view/base/web/js/tier-price.js app/code/Magento/Catalog/view/frontend/requirejs-config.js app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js -app/code/Magento/Catalog/view/frontend/web/js/compare.js app/code/Magento/Catalog/view/frontend/web/js/gallery.js app/code/Magento/Catalog/view/frontend/web/js/list.js app/code/Magento/Catalog/view/frontend/web/js/product/list/toolbar.js app/code/Magento/Catalog/view/frontend/web/js/related-products.js app/code/Magento/Catalog/view/frontend/web/js/upsell-products.js -app/code/Magento/Catalog/view/frontend/web/js/view/compare-products.js app/code/Magento/Catalog/view/frontend/web/js/view/image.js app/code/Magento/Catalog/view/frontend/web/js/zoom.js app/code/Magento/Catalog/view/frontend/web/product/view/validation.js @@ -218,16 +216,16 @@ app/code/Magento/PageCache/view/frontend/web/js/page-cache.js app/code/Magento/Payment/view/adminhtml/web/transparent.js app/code/Magento/Payment/view/frontend/requirejs-config.js app/code/Magento/Payment/view/frontend/web/cc-type.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js -app/code/Magento/Payment/view/frontend/web/js/model/credit-card-validation/validator.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-data.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/cvv-validator.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js +app/code/Magento/Payment/view/base/web/js/model/credit-card-validation/validator.js app/code/Magento/Payment/view/frontend/web/js/view/payment/cc-form.js app/code/Magento/Payment/view/frontend/web/js/view/payment/iframe.js app/code/Magento/Payment/view/frontend/web/js/view/payment/method-renderer/free-method.js @@ -511,7 +509,6 @@ lib/web/mage/captcha.js lib/web/mage/collapsible.js lib/web/mage/common.js lib/web/mage/cookies.js -lib/web/mage/dataPost.js lib/web/mage/decorate.js lib/web/mage/deletable-item.js lib/web/mage/dialog.js @@ -603,13 +600,11 @@ vendor/magento/module-catalog/view/base/web/js/price-utils.js vendor/magento/module-catalog/view/base/web/js/tier-price.js vendor/magento/module-catalog/view/frontend/requirejs-config.js vendor/magento/module-catalog/view/frontend/web/js/catalog-add-to-cart.js -vendor/magento/module-catalog/view/frontend/web/js/compare.js vendor/magento/module-catalog/view/frontend/web/js/gallery.js vendor/magento/module-catalog/view/frontend/web/js/list.js vendor/magento/module-catalog/view/frontend/web/js/product/list/toolbar.js vendor/magento/module-catalog/view/frontend/web/js/related-products.js vendor/magento/module-catalog/view/frontend/web/js/upsell-products.js -vendor/magento/module-catalog/view/frontend/web/js/view/compare-products.js vendor/magento/module-catalog/view/frontend/web/js/view/image.js vendor/magento/module-catalog/view/frontend/web/js/zoom.js vendor/magento/module-catalog/view/frontend/web/product/view/validation.js @@ -776,16 +771,16 @@ vendor/magento/module-page-cache/view/frontend/web/js/page-cache.js vendor/magento/module-payment/view/adminhtml/web/transparent.js vendor/magento/module-payment/view/frontend/requirejs-config.js vendor/magento/module-payment/view/frontend/web/cc-type.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/credit-card-data.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/cvv-validator.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js -vendor/magento/module-payment/view/frontend/web/js/model/credit-card-validation/validator.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/credit-card-data.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/credit-card-type.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/credit-card-number-validator/luhn10-validator.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/cvv-validator.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/expiration-date-validator.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-month-validator.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/expiration-year-validator.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/expiration-date-validator/parse-date.js +vendor/magento/module-payment/view/base/web/js/model/credit-card-validation/validator.js vendor/magento/module-payment/view/frontend/web/js/view/payment/cc-form.js vendor/magento/module-payment/view/frontend/web/js/view/payment/iframe.js vendor/magento/module-payment/view/frontend/web/js/view/payment/method-renderer/free-method.js diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/CopyrightTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/CopyrightTest.php index 582a63ceb19ed8dbb079fdc19abb2358004d891a..a1ede987dac78a6f5de8a2519d481bb81490ac16 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/CopyrightTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/CopyrightTest.php @@ -27,7 +27,7 @@ class CopyrightTest extends \PHPUnit_Framework_TestCase public function copyrightDataProvider() { - $blackList = include __DIR__ . '/_files/copyright/blacklist.php'; + $blackList = $this->getFilesData('blacklist*.php'); $changedFiles = []; foreach (glob(__DIR__ . '/../_files/changed_files*') as $listFile) { @@ -56,4 +56,18 @@ class CopyrightTest extends \PHPUnit_Framework_TestCase ); return $changedFiles; } + + /** + * @param string $filePattern + * @return array + */ + protected function getFilesData($filePattern) + { + $result = []; + foreach (glob(__DIR__ . '/_files/copyright/' . $filePattern) as $file) { + $fileData = include $file; + $result = array_merge($result, $fileData); + } + return $result; + } } diff --git a/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntityLoad.php b/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntityLoad.php index 010cafdd2f7148156bd02b0f2c28db5e469c0f54..3de6bd8fbcdd55840c39d31bf449f1f3ae5c6486 100644 --- a/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntityLoad.php +++ b/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntityLoad.php @@ -32,6 +32,7 @@ class AfterEntityLoad implements ObserverInterface } $entity->getResource()->afterLoad($entity); $entity->afterLoad(); + $entity->setOrigData(); $entity->setHasDataChanges(false); } } diff --git a/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntityLoad.php b/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntityLoad.php new file mode 100644 index 0000000000000000000000000000000000000000..1d292a2e5b3f81516563336f11dbf195b93b64d1 --- /dev/null +++ b/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntityLoad.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\EntityManager\Observer; + +use Magento\Framework\Event\Observer; +use Magento\Framework\Model\AbstractModel; + +/** + * Class BeforeEntityLoad + */ +class BeforeEntityLoad +{ + /** + * Apply model before load operation + * + * @param Observer $observer + * @throws \Magento\Framework\Validator\Exception + * @return void + */ + public function execute(Observer $observer) + { + $identifier = $observer->getEvent()->getIdentifier(); + $entity = $observer->getEvent()->getEntity(); + if ($entity instanceof AbstractModel) { + $entity->beforeLoad($identifier); + } + } +} diff --git a/lib/internal/Magento/Framework/EntityManager/Operation/Read.php b/lib/internal/Magento/Framework/EntityManager/Operation/Read.php index 1cd988f53a0050aeaffa1e55b96270a2eb84ce2c..19a3912890db5af5f50cfab964e0c2ca0de572c4 100644 --- a/lib/internal/Magento/Framework/EntityManager/Operation/Read.php +++ b/lib/internal/Magento/Framework/EntityManager/Operation/Read.php @@ -5,7 +5,6 @@ */ namespace Magento\Framework\EntityManager\Operation; -use Magento\Framework\EntityManager\Operation\ReadInterface; use Magento\Framework\EntityManager\Operation\Read\ReadMain; use Magento\Framework\EntityManager\Operation\Read\ReadAttributes; use Magento\Framework\EntityManager\Operation\Read\ReadExtensions; @@ -13,7 +12,6 @@ use Magento\Framework\EntityManager\HydratorPool; use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\EntityManager\EventManager; use Magento\Framework\EntityManager\TypeResolver; -use Magento\Framework\App\ResourceConnection; /** * Class Read @@ -83,11 +81,7 @@ class Read implements ReadInterface } /** - * @param object $entity - * @param string $identifier - * @param array $arguments - * @return object - * @throws \Exception + * {@inheritDoc} */ public function execute($entity, $identifier, $arguments = []) { @@ -107,6 +101,7 @@ class Read implements ReadInterface 'load_before', [ 'identifier' => $identifier, + 'entity' => $entity, 'arguments' => $arguments ] ); diff --git a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php index befff770156178dd2324e42365b62ac52414c9e8..ecfb67320cb0d58decdf67de64d2058814f1eaf8 100644 --- a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php +++ b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php @@ -75,6 +75,11 @@ class PluginList extends Scoped implements InterceptionPluginList */ protected $_pluginInstances = []; + /** + * @var \Psr\Log\LoggerInterface + */ + private $logger; + /** * @param ReaderInterface $reader * @param ScopeInterface $configScope @@ -149,6 +154,7 @@ class PluginList extends Scoped implements InterceptionPluginList } $this->_inherited[$type] = null; if (is_array($plugins) && count($plugins)) { + $this->filterPlugins($plugins); uasort($plugins, [$this, '_sort']); $this->trimInstanceStartingBackslash($plugins); $this->_inherited[$type] = $plugins; @@ -348,4 +354,34 @@ class PluginList extends Scoped implements InterceptionPluginList } } } + + /** + * Remove from list not existing plugins + * + * @param array $plugins + * @return void + */ + private function filterPlugins(array &$plugins) + { + foreach ($plugins as $name => $plugin) { + if (empty($plugin['instance'])) { + unset($plugins[$name]); + $this->getLogger()->info("Reference to undeclared plugin with name '{$name}'."); + } + } + } + + /** + * Returns logger instance + * + * @deprecated + * @return \Psr\Log\LoggerInterface + */ + private function getLogger() + { + if ($this->logger === null) { + $this->logger = $this->_objectManager->get(\Psr\Log\LoggerInterface::class); + } + return $this->logger; + } } diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/PluginList/PluginListTest.php b/lib/internal/Magento/Framework/Interception/Test/Unit/PluginList/PluginListTest.php index 1291ae44bce6522bf61f1bdbc42c3089a09abd48..b3fe011a0a490727c0682f1863aa731622753264 100644 --- a/lib/internal/Magento/Framework/Interception/Test/Unit/PluginList/PluginListTest.php +++ b/lib/internal/Magento/Framework/Interception/Test/Unit/PluginList/PluginListTest.php @@ -60,7 +60,6 @@ class PluginListTest extends \PHPUnit_Framework_TestCase $omConfigMock->expects($this->any())->method('getOriginalInstanceType')->will($this->returnArgument(0)); $this->_objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); - $this->_objectManagerMock->expects($this->any())->method('get')->will($this->returnArgument(0)); $definitions = new \Magento\Framework\ObjectManager\Definition\Runtime(); @@ -80,6 +79,7 @@ class PluginListTest extends \PHPUnit_Framework_TestCase public function testGetPlugin() { + $this->_objectManagerMock->expects($this->any())->method('get')->will($this->returnArgument(0)); $this->_configScopeMock->expects($this->any())->method('getCurrentScope')->will($this->returnValue('backend')); $this->_model->getNext(\Magento\Framework\Interception\Test\Unit\Custom\Module\Model\Item::class, 'getName'); $this->_model->getNext( @@ -131,6 +131,7 @@ class PluginListTest extends \PHPUnit_Framework_TestCase */ public function testGetPlugins($expectedResult, $type, $method, $scopeCode, $code = '__self') { + $this->_objectManagerMock->expects($this->any())->method('get')->will($this->returnArgument(0)); $this->_configScopeMock->expects( $this->any() )->method( @@ -206,6 +207,7 @@ class PluginListTest extends \PHPUnit_Framework_TestCase */ public function testInheritPluginsWithNonExistingClass() { + $this->_objectManagerMock->expects($this->any())->method('get')->will($this->returnArgument(0)); $this->_configScopeMock->expects($this->any()) ->method('getCurrentScope') ->will($this->returnValue('frontend')); @@ -213,12 +215,34 @@ class PluginListTest extends \PHPUnit_Framework_TestCase $this->_model->getNext('SomeType', 'someMethod'); } + /** + * @covers \Magento\Framework\Interception\PluginList\PluginList::getNext + * @covers \Magento\Framework\Interception\PluginList\PluginList::_inheritPlugins + */ + public function testInheritPluginsWithNotExistingPlugin() + { + $loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class); + $this->_objectManagerMock->expects($this->once()) + ->method('get') + ->with(\Psr\Log\LoggerInterface::class) + ->willReturn($loggerMock); + $loggerMock->expects($this->once()) + ->method('info') + ->with("Reference to undeclared plugin with name 'simple_plugin'."); + $this->_configScopeMock->expects($this->any()) + ->method('getCurrentScope') + ->will($this->returnValue('frontend')); + + $this->assertNull($this->_model->getNext('typeWithoutInstance', 'someMethod')); + } + /** * @covers \Magento\Framework\Interception\PluginList\PluginList::getNext * @covers \Magento\Framework\Interception\PluginList\PluginList::_loadScopedData */ public function testLoadScopedDataCached() { + $this->_objectManagerMock->expects($this->any())->method('get')->will($this->returnArgument(0)); $this->_configScopeMock->expects($this->once()) ->method('getCurrentScope') ->will($this->returnValue('scope')); diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php b/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php index 832a5a67599da7f9dbfe46e2732324b536f267c8..87bbe0d35dd2561799cd5d2024347c8fb48c2b73 100644 --- a/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php +++ b/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php @@ -70,6 +70,11 @@ return [ 'instance' => 'NonExistingPluginClass', ], ], + ], + 'typeWithoutInstance' => [ + 'plugins' => [ + 'simple_plugin' => [], + ], ] ] ] diff --git a/lib/internal/Magento/Framework/Model/AbstractModel.php b/lib/internal/Magento/Framework/Model/AbstractModel.php index dbbb20021b9f4dcc03765aee89bdbd81339bac08..34536d47097796d18e1ff517f2fd1ad2a7317735 100644 --- a/lib/internal/Magento/Framework/Model/AbstractModel.php +++ b/lib/internal/Magento/Framework/Model/AbstractModel.php @@ -527,12 +527,7 @@ abstract class AbstractModel extends \Magento\Framework\DataObject */ public function load($modelId, $field = null) { - $this->_beforeLoad($modelId, $field); $this->_getResource()->load($this, $modelId, $field); - $this->_afterLoad(); - $this->setOrigData(); - $this->_hasDataChanges = false; - $this->updateStoredData(); return $this; } @@ -577,6 +572,18 @@ abstract class AbstractModel extends \Magento\Framework\DataObject return $this; } + /** + * Process operation before object load + * + * @param string $identifier + * @param string|null $field + * @return void + */ + public function beforeLoad($identifier, $field = null) + { + $this->_beforeLoad($identifier, $field); + } + /** * Object after load processing. Implemented as public interface for supporting objects after load in collections * @@ -584,7 +591,6 @@ abstract class AbstractModel extends \Magento\Framework\DataObject */ public function afterLoad() { - $this->getResource()->afterLoad($this); $this->_afterLoad(); $this->updateStoredData(); return $this; diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php index fc189473505abd258acb159f32ff9d2b77d44958..7febcb450f9720d9999f19704808df90ca69deea 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php @@ -332,6 +332,7 @@ abstract class AbstractDb extends AbstractResource */ public function load(\Magento\Framework\Model\AbstractModel $object, $value, $field = null) { + $object->beforeLoad($value, $field); if ($field === null) { $field = $this->getIdFieldName(); } @@ -348,7 +349,10 @@ abstract class AbstractDb extends AbstractResource $this->unserializeFields($object); $this->_afterLoad($object); - + $object->afterLoad(); + $object->setOrigData(); + $object->setHasDataChanges(false); + return $this; } diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php index 1dcb84d276840185af916c1bc6036cc4b1ea5071..0a2e6f2262173f244dc0dddf8c53fa44c9bf3558 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php @@ -269,29 +269,19 @@ class AbstractDbTest extends \PHPUnit_Framework_TestCase public function testLoad() { - $contextMock = $this->getMock(\Magento\Framework\Model\Context::class, [], [], '', false); - $registryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); - $abstractModelMock = $this->getMockForAbstractClass( - \Magento\Framework\Model\AbstractModel::class, - [$contextMock, $registryMock], - '', - false, - true, - true, - ['__wakeup'] - ); - - $value = 'some_value'; - $idFieldName = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, - '_idFieldName' - ); - $idFieldName->setAccessible(true); - $idFieldName->setValue($this->_model, 'field_value'); - + /** @var \Magento\Framework\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject $object */ + $object = $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) + ->disableOriginalConstructor() + ->getMock(); + $object->expects($this->once())->method('beforeLoad')->with('some_value', 'field_name'); + $object->expects($this->once())->method('afterLoad')->willReturnSelf(); + $object->expects($this->once())->method('setOrigData')->willReturnSelf(); + $object->expects($this->once())->method('setHasDataChanges')->with(false)->willReturnSelf(); + $result = $this->_model->load($object, 'some_value', 'field_name'); + $this->assertEquals($this->_model, $result); $this->assertInstanceOf( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, - $this->_model->load($abstractModelMock, $value, $idFieldName) + $result ); } @@ -497,7 +487,6 @@ class AbstractDbTest extends \PHPUnit_Framework_TestCase $idFieldNameReflection->setValue($this->_model, 'idFieldName'); $connectionMock->expects($this->any())->method('save')->with('tableName', 'idFieldName'); $connectionMock->expects($this->any())->method('quoteInto')->will($this->returnValue('idFieldName')); - $abstractModelMock->setIdFieldName('id'); $abstractModelMock->setData( [ diff --git a/lib/web/mage/dataPost.js b/lib/web/mage/dataPost.js index e1c297ffcef4b9a6a3d64806d5f93eb57e938644..2d47929f57213c338c5b121310c544b3876331ec 100644 --- a/lib/web/mage/dataPost.js +++ b/lib/web/mage/dataPost.js @@ -2,50 +2,88 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ -/*jshint browser:true jquery:true*/ -/*global confirm:true*/ + define([ - "jquery", - "mage/template", - "jquery/ui" -], function($,mageTemplate){ - + 'jquery', + 'mage/template', + 'Magento_Ui/js/modal/confirm', + 'jquery/ui' +], function ($, mageTemplate, uiConfirm) { + 'use strict'; + $.widget('mage.dataPost', { options: { - formTemplate: '<form action="<%- data.action %>" method="post">' - + '<% _.each(data.data, function(value, index) { %>' - + '<input name="<%- index %>" value="<%- value %>">' - + '<% }) %></form>', + formTemplate: '<form action="<%- data.action %>" method="post">' + + '<% _.each(data.data, function(value, index) { %>' + + '<input name="<%- index %>" value="<%- value %>">' + + '<% }) %></form>', postTrigger: ['a[data-post]', 'button[data-post]', 'span[data-post]'], formKeyInputSelector: 'input[name="form_key"]' }, - _create: function() { + + /** @inheritdoc */ + _create: function () { this._bind(); }, - _bind: function() { + + /** @inheritdoc */ + _bind: function () { var events = {}; - $.each(this.options.postTrigger, function(index, value) { + + $.each(this.options.postTrigger, function (index, value) { events['click ' + value] = '_postDataAction'; }); + this._on(events); }, - _postDataAction: function(e) { - e.preventDefault(); + + /** + * Handler for click. + * + * @param {Object} e + * @private + */ + _postDataAction: function (e) { var params = $(e.currentTarget).data('post'); + + e.preventDefault(); this.postData(params); }, - postData: function(params) { - var formKey = $(this.options.formKeyInputSelector).val(); + + /** + * Data post action. + * + * @param {Object} params + */ + postData: function (params) { + var formKey = $(this.options.formKeyInputSelector).val(), + $form; + if (formKey) { - params.data.form_key = formKey; + params.data['form_key'] = formKey; } - $(mageTemplate(this.options.formTemplate, { + + $form = $(mageTemplate(this.options.formTemplate, { data: params - })).appendTo('body').hide().submit(); + })); + + if (params.data.confirmation) { + uiConfirm({ + content: params.data.confirmationMessage, + actions: { + /** @inheritdoc */ + confirm: function () { + $form.appendTo('body').hide().submit(); + } + } + }); + } else { + $form.appendTo('body').hide().submit(); + } } }); - + $(document).dataPost(); return $.mage.dataPost; -}); \ No newline at end of file +}); diff --git a/setup/performance-toolkit/profiles/ce/attributeSets.xml b/setup/performance-toolkit/profiles/ce/attributeSets.xml new file mode 100644 index 0000000000000000000000000000000000000000..0db403e9969c079da00562f119233d24ea208a6b --- /dev/null +++ b/setup/performance-toolkit/profiles/ce/attributeSets.xml @@ -0,0 +1,132 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<attribute_sets> <!-- Content of Attribute Sets --> + <attribute_set> + <name>Attribute Set 1</name> + <attributes> + <attribute> + <is_required>1</is_required> + <is_visible_on_front>1</is_visible_on_front> + <is_visible_in_advanced_search>1</is_visible_in_advanced_search> + <attribute_code>mycolor</attribute_code> + <backend_type></backend_type> + <is_searchable>1</is_searchable> + <is_filterable>1</is_filterable> + <is_filterable_in_search>1</is_filterable_in_search> + <frontend_label>my color</frontend_label> + <frontend_input>select</frontend_input> + <default_value>my yellow</default_value> + <options> + <option> + <label>my green</label> + <value>my green</value> + </option> + <option> + <label>my red</label> + <value>my red</value> + </option> + <option> + <label>my yellow</label> + <value>my yellow</value> + </option> + </options> + </attribute> + <attribute> + <is_required>1</is_required> + <is_visible_on_front>1</is_visible_on_front> + <is_visible_in_advanced_search>1</is_visible_in_advanced_search> + <attribute_code>mysize</attribute_code> + <backend_type></backend_type> + <is_searchable>1</is_searchable> + <is_filterable>1</is_filterable> + <is_filterable_in_search>1</is_filterable_in_search> + <frontend_label>my size</frontend_label> + <frontend_input>select</frontend_input> + <default_value>my large</default_value> + <options> + <option> + <label>my small</label> + <value>my small</value> + </option> + <option> + <label>my medium</label> + <value>my medium</value> + </option> + <option> + <label>my large</label> + <value>my large</value> + </option> + </options> + </attribute> + </attributes> + </attribute_set> + <attribute_set> + <name>Attribute Set 2</name> + <attributes> + <attribute> + <is_required>1</is_required> + <is_visible_on_front>1</is_visible_on_front> + <is_visible_in_advanced_search>1</is_visible_in_advanced_search> + <attribute_code>attributeset2attribute1</attribute_code> + <backend_type></backend_type> + <is_searchable>1</is_searchable> + <is_filterable>1</is_filterable> + <is_filterable_in_search>1</is_filterable_in_search> + <frontend_label>Attribute Set 2 - Attribute 1</frontend_label> + <frontend_input>select</frontend_input> + <default_value>attributeset2attribute1option1</default_value> + <options> + <option> + <label>Attribute Set 2 - Attribute 1 - Option a</label> + <value>attributeset2attribute1option1</value> + </option> + <option> + <label>Attribute Set 2 - Attribute 1 - Option b</label> + <value>attributeset2attribute1option2</value> + </option> + <option> + <label>Attribute Set 2 - Attribute 1 - Option c</label> + <value>attributeset2attribute1option3</value> + </option> + </options> + </attribute> + </attributes> + </attribute_set> + <attribute_set> + <name>Attribute Set 3</name> + <attributes> + <attribute> + <is_required>1</is_required> + <is_visible_on_front>1</is_visible_on_front> + <is_visible_in_advanced_search>1</is_visible_in_advanced_search> + <attribute_code>attributeset3attribute1</attribute_code> + <backend_type></backend_type> + <is_searchable>1</is_searchable> + <is_filterable>1</is_filterable> + <is_filterable_in_search>1</is_filterable_in_search> + <frontend_label>Attribute Set 3 - Attribute 1</frontend_label> + <frontend_input>select</frontend_input> + <default_value>attributeset3attribute1option1</default_value> + <options> + <option> + <label>Attribute Set 3 - Attribute 1 - Option a</label> + <value>attributeset3attribute1option1</value> + </option> + <option> + <label>Attribute Set 3 - Attribute 1 - Option b</label> + <value>attributeset3attribute1option2</value> + </option> + <option> + <label>Attribute Set 3 - Attribute 1 - Option c</label> + <value>attributeset3attribute1option3</value> + </option> + </options> + </attribute> + </attributes> + </attribute_set> +</attribute_sets> \ No newline at end of file diff --git a/setup/performance-toolkit/profiles/ce/extra_large.xml b/setup/performance-toolkit/profiles/ce/extra_large.xml index 41561e54f787b417ec5be855e607a2436b1d0abe..c9bf96ad4f4cab4cb8a6c1aacbe6e89a673e842c 100644 --- a/setup/performance-toolkit/profiles/ce/extra_large.xml +++ b/setup/performance-toolkit/profiles/ce/extra_large.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<config> +<config xmlns:xi="http://www.w3.org/2001/XInclude"> <profile> <websites>5</websites> <!-- Number of websites to generate --> <store_groups>5</store_groups> <!--Number of stores--> @@ -68,5 +68,8 @@ <set_scheduled>true</set_scheduled> </indexer> </indexers> + <xi:include href="searchTerms.xml" /> + <xi:include href="searchConfig.xml" /> + <xi:include href="attributeSets.xml" /> </profile> </config> diff --git a/setup/performance-toolkit/profiles/ce/large.xml b/setup/performance-toolkit/profiles/ce/large.xml index ec521527a438406cf08b0211944347612bca5743..07e7ac33023b17d5d626986b76d84e88b3f7314b 100644 --- a/setup/performance-toolkit/profiles/ce/large.xml +++ b/setup/performance-toolkit/profiles/ce/large.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<config> +<config xmlns:xi="http://www.w3.org/2001/XInclude"> <profile> <websites>3</websites> <!-- Number of websites to generate --> <store_groups>3</store_groups> <!--Number of stores--> @@ -68,5 +68,8 @@ <set_scheduled>true</set_scheduled> </indexer> </indexers> + <xi:include href="searchTerms.xml" /> + <xi:include href="searchConfig.xml" /> + <xi:include href="attributeSets.xml" /> </profile> </config> diff --git a/setup/performance-toolkit/profiles/ce/medium.xml b/setup/performance-toolkit/profiles/ce/medium.xml index d2125b0586b1244553277c5cafdbe30e7bb5020a..6b1b289e823bab41a6d637350037b64c39e96935 100644 --- a/setup/performance-toolkit/profiles/ce/medium.xml +++ b/setup/performance-toolkit/profiles/ce/medium.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<config> +<config xmlns:xi="http://www.w3.org/2001/XInclude"> <profile> <websites>1</websites> <!-- Number of websites to generate --> <store_groups>2</store_groups> <!--Number of stores--> @@ -68,5 +68,8 @@ <set_scheduled>false</set_scheduled> </indexer> </indexers> + <xi:include href="searchTerms.xml" /> + <xi:include href="searchConfig.xml" /> + <xi:include href="attributeSets.xml" /> </profile> </config> diff --git a/setup/performance-toolkit/profiles/ce/searchConfig.xml b/setup/performance-toolkit/profiles/ce/searchConfig.xml new file mode 100644 index 0000000000000000000000000000000000000000..55c2caea2482c271af5cc2aa97e243fea9c6f6e3 --- /dev/null +++ b/setup/performance-toolkit/profiles/ce/searchConfig.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<search_config> <!-- Search configuration for Simple/Configurable products --> + <max_amount_of_words_description>200</max_amount_of_words_description> + <max_amount_of_words_short_description>20</max_amount_of_words_short_description> + <min_amount_of_words_description>20</min_amount_of_words_description> + <min_amount_of_words_short_description>5</min_amount_of_words_short_description> +</search_config> diff --git a/setup/performance-toolkit/profiles/ce/searchTerms.xml b/setup/performance-toolkit/profiles/ce/searchTerms.xml new file mode 100644 index 0000000000000000000000000000000000000000..b5713ac4644f661a586564827283c6b7c973b51e --- /dev/null +++ b/setup/performance-toolkit/profiles/ce/searchTerms.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<search_terms> <!-- Content of Search Terms --> + <search_term> + <term>iphone 6</term> + <count>50</count> + </search_term> + <search_term> + <term>galaxy s3</term> + <count>100</count> + </search_term> +</search_terms> \ No newline at end of file diff --git a/setup/performance-toolkit/profiles/ce/small.xml b/setup/performance-toolkit/profiles/ce/small.xml index d935a90299b6063d1b06d995647044c9d0a5b23d..4f9b436666f8c743c0fd0058c6fc747944506c9d 100644 --- a/setup/performance-toolkit/profiles/ce/small.xml +++ b/setup/performance-toolkit/profiles/ce/small.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<config> +<config xmlns:xi="http://www.w3.org/2001/XInclude"> <profile> <websites>1</websites> <!-- Number of websites to generate --> <store_groups>1</store_groups> <!--Number of stores--> @@ -68,5 +68,8 @@ <set_scheduled>false</set_scheduled> </indexer> </indexers> + <xi:include href="searchTerms.xml" /> + <xi:include href="searchConfig.xml" /> + <xi:include href="attributeSets.xml" /> </profile> </config> diff --git a/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php b/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php index d91a1633ef03848eb1a73a123b9e5f87d6f253d4..f70c36cec65dcd5fb868f12b7144fb46e58c3a7c 100644 --- a/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php +++ b/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php @@ -78,7 +78,12 @@ class GenerateFixturesCommand extends Command $output->writeln('<info>Generating profile with following params:</info>'); foreach ($fixtureModel->getParamLabels() as $configKey => $label) { - $output->writeln('<info> |- ' . $label . ': ' . $fixtureModel->getValue($configKey) . '</info>'); + $output->writeln( + '<info> |- ' . $label . ': ' . (is_array($fixtureModel->getValue($configKey)) === true + ? sizeof( + $fixtureModel->getValue($configKey)[array_keys($fixtureModel->getValue($configKey))[0]] + ) : $fixtureModel->getValue($configKey)) . '</info>' + ); } /** @var $config \Magento\Indexer\Model\Config */ diff --git a/setup/src/Magento/Setup/Fixtures/AttributeSetsFixture.php b/setup/src/Magento/Setup/Fixtures/AttributeSetsFixture.php new file mode 100644 index 0000000000000000000000000000000000000000..5617eca9a0e7e24694c151d508ed09a4cd547999 --- /dev/null +++ b/setup/src/Magento/Setup/Fixtures/AttributeSetsFixture.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Fixtures; + +/** + * Class AttributeSetFixture + */ +class AttributeSetsFixture extends Fixture +{ + /** + * @var int + */ + protected $priority = 25; + + /** + * {@inheritdoc} + */ + public function execute() + { + $attributeSets = $this->fixtureModel->getValue('attribute_sets', null); + if ($attributeSets === null) { + return; + } + $this->fixtureModel->resetObjectManager(); + /** @var \Magento\Catalog\Api\AttributeSetManagementInterface $attributeSetManagement */ + $attributeSetManagement = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\AttributeSetManagementInterface::class + ); + /** @var \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface $attributeGroupRepository */ + $attributeGroupRepository = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class + ); + + foreach ($attributeSets['attribute_set'] as $attributeSetData) { + //Create Attribute Set + /** @var \Magento\Eav\Api\Data\AttributeSetInterfaceFactory $attributeSetFactory */ + $attributeSetFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Eav\Api\Data\AttributeSetInterfaceFactory::class + ); + $attributeSet = $attributeSetFactory->create(); + $attributeSet->setAttributeSetName($attributeSetData['name']); + $attributeSet->setEntityTypeId(\Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE); + + $result = $attributeSetManagement->create($attributeSet, 4); + $attributeSetId = $result->getAttributeSetId(); + + //Create Attribute Group + /** @var \Magento\Eav\Api\Data\AttributeGroupInterfaceFactory $attributeGroupFactory */ + $attributeGroupFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Eav\Api\Data\AttributeGroupInterfaceFactory::class + ); + $attributeGroup = $attributeGroupFactory->create(); + $attributeGroup->setAttributeGroupName($result->getAttributeSetName() . ' - Group'); + $attributeGroup->setAttributeSetId($attributeSetId); + $attributeGroupRepository->save($attributeGroup); + $attributeGroupId = $attributeGroup->getAttributeGroupId(); + + /** @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository */ + $attributeRepository = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class + ); + /** @var \Magento\Catalog\Api\ProductAttributeManagementInterface $attributeManagementManagement */ + $attributeManagement = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\ProductAttributeManagementInterface::class + ); + + $attributesData = array_key_exists(0, $attributeSetData['attributes']['attribute']) + ? $attributeSetData['attributes']['attribute'] : [$attributeSetData['attributes']['attribute']]; + foreach ($attributesData as $attributeData) { + //Create Attribute + /** @var \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory $attributeFactory */ + $attributeFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory::class + ); + + $optionsData = array_key_exists(0, $attributeData['options']['option']) + ? $attributeData['options']['option'] : [$attributeData['options']['option']]; + $options = []; + foreach ($optionsData as $optionData) { + /** @var \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory */ + $optionFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory::class + ); + $option = $optionFactory->create(['data' => $optionData]); + $options[] = $option; + } + + $attribute = $attributeFactory->create(['data' => $attributeData]); + $attribute->setOptions($options); + + $result = $attributeRepository->save($attribute); + $attributeId = $result->getAttributeId(); + + //Associate Attribute to Attribute Set + $sortOrder = 3; + $attributeManagement->assign($attributeSetId, $attributeGroupId, $attributeId, $sortOrder); + } + } + } + + /** + * {@inheritdoc} + */ + public function getActionTitle() + { + return 'Generating attribute sets'; + } + + /** + * {@inheritdoc} + */ + public function introduceParamLabels() + { + return [ + 'attribute_sets' => 'Attribute Sets' + ]; + } +} diff --git a/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php b/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php index 5142efc2da6614cfd6253b02cf7a30b69fc07663..2340de71cf78363ed00fd9248577e7479b6dc012 100644 --- a/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php +++ b/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php @@ -6,19 +6,25 @@ namespace Magento\Setup\Fixtures; -use Magento\Setup\Model\Complex\Generator; +use Magento\Setup\Model\DataGenerator; use Magento\Setup\Model\Complex\Pattern; +use Magento\Setup\Model\Complex\Generator; /** * Class ConfigurableProductsFixture */ -class ConfigurableProductsFixture extends Fixture +class ConfigurableProductsFixture extends SimpleProductsFixture { /** * @var int */ protected $priority = 50; + /** + * @var array + */ + protected $searchConfig; + //@codingStandardsIgnoreStart /** * Get CSV template headers @@ -31,6 +37,7 @@ class ConfigurableProductsFixture extends Fixture 'sku', 'store_view_code', 'attribute_set_code', + 'additional_attributes', 'product_type', 'categories', 'product_websites', @@ -137,22 +144,38 @@ class ConfigurableProductsFixture extends Fixture } /** - * @param callable $productCategory - * @param callable $productWebsite - * @param string $variation + * @param Closure|mixed $productCategoryClosure + * @param Closure|mixed $productWebsiteClosure + * @param Closure|mixed $shortDescriptionClosure + * @param Closure|mixed $descriptionClosure + * @param Closure|mixed $priceClosure + * @param Closure|mixed $attributeSetClosure + * @param Closure|mixed $additionalAttributesClosure + * @param string $variationClosure * @param string $suffix * @return array * @SuppressWarnings(PHPMD) */ - private function generateConfigurableProduct($productCategory, $productWebsite, $variation, $suffix) + private function generateConfigurableProduct( + $productCategoryClosure, + $productWebsiteClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure, + $variationClosure, + $suffix + ) { return [ 'sku' => 'Configurable Product %s' . $suffix, 'store_view_code' => '', - 'attribute_set_code' => 'Default', + 'attribute_set_code' => $attributeSetClosure, + 'additional_attributes' => $additionalAttributesClosure, 'product_type' => 'configurable', - 'categories' => $productCategory, - 'product_websites' => $productWebsite, + 'categories' => $productCategoryClosure, + 'product_websites' => $productWebsiteClosure, 'color' => '', 'configurable_variation' => '', 'cost' => '', @@ -162,7 +185,7 @@ class ConfigurableProductsFixture extends Fixture 'custom_design_from' => '', 'custom_design_to' => '', 'custom_layout_update' => '', - 'description' => '<p>Configurable product description %s</p>', + 'description' => $descriptionClosure, 'enable_googlecheckout' => '1', 'gallery' => '', 'gift_message_available' => '', @@ -184,12 +207,12 @@ class ConfigurableProductsFixture extends Fixture 'news_to_date' => '', 'options_container' => 'Block after Info Column', 'page_layout' => '', - 'price' => '10', + 'price' => $priceClosure, 'quantity_and_stock_status' => 'In Stock', 'related_tgtr_position_behavior' => '', 'related_tgtr_position_limit' => '', 'required_options' => '1', - 'short_description' => '', + 'short_description' => $shortDescriptionClosure, 'small_image' => '', 'small_image_label' => '', 'special_from_date' => '', @@ -244,32 +267,51 @@ class ConfigurableProductsFixture extends Fixture '_media_label' => '', '_media_position' => '', '_media_is_disabled' => '', - 'configurable_variations' => $variation, + 'configurable_variations' => $variationClosure, ]; } /** * Get CSV template rows * - * @param Closure|mixed $productCategory - * @param Closure|mixed $productWebsite + * @param Closure|mixed $productCategoryClosure + * @param Closure|mixed $productWebsiteClosure + * @param Closure|mixed $shortDescriptionClosure + * @param Closure|mixed $descriptionClosure + * @param Closure|mixed $priceClosure + * @param Closure|mixed $attributeSetClosure + * @param Closure|mixed $additionalAttributesClosure + * @param Closure|mixed $variationClosure + * @param int $optionsNumber + * @param string $suffix * * @SuppressWarnings(PHPMD) * * @return array */ - protected function getRows($productCategory, $productWebsite, $optionsNumber, $suffix = '') + protected function getRows( + $productCategoryClosure, + $productWebsiteClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure, + $variationClosure, + $optionsNumber, + $suffix = '' + ) { $data = []; - $variation = []; for ($i = 1; $i <= $optionsNumber; $i++) { $productData = [ 'sku' => "Configurable Product %s-option {$i}{$suffix}", 'store_view_code' => '', - 'attribute_set_code' => 'Default', + 'attribute_set_code' => $attributeSetClosure, + 'additional_attributes' => $additionalAttributesClosure, 'product_type' => 'simple', - 'categories' => $productCategory, - 'product_websites' => $productWebsite, + 'categories' => $productCategoryClosure, + 'product_websites' => $productWebsiteClosure, 'color' => '', 'configurable_variation' => "option {$i}", 'cost' => '', @@ -279,7 +321,7 @@ class ConfigurableProductsFixture extends Fixture 'custom_design_from' => '', 'custom_design_to' => '', 'custom_layout_update' => '', - 'description' => '<p>Configurable product description %s</p>', + 'description' => $descriptionClosure, 'enable_googlecheckout' => '1', 'gallery' => '', 'gift_message_available' => '', @@ -301,12 +343,12 @@ class ConfigurableProductsFixture extends Fixture 'news_to_date' => '', 'options_container' => 'Block after Info Column', 'page_layout' => '', - 'price' => function () { return mt_rand(1, 1000) / 10; }, + 'price' => $priceClosure, 'quantity_and_stock_status' => 'In Stock', 'related_tgtr_position_behavior' => '', 'related_tgtr_position_limit' => '', 'required_options' => '0', - 'short_description' => '', + 'short_description' => $shortDescriptionClosure, 'small_image' => '', 'small_image_label' => '', 'special_from_date' => '', @@ -366,21 +408,18 @@ class ConfigurableProductsFixture extends Fixture '_media_position' => '', '_media_is_disabled' => '', ]; - - $variation[] = implode( - ',', - [ - 'sku=' . $productData['sku'], - 'configurable_variation=' . $productData['configurable_variation'], - ] - ); $data[] = $productData; } $data[] = $this->generateConfigurableProduct( - $productCategory, - $productWebsite, - implode('|', $variation), + $productCategoryClosure, + $productWebsiteClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure, + $variationClosure, $suffix ); return $data; @@ -388,26 +427,141 @@ class ConfigurableProductsFixture extends Fixture /** * {@inheritdoc} + * @SuppressWarnings(PHPMD) */ public function execute() { - $configurableCount = $this->fixtureModel->getValue('configurable_products', 0); - if (!$configurableCount) { + $configurableProductsCount = $this->fixtureModel->getValue('configurable_products', 0); + if (!$configurableProductsCount) { return; } - $this->fixtureModel->resetObjectManager(); + $simpleProductsCount = $this->fixtureModel->getValue('simple_products', 0); + $maxAmountOfWordsDescription = $this->getSearchConfigValue('max_amount_of_words_description'); + $maxAmountOfWordsShortDescription = $this->getSearchConfigValue('max_amount_of_words_short_description'); + $minAmountOfWordsDescription = $this->getSearchConfigValue('min_amount_of_words_description'); + $minAmountOfWordsShortDescription = $this->getSearchConfigValue('min_amount_of_words_short_description'); + $attributes = $this->getAttributes(); + $searchTerms = $this->getSearchTerms(); + $this->fixtureModel->resetObjectManager(); $result = $this->getCategoriesAndWebsites(); - + $variationCount = $this->fixtureModel->getValue('configurable_products_variation', 3); $result = array_values($result); + $dataGenerator = new DataGenerator(realpath(__DIR__ . '/' . 'dictionary.csv')); - $productWebsite = function ($index) use ($result) { + $productWebsiteClosure = function ($index) use ($result) { return $result[$index % count($result)][0]; }; - $productCategory = function ($index) use ($result) { + $productCategoryClosure = function ($index) use ($result) { return $result[$index % count($result)][2] . '/' . $result[$index % count($result)][1]; }; - + $shortDescriptionClosure = function ($index) + use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsShortDescription, + $minAmountOfWordsShortDescription + ) + { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + mt_srand($index); + return $dataGenerator->generate( + $minAmountOfWordsShortDescription, + $maxAmountOfWordsShortDescription, + 'shortDescription-' . $index + ) . ($index <= ($count * count($searchTerms)) ? ' ' + . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $descriptionClosure = function ($index) + use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsDescription, + $minAmountOfWordsDescription + ) + { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + mt_srand($index); + return $dataGenerator->generate( + $minAmountOfWordsDescription, + $maxAmountOfWordsDescription, + 'description-' . $index + ) . ($index <= ($count * count($searchTerms)) + ? ' ' . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $priceClosure = function($index) { + mt_srand($index); + switch (mt_rand(0,3)) { + case 0: return 9.99; + case 1: return 5; + case 2: return 1; + case 3: return mt_rand(1,10000)/10; + } + }; + $attributeSetClosure = function($index) use ($attributes, $result) { + mt_srand($index); + $attributeSet = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + return $attributeSet; + }; + $variationClosure = function($index, $variationIndex) use ($attributes, $result, $variationCount) { + mt_srand($index); + $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + $skus = []; + for ($i=1; $i <= $variationCount; $i++) { + $skus[] = 'sku=Configurable Product ' . $index . '-option ' . $i; + } + $values = []; + if ($attributeSetCode == 'Default') { + for ($i=1; $i <= $variationCount; $i++) { + $values[] = 'configurable_variation=option ' . $i; + } + } else { + for ($i=$variationCount; $i > 0; $i--) { + $attributeValues = ''; + foreach ($attributes[$attributeSetCode] as $attribute) { + $attributeValues = $attributeValues . $attribute['name'] . "=" . + $attribute['values'][($variationIndex - $i) % count($attribute['values'])] . ","; + } + $values [] = $attributeValues; + } + } + $variations = []; + for ($i=0; $i < $variationCount; $i++) { + $variations[] = trim(implode(",",[$skus[$i],$values[$i]]), ","); + } + return implode("|",$variations); + }; + $additionalAttributesClosure = function($index, $variationIndex) use ($attributes, $result) { + $attributeValues = ''; + mt_srand($index); + $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + if ($attributeSetCode !== 'Default' ) { + foreach ($attributes[$attributeSetCode] as $attribute) { + $attributeValues = $attributeValues . $attribute['name'] . "=" . + $attribute['values'][$variationIndex % count($attribute['values'])] . ","; + } + } + return trim($attributeValues, ","); + }; /** * Create configurable products */ @@ -415,9 +569,15 @@ class ConfigurableProductsFixture extends Fixture $pattern->setHeaders($this->getHeaders()); $pattern->setRowsSet( $this->getRows( - $productCategory, - $productWebsite, - $this->fixtureModel->getValue('configurable_products_variation', 3) + $productCategoryClosure, + $productWebsiteClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure, + $variationClosure, + $variationCount ) ); @@ -435,7 +595,7 @@ class ConfigurableProductsFixture extends Fixture $source = $this->fixtureModel->getObjectManager()->create( Generator::class, - ['rowPattern' => $pattern, 'count' => $configurableCount] + ['rowPattern' => $pattern, 'count' => $configurableProductsCount] ); // it is not obvious, but the validateSource() will actually save import queue data to DB if (!$import->validateSource($source)) { @@ -467,9 +627,10 @@ class ConfigurableProductsFixture extends Fixture } /** + * @override * @return array */ - private function getCategoriesAndWebsites() + protected function getCategoriesAndWebsites() { /** @var \Magento\Store\Model\StoreManager $storeManager */ $storeManager = $this->fixtureModel->getObjectManager()->get(\Magento\Store\Model\StoreManager::class); diff --git a/setup/src/Magento/Setup/Fixtures/FixtureModel.php b/setup/src/Magento/Setup/Fixtures/FixtureModel.php index 118b29cb4306bb6e05580eea3bc0da207a72835d..44173a32c3e771ec2c43480a73c380ad2a2691ab 100644 --- a/setup/src/Magento/Setup/Fixtures/FixtureModel.php +++ b/setup/src/Magento/Setup/Fixtures/FixtureModel.php @@ -206,7 +206,9 @@ class FixtureModel if (!is_readable($filename)) { throw new \Exception("Profile configuration file `{$filename}` is not readable or does not exists."); } - $this->config = $this->fileParser->load($filename)->xmlToArray(); + $this->fileParser->getDom()->load($filename); + $this->fileParser->getDom()->xinclude(); + $this->config = $this->fileParser->xmlToArray(); } /** diff --git a/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php b/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php index 6de4eaf91529fb3bc12cffe4d78aba238bc2fc05..fbb28d35269b177762410e8da7560612dd64db9c 100644 --- a/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php +++ b/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php @@ -6,6 +6,7 @@ namespace Magento\Setup\Fixtures; +use Magento\Setup\Model\DataGenerator; use Magento\Setup\Model\Generator; /** @@ -18,8 +19,14 @@ class SimpleProductsFixture extends Fixture */ protected $priority = 30; + /** + * @var array + */ + protected $searchConfig; + /** * {@inheritdoc} + * @SuppressWarnings(PHPMD) */ public function execute() { @@ -27,48 +34,16 @@ class SimpleProductsFixture extends Fixture if (!$simpleProductsCount) { return; } + $configurableProductsCount = $this->fixtureModel->getValue('configurable_products', 0); + $maxAmountOfWordsDescription = $this->getSearchConfigValue('max_amount_of_words_description'); + $maxAmountOfWordsShortDescription = $this->getSearchConfigValue('max_amount_of_words_short_description'); + $minAmountOfWordsDescription = $this->getSearchConfigValue('min_amount_of_words_description'); + $minAmountOfWordsShortDescription = $this->getSearchConfigValue('min_amount_of_words_short_description'); + $searchTerms = $this->getSearchTerms(); + $attributes = $this->getAttributes(); $this->fixtureModel->resetObjectManager(); - - /** @var \Magento\Store\Model\StoreManager $storeManager */ - $storeManager = $this->fixtureModel->getObjectManager()->create(\Magento\Store\Model\StoreManager::class); - /** @var $category \Magento\Catalog\Model\Category */ - $category = $this->fixtureModel->getObjectManager()->get(\Magento\Catalog\Model\Category::class); - - $result = []; - //Get all websites - $websites = $storeManager->getWebsites(); - foreach ($websites as $website) { - $websiteCode = $website->getCode(); - //Get all groups - $websiteGroups = $website->getGroups(); - foreach ($websiteGroups as $websiteGroup) { - $websiteGroupRootCategory = $websiteGroup->getRootCategoryId(); - $category->load($websiteGroupRootCategory); - $categoryResource = $category->getResource(); - //Get all categories - $resultsCategories = $categoryResource->getAllChildren($category); - foreach ($resultsCategories as $resultsCategory) { - $category->load($resultsCategory); - $structure = explode('/', $category->getPath()); - $pathSize = count($structure); - if ($pathSize > 1) { - $path = []; - for ($i = 0; $i < $pathSize; $i++) { - $path[] = $category->load($structure[$i])->getName(); - } - array_shift($path); - $resultsCategoryName = implode('/', $path); - } else { - $resultsCategoryName = $category->getName(); - } - //Deleted root categories - if (trim($resultsCategoryName) != '') { - $result[$resultsCategory] = [$websiteCode, $resultsCategoryName]; - } - } - } - } - $result = array_values($result); + $result = $this->getCategoriesAndWebsites(); + $dataGenerator = new DataGenerator(realpath(__DIR__ . '/' . 'dictionary.csv')); $productWebsite = function ($index) use ($result) { return $result[$index % count($result)][0]; @@ -76,10 +51,92 @@ class SimpleProductsFixture extends Fixture $productCategory = function ($index) use ($result) { return $result[$index % count($result)][1]; }; - - $generator = new Generator( - $this->getPattern($productWebsite, $productCategory), - $simpleProductsCount + $shortDescription = function ($index) use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsShortDescription, + $minAmountOfWordsShortDescription + ) { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $simpleProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + return $dataGenerator->generate( + $minAmountOfWordsShortDescription, + $maxAmountOfWordsShortDescription + ) . ($index <= ($count * count($searchTerms)) ? ' ' + . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $description = function ($index) use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsDescription, + $minAmountOfWordsDescription + ) { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $simpleProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + return $dataGenerator->generate( + $minAmountOfWordsDescription, + $maxAmountOfWordsDescription + ) . ($index <= ($count * count($searchTerms)) ? ' ' + . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $price = function () { + switch (mt_rand(0, 3)) { + case 0: + return 9.99; + case 1: + return 5; + case 2: + return 1; + case 3: + return mt_rand(1, 10000)/10; + } + }; + $attributeSet = function ($index) use ($attributes, $result) { + mt_srand($index); + return (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + }; + $additionalAttributes = function ($index) use ($attributes, $result) { + $attributeValues = ''; + mt_srand($index); + $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + if ($attributeSetCode !== 'Default') { + foreach ($attributes[$attributeSetCode] as $attribute) { + $attributeValues = $attributeValues . $attribute['name'] . "=" . + $attribute['values'][mt_rand(0, count($attribute['values']) - 1)] . ","; + } + } + return trim($attributeValues, ","); + }; + $generator = $this->fixtureModel->getObjectManager()->create( + Generator::class, + [ + 'rowPattern' => $this->getPattern( + $productWebsite, + $productCategory, + $shortDescription, + $description, + $price, + $attributeSet, + $additionalAttributes + ), + 'limit' => $simpleProductsCount + ] ); /** @var \Magento\ImportExport\Model\Import $import */ $import = $this->fixtureModel->getObjectManager()->create( @@ -93,9 +150,13 @@ class SimpleProductsFixture extends Fixture ] ); // it is not obvious, but the validateSource() will actually save import queue data to DB - $import->validateSource($generator); + if (!$import->validateSource($generator)) { + throw new \Exception($import->getFormatedLogTrace()); + } // this converts import queue into actual entities - $import->importSource(); + if (!$import->importSource()) { + throw new \Exception($import->getFormatedLogTrace()); + } } /** @@ -103,21 +164,34 @@ class SimpleProductsFixture extends Fixture * * @param Closure|int|string $productWebsiteClosure * @param Closure|int|string $productCategoryClosure + * @param Closure|int|string $shortDescriptionClosure + * @param Closure|int|string $descriptionClosure + * @param Closure|int|string $priceClosure + * @param Closure|int|string $attributeSetClosure + * @param Closure|int|string $additionalAttributesClosure * @return array */ - protected function getPattern($productWebsiteClosure, $productCategoryClosure) - { + protected function getPattern( + $productWebsiteClosure, + $productCategoryClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure + ) { return [ - 'attribute_set_code' => 'Default', + 'attribute_set_code' => $attributeSetClosure, + 'additional_attributes' => $additionalAttributesClosure, 'product_type' => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, 'product_websites' => $productWebsiteClosure, 'categories' => $productCategoryClosure, 'name' => 'Simple Product %s', - 'short_description' => 'Short simple product description %s', + 'short_description' => $shortDescriptionClosure, 'weight' => 1, - 'description' => 'Full simple product Description %s', + 'description' => $descriptionClosure, 'sku' => 'product_dynamic_%s', - 'price' => 10, + 'price' => $priceClosure, 'visibility' => 'Catalog, Search', 'product_online' => \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED, 'tax_class_name' => 'Taxable Goods', @@ -155,4 +229,112 @@ class SimpleProductsFixture extends Fixture 'simple_products' => 'Simple products' ]; } + + /** + * @return array + */ + protected function getAttributes() + { + $attributeSets = $this->fixtureModel->getValue('attribute_sets', null); + $attributes = []; + + if ($attributeSets !== null && array_key_exists('attribute_set', $attributeSets)) { + foreach ($attributeSets['attribute_set'] as $attributeSet) { + $attributesData = array_key_exists(0, $attributeSet['attributes']['attribute']) + ? $attributeSet['attributes']['attribute'] : [$attributeSet['attributes']['attribute']]; + foreach ($attributesData as $attributeData) { + $values = []; + $optionsData = array_key_exists(0, $attributeData['options']['option']) + ? $attributeData['options']['option'] : [$attributeData['options']['option']]; + foreach ($optionsData as $optionData) { + $values[] = $optionData['label']; + } + $attributes[$attributeSet['name']][] = + ['name' => $attributeData['attribute_code'], 'values' => $values]; + } + } + } + return $attributes; + } + + /** + * @return array + */ + protected function getCategoriesAndWebsites() + { + /** @var \Magento\Store\Model\StoreManager $storeManager */ + $storeManager = $this->fixtureModel->getObjectManager()->create(\Magento\Store\Model\StoreManager::class); + /** @var $category \Magento\Catalog\Model\Category */ + $category = $this->fixtureModel->getObjectManager()->get(\Magento\Catalog\Model\Category::class); + + $result = []; + //Get all websites + $websites = $storeManager->getWebsites(); + foreach ($websites as $website) { + $websiteCode = $website->getCode(); + //Get all groups + $websiteGroups = $website->getGroups(); + foreach ($websiteGroups as $websiteGroup) { + $websiteGroupRootCategory = $websiteGroup->getRootCategoryId(); + $category->load($websiteGroupRootCategory); + $categoryResource = $category->getResource(); + //Get all categories + $resultsCategories = $categoryResource->getAllChildren($category); + foreach ($resultsCategories as $resultsCategory) { + $category->load($resultsCategory); + $structure = explode('/', $category->getPath()); + $pathSize = count($structure); + if ($pathSize > 1) { + $path = []; + for ($i = 0; $i < $pathSize; $i++) { + $path[] = $category->load($structure[$i])->getName(); + } + array_shift($path); + $resultsCategoryName = implode('/', $path); + } else { + $resultsCategoryName = $category->getName(); + } + //Deleted root categories + if (trim($resultsCategoryName) != '') { + $result[$resultsCategory] = [$websiteCode, $resultsCategoryName]; + } + } + } + } + return array_values($result); + } + + /** + * @return array + */ + protected function getSearchConfig() + { + if (!$this->searchConfig) { + $this->searchConfig = $this->fixtureModel->getValue('search_config', null); + } + return $this->searchConfig; + } + + /** + * @param string $name + * @return int|mixed + */ + protected function getSearchConfigValue($name) + { + return $this->getSearchConfig() === null + ? 0 : ($this->getSearchConfig()[$name] === null ? 0: $this->getSearchConfig()[$name]); + } + + /** + * @return array + */ + protected function getSearchTerms() + { + $searchTerms = $this->fixtureModel->getValue('search_terms', null); + if ($searchTerms !== null) { + $searchTerms = array_key_exists(0, $searchTerms['search_term']) + ? $searchTerms['search_term'] : [$searchTerms['search_term']]; + } + return $searchTerms; + } } diff --git a/setup/src/Magento/Setup/Fixtures/dictionary.csv b/setup/src/Magento/Setup/Fixtures/dictionary.csv new file mode 100644 index 0000000000000000000000000000000000000000..c839b7c46f51c25b1cda3afe4bfb7466e4ef082e --- /dev/null +++ b/setup/src/Magento/Setup/Fixtures/dictionary.csv @@ -0,0 +1,7373 @@ +the +of +and +a +in +to +it +is +to +was +I +for +that +you +he +be +with +on +by +at +have +are +not +this +but +had +they +his +from +she +that +which +or +we +an +were +as +do +been +their +has +would +there +what +will +all +if +can +her +said +who +one +so +up +as +them +some +when +could +him +into +its +then +two +out +time +my +about +did +your +now +me +no +other +only +just +more +these +also +people +know +any +first +see +very +new +may +well +should +like +than +how +get +way +one +our +made +got +after +think +between +many +years +er +those +go +being +because +down +yeah +three +good +back +make +such +on +there +through +year +over +must +still +even +take +too +more +here +own +come +last +does +oh +say +no +going +work +where +erm +us +government +same +man +might +day +yes +however +put +world +over +another +in +want +as +life +most +against +again +never +under +old +much +something +Mr +why +each +while +house +part +number +found +off +different +went +really +thought +came +used +children +always +four +where +without +give +few +within +about +system +local +place +great +during +although +small +before +look +next +when +case +end +things +social +most +find +group +quite +mean +five +party +every +company +women +says +important +took +much +men +information +both +national +often +seen +given +school +fact +money +told +away +high +point +night +state +business +second +British +need +taken +done +right +having +thing +looked +London +area +perhaps +head +water +right +family +long +hand +like +already +possible +nothing +yet +large +left +side +asked +set +whether +days +mm +home +called +John +development +week +use +country +power +later +almost +young +council +himself +far +both +use +room +together +tell +little +political +before +able +become +six +general +service +eyes +members +since +times +problem +anything +market +towards +court +public +others +face +full +doing +war +car +felt +police +keep +held +problems +road +probably +help +interest +available +law +best +form +looking +early +making +today +mother +saw +knew +education +work +actually +policy +ever +so +at least +office +am +research +feel +big +body +door +let +Britain +name +person +services +months +report +question +using +health +turned +lot +million +main +though +words +enough +child +less +book +period +until +several +sure +father +level +control +known +society +major +seemed +around +began +itself +themselves +minister +economic +wanted +upon +areas +after +therefore +woman +England +city +community +only +including +centre +gave +job +among +position +effect +likely +real +clear +staff +black +kind +read +provide +particular +became +line +moment +international +action +special +difficult +certain +particularly +either +open +management +taking +across +idea +further +whole +age +process +act +around +evidence +view +better +off +mind +sense +rather +seems +believe +morning +third +else +half +white +death +sometimes +thus +brought +getting +ten +shall +try +behind +heard +table +change +support +back +sort +Mrs +whose +industry +ago +free +care +order +century +range +European +gone +yesterday +training +working +ask +street +home +word +groups +history +central +all +study +usually +remember +trade +hundred +programme +food +committee +air +hours +experience +rate +hands +indeed +sir +language +land +result +course +someone +everything +certainly +based +team +section +leave +trying +coming +similar +once +minutes +authority +human +changes +little +cases +common +role +Europe +necessary +nature +class +reason +long +saying +town +show +subject +voice +companies +since +simply +especially +department +single +short +personal +pay +value +member +started +run +patients +paper +private +seven +UK +eight +systems +herself +practice +wife +price +type +seem +figure +former +lost +right +need +matter +decision +bank +countries +until +makes +union +terms +financial +needed +south +university +club +president +friend +parents +quality +cos +building +north +stage +meeting +foreign +soon +strong +situation +comes +late +bed +recent +date +low +US +concerned +girl +hard +American +David +according to +twenty +higher +tax +production +various +understand +led +bring +schools +ground +conditions +secretary +weeks +clearly +bad +art +start +include +poor +hospital +friends +decided +shown +music +month +English +tried +game +1990 +May +anyone +wrong +ways +chapter +followed +cost +play +present +love +issue +goes +described +award +Mr. +king +royal +results +workers +April +expected +amount +students +despite +knowledge +June +moved +news +light +March +approach +cut +basis +hair +required +further +paid +series +better +before +field +allowed +easy +kept +questions +natural +live +future +rest +project +greater +feet +meet +simple +died +for +happened +added +manager +computer +security +near +met +evening +means +round +carried +hear +bit +heart +forward +sent +above +attention +labour +story +structure +move +agreed +nine +letter +individual +force +studies +movement +account +per +call +board +success +1989 +French +following +considered +current +everyone +fire +agreement +please +boy +capital +stood +analysis +whatever +population +modern +theory +books +stop +legal +Scotland +material +son +received +model +chance +environment +finally +performance +sea +rights +growth +authorities +provided +nice +whom +produced +relationship +talk +turn +built +final +east +1991 +talking +fine +worked +west +parties +size +record +red +close +property +myself +example +space +giving +normal +nor +reached +buy +serious +quickly +Peter +along +plan +behaviour +France +recently +term +previous +couple +included +pounds +anyway +cup +treatment +energy +total +thank +director +prime +levels +significant +issues +sat +income +top +choice +costs +design +pressure +scheme +July +change +a bit +list +suddenly +continue +technology +hall +takes +ones +details +happy +consider +won +defence +following +parts +loss +industrial +activities +throughout +spent +outside +teachers +generally +opened +floor +round +activity +hope +points +association +nearly +United +allow +rates +sun +army +sorry +wall +hotel +forces +contract +dead +Paul +stay +reported +as well +hour +difference +meant +summer +county +specific +numbers +wide +appropriate +husband +top +played +relations +Dr +figures +chairman +set +lower +product +colour +ideas +George +St +look +arms +obviously +unless +produce +changed +season +developed +unit +appear +investment +test +basic +write +village +reasons +military +original +successful +garden +effects +aware +yourself +exactly +help +suppose +showed +style +employment +passed +appeared +page +hold +suggested +Germany +continued +October +offered +products +popular +science +New +window +expect +beyond +resources +rules +professional +announced +economy +picture +okay +needs +doctor +maybe +events +direct +gives +advice +running +circumstances +sales +risk +interests +September +dark +event +thousand +involved +written +park +1988 +returned +ensure +America +fish +wish +opportunity +commission +1992 +oil +sound +ready +lines +shop +looks +James +immediately +worth +college +press +January +fell +blood +goods +playing +carry +less +film +prices +useful +conference +operation +follows +extent +designed +application +station +television +access +Richard +response +degree +majority +effective +established +wrote +region +green +York +ah +western +traditional +easily +cold +shows +offer +though +statement +Scottish +published +forms +German +down +accept +miles +independent +election +support +importance +lady +site +jobs +needs +plans +earth +earlier +title +parliament +standards +leaving +interesting +houses +planning +considerable +girls +involved +Ireland +increase +species +stopped +concern +public +means +caused +raised +through +glass +physical +thought +Michael +eye +left +heavy +walked +daughter +existing +competition +speak +responsible +up to +river +follow +software +complete +above +November +December +purpose +mouth +medical +responsibility +Sunday +Wales +leader +tomorrow +piece +thirty +lay +officer +task +blue +answer +stand +thinking +extra +highly +places +arm +eventually +campaign +ability +appeal +whole +Charles +skills +opposition +remained +pattern +method +miss +hot +lead +source +bought +baby +lack +once +bill +division +remain +surface +older +charge +methods +trouble +fully +equipment +moving +suggest +disease +officers +past +peace +male +slightly +demand +failed +wants +attempt +types +Christmas +hit +post +policies +hardly +ii +arrived +compared +below +otherwise +windows +West +deal +directly +interested +sale +like +firm +status +happen +box +even if +teacher +radio +provision +variety +show +ran +sector +return +factors +essential +direction +beautiful +civil +base +waiting +caught +sit +develop +character +safety +placed +past +completely +tea +introduced +killed +love +mum +context +fifty +primary +animals +culture +Oxford +brother +obvious +weight +discussion +created +1987 +future +other +start +States +none +sold +let's +machine +afternoon +knows +environmental +fair +William +February +provides +wait +league +trees +positive +organisation +win +condition +families +argument +Saturday +learn +up +normally +claimed +truth +senior +kitchen +works +add +lived +library +minute +believed +enough +transport +share +principle +create +agree +born +players +cash +exchange +rule +budget +turn +pupils +nuclear +sitting +version +English +best +features +duty +annual +balance +front +send +boys +presence +protection +dog +courses +individuals +matters +media +avoid +influence +presented +speaker +stone +relevant +apply +August +explain +deep +Robert +1986 +achieved +slowly +relatively +shares +letters +finished +survey +huge +accepted +covered +review +Smith +closed +form +marriage +commercial +aid +lives +collection +living +speech +Africa +regional +differences +benefit +apparently +effort +gets +executive +later +latter +function +failure +return +chair +reference +horse +becomes +attack +reports +practical +queen +subjects +career +bar +official +text +appears +separate +student +names +sell +holiday +larger +cells +open +progress +early +states +helped +visit +smiled +stock +memory +merely +studio +key +putting +eat +opinion +understanding +regular +decisions +chief +drawn +firms +remains +facilities +values +district +cars +due +mhm +begin +managed +receive +corner +image +edge +sister +politics +expression +instead +impact +quarter +forced +inside +views +scale +plant +race +ball +gold +join +Henry +spend +voice +alone +additional +benefits +1985 +trust +for instance +largely +advantage +associated +increased +standing +dad +foot +somebody +pain +gas +clothes +smaller +aspects +active +affairs +possibly +increase +railway +ended +feeling +network +leaders +nevertheless +cause +half +powerful +step +complex +joined +plants +standard +holding +carefully +length +mind +rise +strength +crime +hard +wind +Mary +possibility +becoming +damage +records +reduce +examples +mainly +credit +winter +impossible +insurance +explained +units +currently +forest +formed +somewhere +earlier +beginning +regarded +fall +confidence +discussed +speed +legislation +mentioned +along +pulled +spoke +debate +intended +bodies +message +middle +plus +supply +100 +skin +Edward +stuff +providing +entirely +front +domestic +require +proved +expressed +treated +match +solution +previously +tonight +patient +actual +difficulties +farm +united +far +build +reach +proposals +extremely +choose +ministers +technical +fresh +ordinary +scene +materials +museum +Thomas +move +article +prevent +achieve +customers +includes +powers +band +items +justice +play +animal +internal +suggests +excellent +face +rich +assessment +save +phone +fairly +football +watched +telephone +steps +decide +South +traffic +watch +coffee +deal +sources +past +buildings +increasingly +relief +distance +introduction +forty +administration +no +safe +applied +sight +Mark +island +potential +banks +housing +meaning +existence +claim +northern +enjoy +reduced +twelve +equally +in front of +walk +very +apart from +watching +cultural +famous +latest +users +TV +cabinet +legs +institutions +Japan +measures +reality +proper +video +worse +lose +argued +train +spirit +programmes +accounts +trial +target +fear +joint +doubt +formal +unemployment +prison +accident +concept +limited +elements +strange +served +papers +discovered +conservative +rock +cover +usual +tree +smile +unable +warm +surely +organization +battle +proportion +difficulty +sides +refused +weekend +construction +picked +distribution +dinner +wine +while +works +obtained +exercise +writing +asking +showing +ahead +rural +lovely +applications +twice +factor +path +games +funds +whereas +nobody +shape +initial +substantial +referred +tend +seat +improve +onto +thanks +aircraft +light +contact +quiet +rain +background +identified +contrast +officials +strategy +average +master +forget +leading +soft +reasonable +seeing +pound +grounds +raise +immediate +communication +client +Paris +star +fourth +suitable +determined +ought +detail +everybody +noted +equal +imagine +appointed +manner +homes +classes +freedom +operations +detailed +keeping +selection +requirements +pair +draw +walls +talks +working +call +danger +attitude +user +overall +offer +female +relationships +Edinburgh +note +afraid +pick +charges +democratic +elections +entered +courts +growing +goal +straight +techniques +sufficient +middle +agency +scientific +eastern +crisis +rose +correct +removed +prince +theatre +Irish +laid +act +expensive +markets +sign +educational +capacity +telling +happens +absolutely +patterns +whilst +managers +purposes +employees +1984 +totally +opportunities +cause +break +will +procedure +feeling +output +mental +frequently +bridge +dangerous +either +fingers +recognition +largest +turning +arrangements +sites +profits +quick +absence +sentence +beside +pass +fields +critical +pointed +prove +listen +inc +recorded +cost +signed +hill +dropped +card +tour +understood +notes +track +1983 +partly +replaced +increased +weather +principles +seriously +familiar +related +package +elsewhere +teaching +bottom +necessarily +commitment +player +double +birds +properly +1993 +Jack +threat +notice +unlikely +admitted +1981 +replied +silence +route +file +liked +supported +issued +perfect +victory +discuss +widely +occur +second +violence +efforts +element +neck +carrying +conflict +pieces +Darlington +under +profit +reaction +colleagues +historical +standard +end +Friday +finance +hope +rooms +projects +closely +fund +daily +below +cell +Liverpool +Tom +southern +expenditure +increasing +discipline +completed +occurred +individual +spring +audience +lead +thousands +grow +conversation +tiny +congress +emphasis +finding +exist +check +alone +consideration +speaking +learning +defined +seek +1979 +appearance +maintain +option +dry +bright +urban +pictures +estate +debt +youth +neither +affected +married +feature +payment +exhibition +liberal +supposed +assembly +reform +empty +boat +suffered +bus +hell +remembered +driver +lunch +flowers +heat +processes +upper +volume +share +captain +murder +North +fifteen +represented +meetings +contribution +drugs +die +feelings +outside +Ian +arts +leg +serve +dealing +writing +curriculum +bag +sought +apparent +branch +beginning +noticed +procedures +models +Martin +enter +revealed +institute +establish +object +occasion +waste +facts +membership +requires +shook +Monday +claims +control +prepared +younger +faith +shops +challenge +answer +Russian +moral +pleasure +orders +Alan +heads +bloody +careful +filled +Corp +literature +birth +1980 +leading +code +centres +broke +prepared +that +professor +1982 +aye +wood +gentleman +flight +entry +pretty +attractive +wild +investigation +crown +protect +nodded +greatest +subject to +functions +encourage +belief +care +developments +description +tradition +Japanese +thin +adopted +vital +document +conclusion +hoped +Italy +enjoyed +engineering +coal +transfer +address +breath +along with +Ltd +alternative +total +schemes +copy +desire +search +effectively +organisations +demands +pushed +visit +etc +planning +farmers +ancient +released +opening +lips +iii +treaty +newspaper +aim +drug +identify +engine +Manchester +USA +tests +owner +sky +Tony +wearing +depends +elderly +ministry +Australia +busy +inside +anybody +reading +external +capable +marketing +streets +partner +respect +shot +institution +generation +acid +realised +chosen +wider +his +narrow +horses +broad +ordered +wonderful +key +contained +laughed +bringing +clients +typical +drink +Stephen +employed +atmosphere +slow +wondered +clean +actions +entire +troops +Leeds +vote +definition +welfare +reduction +row +walking +laws +visitors +release +meanwhile +confirmed +examination +doors +leadership +attitudes +East +enable +beneath +journey +milk +stated +hence +IBM +machines +affect +grey +screen +criticism +surprise +reading +nineteen +stories +billion +constant +teeth +brain +explanation +brief +signs +married +highest +cover +starting +knowing +claim +creation +castle +governments +goals +intention +India +vast +flat +guide +drive +surprised +easier +ideal +shut +readers +run +Bill +magazine +bound +terrible +thoughts +kinds +academic +worry +minor +seats +customer +significance +measure +pleased +unfortunately +o'clock +revolution +attempts +noise +charged +rare +biggest +rather than +somewhat +sections +stared +seeking +paying +meeting +encouraged +thick +Jones +loved +metal +grand +plenty +note +phase +coast +injury +China +granted +motion +observed +technique +ill +drew +potential +factory +lying +severe +mine +lights +wonder +Harry +spread +contains +strongly +offers +afterwards +committed +tape +shoulder +bear +corporate +obtain +kill +that is +worst +learned +settlement +ooh +grew +represent +rapidly +tall +hole +living +adult +iron +amongst +faced +negative +afford +lots +index +permanent +beat +trip +contain +fundamental +doctors +desk +ourselves +sport +unions +implications +fashion +content +similarly +elected +proposed +judge +pool +inflation +brown +Brian +originally +funny +via +practices +somehow +payments +odd +Andrew +pension +pay +crucial +fit +inner +appointment +used +flow +launched +Chris +independence +Spain +objects +setting +little +least +colours +palace +perfectly +combination +contracts +criminal +consequences +pages +contemporary +UN +talked +session +sharp +structures +planned +drive +Wednesday +Kingdom +falling +sample +virtually +fast +sick +movements +dogs +Anne +Yorkshire +Roman +accommodation +nation +temperature +massive +societies +consumer +cities +offices +documents +valley +indicated +breakfast +stayed +kids +display +named +bedroom +sports +aspect +unique +Steve +sixty +author +lane +objectives +secondary +wear +republic +agent +interpretation +assistance +directors +badly +alright +parliamentary +African +Joe +unknown +industries +assets +selling +moreover +Northern +nose +Jim +Russia +subsequent +place +describe +declared +gallery +allowing +ship +other than +visited +cross +grown +crowd +recognised +interview +broken +Simon +argue +BBC +naturally +thinking +general +Mike +meal +catch +representatives +proceedings +tears +alive +involving +shoulders +employers +begun +departments +vision +yours +unix +beauty +guilty +proposal +impression +square +angry +regulations +regions +vehicle +Jane +democracy +sequence +offering +Graham +enormous +invited +cancer +sheet +struck +Glasgow +rarely +involve +involvement +improvement +ninety +motor +shock +tone +significantly +contact +manufacturing +close +seconds +dress +assumed +well +quietly +grass +nations +provisions +communities +roof +yellow +indicate +distinction +present +statements +comments +allows +late +pollution +fruit +acting +involves +unusual +assume +towns +lucky +fuel +spot +properties +touch +fall +Major +bottle +except +anywhere +net +buying +long-term +soil +sum +stages +decline +missed +reader +extensive +manage +calling +talk +heavily +containing +plate +advertising +revenue +remaining +glad +diet +agricultural +artist +plastic +artists +gently +Bob +alright +location +ring +ice +operate +lies +candidates +Italian +pull +passage +principal +cope +linked +tired +periods +firmly +occasionally +identity +persons +limited +warned +efficient +runs +hundreds +maintenance +divided +unlike +establishment +channel +producing +fight +happening +song +map +expert +formation +comfortable +border +constitution +weapons +emergency +Chinese +waited +continues +arranged +link +Wilson +spokesman +extended +rail +Philip +candidate +believes +funding +promised +positions +mostly +household +remove +performed +cat +sleep +abroad +teams +mountain +program +countryside +stars +victim +studied +relative +criteria +conventional +parish +framework +willing +strike +cheap +ref +sudden +approval +concentration +partners +autumn +maintained +warning +cards +roads +approved +lake +starts +determine +liability +editor +realise +thinks +helping +longer +proposed +voluntary +settled +grant +characters +valuable +situations +deputy +walk +regularly +occasions +trading +rejected +agriculture +premises +dramatic +fill +theme +silver +golden +duties +friendly +arguments +accused +driving +losses +error +reflected +dream +shortly +wealth +working +temporary +federal +stress +painting +request +initially +reflect +lifted +eighty +hello +pub +recovery +loan +electricity +1980s +chest +Margaret +refer +taught +silent +Brown +beach +Indian +eleven +answered +learning +recession +focus +facing +video-taped +height +clubs +item +characteristics +emerged +options +matter +hurt +forgotten +worried +bread +admit +chief +specifically +owners +Lewis +statutory +mirror +agents +writer +deeply +Welsh +foundation +struggle +1978 +parent +dependent +mistake +reputation +Frank +eggs +decade +steel +gain +leads +publication +resistance +offence +incident +Thursday +prefer +stations +denied +examine +lifespan +wages +tasks +gained +acquired +outcome +claims +travel +competitive +marked +panel +resolution +wished +dear +efficiency +demanded +flat +yards +subsequently +gradually +businesses +chancellor +chain +specialist +1977 +dressed +tells +negotiations +relating +supporters +armed +radical +sleep +representation +agencies +theories +outside +shoes +threatened +spending +keen +drove +gardens +acceptable +notion +initiative +stairs +Cambridge +advance +leaves +recognise +worker +essentially +empire +shared +sensitive +uses +clause +attached +Taylor +living +fallen +Belfast +fighting +dear +controlled +sugar +Elizabeth +block +global +delivery +changing +Lee +computers +ages +meat +mass +emotional +brothers +bird +expansion +islands +healthy +Middlesbrough +aside +attend +secret +store +1976 +break +writers +self +rising +travel +bigger +alternative +rapid +instructions +wet +adequate +weak +licence +fixed +soldiers +examined +aimed +owned +average +awareness +centuries +images +drama +notice +Tuesday +handed +furniture +gate +scientists +administrative +sees +pocket +wooden +uncle +remarkable +co-operation +creating +Adam +Luke +newspapers +currency +comprehensive +intelligence +charity +fifth +links +hoping +respond +surprising +extension +solid +survive +growing +apart +restaurant +churches +precisely +pale +skill +close +connection +mass +dealt +brilliant +maximum +losing +depend +200 +experienced +across +introduce +philosophy +convention +gun +films +sons +eh +communications +regime +miss +attended +suffer +copies +councils +round +partnership +inquiry +Sarah +residents +absolute +firm +French +corporation +arrested +reports +minority +arrival +in addition to +listening +taste +sad +gap +plane +scope +experiences +coat +command +consequence +left +fun +Birmingham +tory +golf +electronic +behind +visual +retirement +replace +rise +darkness +fault +directed +complete +1970s +enemy +comment +electric +priority +metres +database +Tim +pure +Spanish +Nigel +rough +core +circle +result +literary +bay +championship +guests +1975 +insisted +mere +bits +successfully +limit +imposed +continuing +Rome +sounds +abuse +categories +languages +tower +Thatcher +anger +accompanied +category +collected +present +need +comparison +supreme +supplied +chemical +fans +greatly +sweet +wedding +teaching +represents +duke +mark +personnel +genuine +adults +mail +politicians +occurs +exciting +written +returning +promotion +longer +preparation +defendant +presumably +DNA +derived +Washington +paintings +fitted +mothers +affair +stupid +cricket +advanced +tank +arise +photographs +point +disappeared +expectations +findings +illness +citizens +mood +faces +tension +Commons +ladies +briefly +stones +mixture +classical +arrangement +extreme +Williams +nineteenth +discover +favourite +shot +causing +yard +begins +socialist +judgment +landscape +fail +feels +consumption +mill +1974 +informed +birthday +widespread +consent +confident +acts +Gloucester +sake +estimated +requirement +catholic +experts +Israel +numerous +throat +permission +ignored +guidance +moments +brings +costs +module +opposite +respectively +altogether +input +presentation +everywhere +distinct +statistics +repeated +tough +earnings +saved +finger +branches +fishing +components +truly +drink +turns +luck +boss +exists +champion +MP +answers +tools +cycle +recommended +intervention +mile +Scott +whenever +AIDS +promote +helpful +prospect +definitely +Johnson +organised +controls +Ben +express +Iraq +nurse +frame +perform +cottage +wave +adding +proud +by +winner +solicitor +neighbours +pilot +calls +mad +alliance +given +straight +survival +winning +votes +primarily +attacks +compensation +Sam +destroyed +camp +hat +territory +symptoms +prior to +ownership +wage +concluded +discussions +developing +cream +achievement +drawing +entrance +basically +poverty +disabled +extend +fast +suggestion +consistent +shareholders +degrees +mention +anxious +fewer +delivered +dark +transferred +employee +throw +assumption +inevitably +nervous +profession +awful +cool +hang +threw +vehicles +stable +realized +suit +hills +prize +drop +constitutional +perspective +Neil +satisfied +bid +aunt +festival +constantly +conscious +developing +connected +concerning +savings +reasonably +concentrate +pace +novel +operating +breach +purchase +crossed +Asia +chances +depth +calls +strategic +thrown +bills +Jean +Ken +reply +ha +Ruth +treat +green +sheep +dominant +phrase +push +eating +now that +conducted +employer +ears +contents +touched +prepare +sounded +Moscow +theoretical +setting +soul +wore +study +1960s +outstanding +benefit +vary +jacket +except +holy +processing +sand +clinical +prisoners +dispute +shadow +minimum +organizations +plaintiff +snow +cried +fit +driven +Joseph +port +recognized +servants +limits +pink +et al +sound +hearing +measured +dance +eighteen +sorts +Patrick +trained +stomach +slight +fought +points +storage +breaking +impressive +honest +provided +dismissed +glanced +related +cast +crew +defeat +hold +gift +enthusiasm +princess +press +spending +advantages +reaching +articles +resulted +files +hung +cuts +residential +extraordinary +visible +shouted +reducing +experiments +tables +finish +tendency +conduct +objective +report +ring +hospitals +mechanism +seventy +exception +poetry +inspector +1973 +covering +stepped +accurate +percent +victims +approached +distant +alongside +airport +furthermore +considerably +pressed +missing +origin +salt +personality +fight +Canada +arrive +fly +Greek +receiving +still +rocks +fees +fee +complicated +ends +musical +stands +moon +chamber +puts +turnover +attacked +ultimately +routine +observation +precise +plain +gentle +watch +staring +since +leisure +economics +device +broken +mortgage +live +leaves +confusion +cut +finds +instruments +secondly +Bush +certificate +ear +remote +satisfaction +responsibilities +ratio +coach +fears +sentences +holder +shopping +possession +selected +Bristol +sets +smoke +rugby +songs +clock +summary +implementation +protein +housing +escape +wing +fixed +helps +poll +Arthur +scored +chose +column +holidays +contributions +architecture +Nick +approximately +disaster +minds +Keith +marks +trust +neither +monetary +mountains +White +discovery +collect +spoken +steam +smooth +silly +childhood +teach +Kong +unity +staying +climate +percentage +villages +attracted +Americans +designs +secure +cutting +iv +Hong +last +taxes +tennis +peak +relation +readily +evaluation +frequency +Andy +shirt +cake +nights +bishop +test +pretty +Charlie +deliberately +round +determination +applies +automatically +standing +rent +psychological +violent +medicine +boards +protest +Anna +unemployed +final +being +Rose +reforms +inevitable +junior +signal +building +till +welcome +fat +roles +headquarters +sensible +visits +manufacturers +restrictions +samples +Pacific +improved +Berlin +grateful +strategies +score +tended +expense +loans +addressed +mode +structural +dozen +pride +newly +founded +variation +aged +rely +investors +infection +dominated +combined +survived +Helen +string +Lucy +experiment +fourteen +undertaken +committees +buyer +agreements +participation +welcome +match +complaints +ships +critics +guitar +camera +laboratory +waves +landlord +rang +hate +demonstrated +bomb +engaged +knife +so-called +modules +pleasant +headed +surgery +universities +millions +concepts +proof +marry +Maggie +operating +pressures +lives +sixteen +repeat +host +Dave +pitch +attempted +assess +penalty +tail +boxes +holes +deep +contribute +passing +reveal +cleared +thereby +acceptance +1972 +anxiety +above +Newcastle +formula +personally +Howard +mission +deaf +relatives +imagination +apple +dirty +rid +abandoned +appreciate +continuous +describes +suffering +circuit +stronger +responses +excitement +approaches +supply +plan +Zealand +tested +disk +holds +replacement +instrument +universe +memories +overseas +expertise +causes +solicitors +comfort +sergeant +trend +treasury +entitled +sounds +acquisition +opening +tickets +bath +delighted +sending +increasing +confirm +loose +state +targets +occasional +paragraph +writes +evident +Kent +desperate +handle +fellow +blind +occupied +overcome +dust +burden +psychology +relate +drivers +surprisingly +1970 +Matthew +cheese +consciousness +considering +universal +Gordon +aha +square +succeeded +knees +1971 +boots +smell +closer +mummy +slipped +component +regulation +Roger +attempt +locked +keeps +wheel +classic +MPs +cattle +consists +touch +illustrated +platform +shift +draft +purely +load +influenced +passengers +recommendations +preparing +solutions +Alexander +injuries +tenant +commonly +Victoria +leather +gathered +zone +sufficiently +like +Laura +squad +recall +steady +retain +checked +existed +attract +conservation +flesh +pack +publicity +rose +mean +variations +split +sixth +edition +concerns +tied +summit +engineers +Terry +listed +judges +researchers +equivalent +assist +upstairs +hers +Francis +located +nurses +fear +mark +suggesting +whispered +serving +intellectual +influence +stream +generated +consequently +San +authors +wondering +judgement +experience +Victorian +egg +supplies +level +produces +councillor +roots +taxation +bathroom +ultimate +awarded +stick +glasses +raising +qualities +layer +lost +creative +medieval +risks +assumptions +displayed +dreams +Germans +accounting +curve +drawing +backed +adopt +colleges +guard +evolution +sign +aims +sharply +constructed +advised +softly +settle +decades +completion +linguistic +ignore +convinced +Colin +judicial +photograph +sophisticated +Alice +asleep +paused +amounts +poem +recording +carbon +Durham +possibilities +good +explains +equation +NHS +vulnerable +raw +net +deaths +babies +illegal +outer +topic +medium +till +promise +tends +hopes +angle +interviews +ban +feed +potentially +machinery +tongue +coalition +travelling +define +consultation +reception +pulling +Nicholas +integration +revolutionary +quoted +compare +surrounded +bitter +attempting +guess +improvements +climbed +cathedral +heaven +wanting +painted +Australian +changing +grammar +jumped +Ulster +Gulf +native +imperial +persuade +voices +conclusions +laughing +lift +1968 +Gary +boundaries +favour +guy +studying +Jimmy +beliefs +undoubtedly +wings +retained +joy +bone +informal +demonstrate +Douglas +regard +clear +calculated +flexible +meals +announcement +lawyers +ruled +account +sheets +tunnel +exercise +bars +carpet +quantity +catalogue +reminded +shrugged +notably +Anthony +schedule +petrol +investigate +hotels +buried +once more +journal +nowhere +considerations +concentrated +collective +destruction +frequent +versions +offences +agenda +clever +experimental +plays +Kate +listened +La +texts +plates +deficit +transition +Norman +spiritual +intense +indication +flew +pushing +rational +hanging +entitled +excluded +knocked +professionals +tight +composition +indicates +conservatives +Kevin +interaction +ceiling +guidelines +cold +roughly +Governor +qualifications +ethnic +me +argues +Dublin +inches +opera +pupil +cheaper +generous +prominent +inadequate +accordingly +welcomed +instruction +logical +passion +drawings +exposure +departure +blame +racing +mixed +historic +guest +Mrs. +pipe +modest +Dutch +lessons +hero +Lloyd +sectors +Diana +barely +logic +Essex +acute +harm +representing +discourse +voted +electrical +hearing +consumers +jury +Grant +weekly +acted +delay +valid +wherever +representative +transaction +bowl +increases +contributed +Christopher +record +leaned +lesson +lit +admission +stores +awards +automatic +timber +trousers +vote +habit +Oliver +arrange +red +matches +punishment +bones +cross +deny +rubbish +hide +mortality +complex +pc +earl +explore +urged +occupation +storm +darling +keys +customs +profile +gross +depression +classroom +glance +mystery +mutual +reliable +wholly +entering +bare +liable +facility +stressed +stuck +realize +engineer +smiling +confined +province +registration +males +laughter +humour +resource +multiple +Albert +ruling +silk +waters +Rachel +paint +cotton +Atlantic +identification +claiming +sole +coverage +arising +Owen +honour +poet +prospects +travelled +divisions +posts +avoided +in case +charter +managing +pregnant +obligation +win +adds +formally +flying +Latin +nearby +Egypt +exact +directions +curious +bother +participants +lawyer +resignation +bearing +sets +pointing +tool +damages +speakers +fate +daddy +devices +phenomenon +strain +substance +bags +wire +Wood +underlying +responded +enjoying +visitor +joining +uncertainty +but +drop +submitted +flower +Ford +California +perception +identical +farming +letting +audit +satisfactory +Billy +ticket +lists +preference +Great +thirteen +Van +secret +pop +album +federation +learnt +deliver +Westminster +chemicals +farmer +variables +male +assault +marginal +leave +namely +fed +distinctive +kingdom +assessed +refuse +electoral +urgent +allowance +observations +libraries +Lawrence +reflects +force +sympathy +running +falls +publishing +recovered +stability +canal +funeral +singing +titles +beds +sessions +restricted +Sheffield +Nottingham +expecting +clothing +drinks +disposal +failing +joke +focus +succeed +Maria +typically +official +conversion +presidential +generations +mayor +sharing +Clare +worth +transactions +era +policeman +Fred +gaze +controversial +count +proceed +Young +folk +fabric +oral +horror +Kelly +everyday +emperor +viewed +sing +belt +fortune +demand +doubt +crash +encouraging +interpreted +Louis +organic +maintaining +removal +female +routes +continued +trials +enables +print +laugh +bent +expected +connections +magistrates +errors +statistical +resolved +desirable +recognize +Stuart +thoroughly +injured +van +blocks +prosecution +register +trends +preferred +reckon +innocent +ideology +belong +improved +past +corridor +exclusive +tale +pairs +prayer +collapse +lease +talent +gains +separated +marked +experienced +persuaded +sighed +butter +suggestions +Russell +unexpected +foods +picking +banking +sciences +superb +contacts +operated +alarm +go +Poland +gene +daughters +sheer +guardian +count +cloud +disappointed +Bernard +format +scenes +frightened +hardware +traditionally +gastric +genes +effectiveness +full-time +intend +concentrations +defend +strict +fighting +creatures +closer +Swindon +capitalist +Walker +addition +chocolate +emerge +Hugh +hidden +likes +Susan +Stewart +reactions +lands +establishing +swept +anniversary +permitted +export +1967 +justify +tissue +Davies +bet +specified +romantic +garage +conviction +declined +resigned +Clarke +advise +scientist +root +asset +warmth +bulk +bands +knee +minimum +humans +references +any +associations +muscles +withdrawal +registered +distributed +regarding +exposed +declaration +graphics +reluctant +actor +switched +sisters +winners +eighteenth +chemistry +rest +justified +stop +converted +boundary +suspect +magnificent +stretched +convenient +friendship +established +recover +destroy +Jackson +mess +correspondent +navy +dollar +craft +reflection +chicken +plans +tin +Miller +curtains +gesture +tourist +diary +protected +ocean +discussing +practitioners +bloody +entertainment +nearest +mechanisms +closed +expenses +uncertain +artificial +democrats +damaged +composed +heating +diplomatic +drinking +discrimination +rows +bench +councillors +acquire +installed +guns +killing +Microsoft +blow +salary +Baker +tip +1950s +physically +estates +tremendous +marine +ease +institutional +mechanical +retail +resist +mixed +literally +chapel +distinguish +wildlife +Rivers +Iran +tories +doubts +formerly +priorities +reserves +publications +commented +gender +passenger +Sussex +strictly +boats +causes +pen +chapters +cheque +required +testing +carriage +weapon +generate +Clinton +asks +earn +supporting +mentally +judge +messages +females +biological +applying +implies +known +Emily +rolled +tube +functional +accidents +flexibility +chairs +Phil +styles +cap +straightforward +moves +wise +fired +organized +inspection +Derek +mathematics +heritage +superior +1969 +specially +finance +cloth +sociology +desperately +fiction +equity +satisfy +Lords +shell +Wright +lad +whereby +forests +suit +pursue +digital +increases +tenants +refers +voters +piano +productivity +part-time +lightly +assistant +Commander +address +situated +restoration +outlined +imports +comment +stolen +Harris +clerk +cinema +Ann +covers +capitalism +spectacular +shapes +controversy +Marx +gates +escaped +Robin +continuing +trains +ensuring +colonel +confused +grants +remarks +bonds +wives +computing +constraints +solve +aggressive +availability +unfair +sadly +invasion +tracks +compete +closure +spare +painful +earned +venture +topics +wonder +equivalent +grade +Korea +pot +emotions +washed +escape +abstract +Eric +murmured +stake +lift +states +breeding +securities +asian +mud +Joan +estimates +cheek +stored +correctly +refugees +Moore +obligations +spirits +unhappy +Ross +networks +beaten +snapped +initiatives +understanding +alter +shame +pensions +oxygen +therapy +associated +courage +discretion +dates +deposits +hopefully +exports +legislative +Eliot +ward +monthly +deciding +describing +assuming +opposed +Alex +searching +intelligent +impose +explicit +jurisdiction +designer +tie +fellow +quantities +fleet +Barry +seller +RAF +borough +stand +flats +virtue +constituency +complained +coloured +midnight +taxi +engines +railways +display +just +ridiculous +Caroline +debts +comparable +amazing +acknowledged +appeal +wars +successive +refusal +incorporated +creature +secured +economies +isolation +Leicester +succession +signals +working-class +physics +feared +concert +tonnes +realistic +hungry +launch +Evans +resort +burst +sort +back +Walter +gear +Shakespeare +surveys +volunteers +stick +separation +la +demonstration +fails +conception +decent +discount +unnecessary +prevented +flying +worn +dictionary +twentieth +fat +random +retired +local +origins +packed +achieving +heading +forever +influential +masters +channels +harbour +producers +duration +Thames +cable +1945 +desert +terrace +assured +allocation +check +diseases +merchant +constable +Vietnam +Dean +recalled +lifetime +chips +Ray +genetic +complaint +near +visiting +explaining +order +marvellous +Malcolm +Morgan +restored +earliest +enabled +release +Cardiff +assurance +bottles +brick +essence +autonomy +giant +requiring +hunting +consensus +differ +vegetables +junction +workshop +measure +purchaser +secure +attendance +necessity +bottom +demanding +skilled +shaking +subtle +select +attack +questioned +sooner +producer +planet +elegant +amendment +hopes +carries +recommend +lesser +farms +parallel +limitations +locally +Marie +tragedy +instance +cousin +collections +backwards +grain +resulting +fraud +swung +landed +quarters +liberation +seventeen +referring +interior +bike +suspended +officially +journalists +nasty +movie +suppliers +dealer +shows +soldier +intensive +kit +witness +delight +symbol +forum +casual +tropical +shorter +Allen +crimes +printed +miners +feeding +relax +pass +manufacturer +chip +crazy +forming +kissed +swimming +happily +copper +arguing +shots +landing +nursery +entries +preliminary +besides +arises +partial +households +damp +wool +1964 +servant +Pakistan +attending +Guy +plot +muscle +beings +inch +simultaneously +concrete +Roy +roll +bell +neighbour +reign +analysed +tide +expand +alleged +guilt +rank +introducing +transfer +uses +ceremony +Morris +separately +opinions +enquiry +grinned +lover +slept +choices +assistant +severely +finest +poured +vertical +Easter +upset +hey +allegations +IRA +justification +detective +programs +throwing +strike +ate +appendix +Jenny +districts +commonwealth +dealers +delicate +forms +advisers +lonely +dull +mouse +Pat +occupational +pity +behave +complexity +youngsters +riding +weakness +excessive +Clark +progressive +captured +stance +undertake +exceptional +faster +Iraqi +remind +counter +Greece +triumph +remarked +continental +striking +integrated +pit +encountered +implemented +sizes +directive +participate +safely +lowest +lighting +villa +okay +downstairs +portrait +alternatively +edges +focused +bye +residence +panic +label +aims +magazines +neat +combined +transformation +theft +lecture +incidence +scores +radiation +perceived +spread +firstly +interface +doctrine +shouting +affecting +ours +excuse +accepting +risen +Lancashire +approach +deposit +pond +substantially +innovation +diagnosis +gifts +allocated +regard +remainder +speculation +approaching +dialogue +estimate +wash +supervision +dying +exclusively +happiness +politically +timing +chronic +Geoffrey +peasants +tightly +characteristic +accuracy +compulsory +wrapped +interim +objective +Benjamin +walking +infant +Bruce +judged +splendid +ride +divorce +magic +Cleveland +bond +review +short-term +ambulance +brave +investigations +systematic +Green +seized +cry +laugh +advanced +obliged +opens +eaten +relevance +1930s +careers +Liz +withdrawn +Barbara +no +payable +handsome +fun +Ms +instances +governors +horrible +measurement +employ +primitive +steadily +switch +fascinating +Brazil +ideological +pile +mounted +metropolitan +alternatives +dollars +north-east +explosion +starting +glory +scarcely +Harriet +surrounding +coup +domain +fence +threatening +dragged +breast +habits +mine +hierarchy +grip +socialism +enquiries +particles +Sweden +choosing +colleague +monitoring +Midlands +restore +printer +imagined +doorway +prisoner +juice +classification +estimated +equilibrium +solely +with regard to +serves +peaceful +observer +explanations +circles +rescue +maps +hated +observe +Hughes +premier +mate +hypothesis +1966 +ride +companion +liver +factories +buyers +reward +controlling +satellite +loyalty +operational +pardon +improving +jump +potatoes +intervals +technological +near +fortunately +hostile +advisory +cook +precious +opponents +peasant +insist +geography +button +consistently +cultures +seeds +monopoly +accessible +tournament +moves +excited +determined +owed +pockets +belonged +Hollywood +dining +switch +traditions +compromise +intensity +chaos +obtaining +Mexico +King +combine +altered +nonsense +clouds +themes +suspicion +ranks +disorder +stocks +Kuwait +1965 +2000 +consultant +collapsed +purchased +impressed +half +Catherine +provincial +sterling +performances +instantly +Bell +constitute +arrest +dose +exercises +issue +competitors +spectrum +dangers +allies +travellers +plc +kid +disc +Donald +nowadays +Surrey +cheeks +endless +isolated +dimension +twin +bedrooms +clean +columns +privilege +post-war +volumes +broadcasting +commerce +historians +train +geographical +oak +actors +step +like +dynamic +freely +checking +equipped +inspired +density +1994 +forthcoming +HIV +boring +handled +poems +recording +unfortunate +banned +Karen +own +suspected +boom +tribunal +kicked +possessed +Jonathan +broadly +publicly +attributed +definite +challenged +extending +cooking +pause +strip +predicted +super +barrier +pregnancy +loud +menu +preserved +Avenue +restaurants +acres +prompted +senses +essay +lip +recruitment +defendants +presents +guarantee +invest +cats +maximum +notable +upwards +arose +cry +fierce +detected +indirect +German +witnesses +patch +sensitivity +Le +mistakes +receiver +crops +chin +wheels +rice +Dec +forgot +illustrate +reveals +Freud +limit +chap +Campbell +races +awkward +Turkey +implied +climb +widow +varied +slid +stopping +rope +steep +neutral +Oxfordshire +finish +debut +seed +challenge +promoted +delegation +hitherto +artistic +muttered +adoption +architect +dear +Kenneth +portfolio +continent +transformed +couples +probability +content +Robinson +struggling +mild +counties +wish +mention +fitness +tackle +dish +statute +invariably +Charlotte +prey +view +consultants +gather +arriving +corners +delegates +Holland +archbishop +Sue +withdraw +replacing +Milton +meaning +mature +differently +chart +technologies +woods +possess +cab +grace +toilet +grabbed +prevention +equality +wishes +bases +operator +regardless +harsh +colonial +ambitious +exploration +lords +investigated +collecting +Switzerland +shadows +Corbett +evil +Johnny +dramatically +Marshall +indicating +orchestra +lock +inhabitants +defeated +disappointment +magnetic +washing +fibre +correspondence +verbal +legitimate +requested +emotion +odds +workforce +vessels +brass +pursued +ph +balls +adviser +faint +handling +appointments +grandfather +motivation +sympathetic +publishers +peoples +socially +investments +rhythm +variable +Chelsea +memorial +well-known +empirical +roses +ceased +fluid +descriptions +incidents +DC +dismissal +appreciated +communicate +rushed +bronze +wisdom +Daniel +supper +adventure +tribute +seeks +promise +head +ye +1960 +crop +beef +suited +exercised +respects +terror +circulation +identifying +achievements +fool +intentions +proportions +lads +directory +Brighton +inn +promoting +flag +separate +Roberts +Ward +Dennis +clay +Cook +Norway +attraction +ends +disability +championships +vague +virus +shift +ranging +competence +examining +inform +spaces +goodness +gang +favourite +preserve +remembering +naval +molecules +hearts +trapped +actively +leaf +Brussels +distress +resolve +custody +packages +drinking +operators +myth +gain +voting +Mick +returns +tourists +encouragement +lacking +seldom +processor +sums +integrity +acknowledge +shortage +depressed +rightly +Louise +remarkably +repair +shoot +electronics +wishing +Kinnock +imprisonment +kings +waved +shared +shocked +uniform +added +reject +implement +pays +hesitated +seventh +magic +mid +populations +worthwhile +filling +crystal +fraction +qualified +Newton +Sally +server +Nato +specimens +kiss +reflecting +shower +missing +roll +sword +varieties +clinic +imply +ie +rivals +Julia +breakdown +Anderson +scales +fan +operates +blank +whoever +scandal +oldest +smart +favourable +filter +interviewed +absent +mining +gentlemen +enemies +champions +Duncan +exclusion +boot +locations +Hamilton +transmission +custom +tanks +tries +Gloucestershire +publisher +beating +evidently +Netherlands +Polish +lively +exceptions +Emma +appeals +Israeli +mobility +reviewed +buses +conclude +mix +shore +commissioner +absorbed +Norwich +dawn +developed +guards +incomes +parking +vendor +wishes +republics +loads +barriers +translation +evenings +Hungary +lectures +stimulus +conflicts +remains +margin +question +bothered +neighbourhood +tourism +meanings +FA +desktop +reportedly +risk +zero +demonstrations +dividend +opponent +wake +stiff +rejection +flavour +relates +borrow +emissions +representative +Midland +thereafter +enthusiastic +observers +cited +quid +fortnight +dreadful +guarantee +reduced +rigid +killer +ending +trick +successor +execution +influences +temperatures +mines +drank +coastal +greeted +nightmare +peculiar +corruption +tray +speaks +cupboard +creates +Jordan +Aberdeen +harder +burned +appearing +Swiss +rabbit +environments +comedy +referendum +bureau +avoiding +just about +matrix +honestly +profound +journalist +extended +Julie +tapes +suspension +delayed +eager +comply +selected +skirt +matched +feminist +Davis +Canadian +closing +acts +grief +relaxed +insight +deck +sensation +placing +sequences +temple +parks +tactics +verdict +adapted +enhance +corresponding +strings +accurately +running +pray +accent +envelope +interference +grandmother +examinations +phone +planned +shelf +deemed +waist +waste +onwards +applicable +futures +sauce +immense +purchase +breathing +allied +Norfolk +contest +expects +supports +km +blacks +decision-making +coins +genuinely +accounted +expressing +assessing +dance +scheduled +adjustment +charge +winds +meets +practically +merger +comparative +permit +celebrate +vessel +belonging +affection +outline +albeit +Lily +leaning +lounge +raises +Cheltenham +workshops +refusing +shallow +dishes +monitor +propose +blamed +dioxide +kind +broader +handling +bastard +uncomfortable +affects +proposition +representations +conservation +ya +makers +Yugoslavia +Fox +citizen +forcing +productive +woke +bored +beneficial +slip +campaigns +handful +aged +collar +curtain +diversity +hint +Thompson +disappear +charming +bonus +secrets +interrupted +specialists +accommodate +frustration +recommendation +meantime +coffin +daily +condemned +minimal +mobile +academy +testing +independently +appealed +museums +cruel +faces +murdered +on board +Turkish +aim +Will +territories +pressing +Churchill +commit +verse +research +orange +interval +threats +passive +suspicious +forgive +liberty +ghost +rear +believing +correlation +measurements +1963 +investigating +shade +layers +bias +overwhelming +certainty +Sunderland +cow +commissioned +trusts +maturity +resulting +fatal +surrounding +crying +planted +symbolic +isle +historian +enabling +removing +slope +excuse +angel +nearby +rats +straw +1962 +surfaces +gods +foundations +honours +Belgium +disputes +insects +inspiration +draw +presenting +registered +pavement +telephone +reserve +keeper +dimensions +predict +neighbouring +validity +breeze +ugly +expanded +lasted +irrelevant +complain +shelter +patient +driving +wealthy +upset +hostility +profitable +rod +fled +compact +lamp +shifted +supplier +crossing +phenomena +IT +measuring +horizon +rival +making +clergy +marble +pensioners +fragments +loyal +Alison +Stanley +conscience +sixties +Hill +saving +tune +moderate +1961 +soup +paths +struggled +popularity +score +singer +distinguished +climbing +kick +Betty +characteristic +interior +episode +oven +basket +noble +forwards +consisted +crowds +positively +pole +burning +pet +insufficient +evil +mysterious +jet +eligible +behalf +passes +nails +collaboration +lorry +nest +varying +enforcement +Spencer +Denmark +make-up +molecular +managerial +raid +ambition +middle-class +brand +migration +embassy +neatly +looks +worship +Olympic +devised +exclude +organ +favoured +linear +Samuel +cared +manor +detect +interpret +Kennedy +substances +crude +fantasy +counselling +abilities +treating +blew +embarrassment +executed +implication +Ron +printed +prospective +importantly +Preston +continually +Barnes +executives +catching +forehead +Ali +diverse +parental +elaborate +furious +definitions +appreciation +fiscal +Kim +commitments +sculpture +runs +striker +beans +brush +soccer +spell +reductions +contrary +soap +dated +stretch +publish +russians +pig +stroke +ladder +Greater +burning +expressions +useless +nerve +pence +Gabriel +rumours +relied +Edwards +semantic +inherent +embarrassed +1948 +specification +despair +yep +name +serum +Maxwell +Dick +apartment +Vienna +deliberate +stranger +philosophical +criterion +trap +pubs +utterly +link +frowned +awake +bureaucracy +nonetheless +sunshine +bloke +partially +remedy +battery +variable +within +forth +barn +ties +settlements +installation +crashed +negotiate +Somerset +nursing +dignity +promising +minus +criticised +sacred +analyse +senate +incentive +unpleasant +varied +selective +qualified +Devon +powder +clauses +expectation +tender +inclined +funded +alleged +hidden +ridge +exhibitions +lengths +Joyce +posed +explicitly +symbols +exploitation +receives +1950 +intermediate +Isabel +blocked +trophy +launch +spotted +manufacture +diesel +masses +protective +paint +budgets +Lisa +grows +fortunate +deserve +lap +concerns +varies +compliance +defensive +damage +objections +qualify +featured +suite +salmon +reach +requests +objection +devoted +thesis +repeatedly +blow +palm +Austria +Rover +parked +Carter +Guinness +temporarily +Land +south-east +chains +worthy +ozone +pursuit +valued +divine +react +deals +head +phoned +carrier +jeans +feedback +dancing +tales +rally +grant +performing +rush +handicap +consisting +counted +qualification +guaranteed +negligence +continuity +lend +offers +educated +stuck +surplus +swallowed +eagle +printing +land +Willie +novels +driving +dependence +1st +eighth +Craig +organise +Cornwall +orange +diameter +1939 +toward +auction +eating +Max +invisible +determining +construct +faculty +offenders +occurring +Pete +charm +Don +suffering +contempt +Wimbledon +reinforced +specify +misery +dropping +breasts +overall +Sara +jewellery +bacteria +sin +comparisons +privatisation +owe +squadron +grave +codes +circular +misleading +centred +sunlight +lowered +invested +mathematical +proteins +sanctions +aggression +caution +loch +reply +direct +subjected +inappropriate +diagram +terribly +St +human +liquid +solar +angles +sorted +persistent +poles +laying +inherited +phrases +doubtful +calcium +shake +ingredients +Sophie +admits +black +BR +monster +flames +allowances +sustain +needle +telecommunications +sphere +revenues +guessed +bowel +doubled +prints +rangers +accountants +screaming +legend +petition +predominantly +manual +lies +premium +photo +surroundings +spots +gravel +19th +architectural +bold +Maastricht +inheritance +Harvey +knock +blues +beyond +Day +emergence +beautifully +deeper +intact +cooperation +convince +incredible +sound +devoted +conduct +united +celebration +abruptly +considers +flights +explored +loves +blue +Derby +restriction +prior +submit +gaining +Santa +morality +tragic +musicians +invite +Ipswich +selling +script +coupled +tap +remark +consist +respectable +pint +optimistic +humanity +layout +openly +breed +policemen +Scots +invented +linking +convincing +Harold +guide +vocabulary +Rob +unacceptable +competent +Carrie +spatial +ignoring +applicant +swiftly +easier +painter +decisive +traders +pretend +bargaining +depended +modes +preventing +rage +respective +elite +permanently +seemingly +bunch +carers +fathers +engagement +liquid +Canterbury +binding +fires +sentenced +rebels +founder +ballet +erosion +Gould +syndrome +relieved +nursing +harmony +Coventry +protested +hut +sits +stops +Lamont +bore +instructed +fertility +toxic +testament +1957 +sickness +stretch +Bath +lemon +practise +mix +faster +integral +select +redundant +handle +throne +conceived +polytechnic +nerves +belongs +privately +burn +gravity +labelled +Alfred +bishops +basin +rings +holders +swing +flood +Christie +evolved +sovereignty +then +applicants +cows +lion +Virginia +trail +smoking +trading +Murray +boxing +amateur +probable +scrutiny +tempted +borders +pan +fix +hydrogen +accountability +consulted +echo +sponsorship +fame +El +lakes +protests +patience +documentation +Geoff +backing +search +Mozart +silently +passing +seasons +recipe +fetch +auditors +territorial +specified +abandon +bombs +Los +mineral +horizontal +lined +Robyn +booked +du +cleaning +bear +old-fashioned +inland +youngest +envisaged +floors +thrust +likewise +strengthen +penny +wake +Bradford +overseas +consult +cognitive +Ralph +dock +reaches +disturbed +communists +slim +synthesis +contexts +revival +Reading +regulatory +hurried +defender +dry +miserable +walks +debates +dancing +isolated +venue +Hampshire +resident +rounds +deals +packet +likelihood +remaining +induced +guys +temper +comparatively +calculations +protecting +holdings +corn +1947 +Yeltsin +fusion +Marxist +conferences +creditors +questionnaire +gothic +scared +willingness +civilian +shelves +reporting +precision +divide +Phillips +overnight +Intel +Linda +deputies +Indians +Trevor +Juliet +Watson +conventions +modified +instant +praise +Des +coin +blown +hiding +galleries +1940 +Constance +outlook +incurred +adverse +subsidiary +tiles +seventeenth +Korean +emphasised +Eddie +bile +1959 +fancy +accounting +leaflet +headmaster +crack +heels +truck +engage +reporter +plays +Steven +calm +initiated +brigade +Dorothy +unconscious +convicted +illustration +trustees +sustained +alike +End +ideally +entity +tons +sang +telegraph +negotiation +opposite +smell +aesthetic +wiped +concentrating +anonymous +trace +usage +orthodox +fulfil +polite +girlfriend +lovers +translated +static +intent +cancelled +inside +unaware +presidency +corps +assigned +appearances +exploit +margins +worldwide +cups +solved +panels +halt +EEC +Suffolk +developers +fantastic +Lancaster +seminar +fashionable +criticisms +Cooper +motorway +zones +foolish +intake +advances +receipt +rule +regiment +trades +manual +backs +duck +causal +convey +Tommy +wee +cleaning +fond +compatible +Southampton +inclusion +Herbert +finding +lengthy +two-thirds +tent +shed +implicit +cameras +dare +abolition +Romania +pigs +lace +dedicated +cuts +perceptions +ft +counts +earning +kiss +confirmation +dual +confronted +twenty-five +mistress +assignment +propaganda +toys +Arsenal +Eleanor +critic +curiosity +republican +pipes +reduces +shooting +cheerful +reporting +plea +distinguished +subjective +pie +priests +returns +tel +labels +width +relaxation +advertisement +white +smoke +pencil +legally +following +lacked +surviving +disadvantage +ruling +forward +sleeping +owl +adequately +reproduction +rewards +architects +rear +Shelley +exotic +ambassador +1914 +camps +displays +passages +gazed +timetable +salad +purple +cautious +visiting +Turner +aggregate +ignorance +anticipated +Parker +redundancy +array +penalties +renaissance +theology +try +warn +process +ethical +major +proving +plain +protestant +grid +tenth +takeover +canvas +Ted +skull +highlighted +jokes +beat +pools +twins +borne +criticized +chemical +omitted +revision +sincerely +prizes +salvation +teenage +responding +indicators +repairs +amnesty +comparing +large-scale +yield +Claire +photography +disastrous +thumb +dying +jointly +kilometres +scholars +ace +lump +delicious +confidential +clash +market +underground +Blanche +armed +destination +witnessed +parameters +costly +restraint +bit +1958 +shaped +rode +tips +prosperity +diamond +fury +instinct +reserved +valuation +contacted +subsidies +Hunt +collector +Darwin +sponsored +compound +strengths +sank +defences +lifestyle +prejudice +announce +apparatus +dot +shoe +blanket +wound +Christine +hunger +cabin +photographer +stay +preservation +calendar +assessments +colony +Katherine +thorough +medal +trips +washing +eliminate +breathe +actress +provinces +helicopter +mist +clue +dominance +relaxed +analysts +searched +grin +Czechoslovakia +hitting +inability +portion +restrict +Gray +conspiracy +Nicholson +mercy +log +autonomous +intends +solidarity +jail +genius +1920s +pilots +incorporate +atomic +blade +frozen +1956 +colourful +discharge +injured +mask +provided that +Trent +ease +draws +retire +supposed +ml +angrily +sigh +stamp +adjust +ferry +concessions +majesty +Gilbert +pylori +uniform +adjusted +ashamed +admired +alpha +referee +1944 +Lebanon +respondents +Collins +rested +reconstruction +flown +individually +jaw +submission +efficiently +bitterly +glorious +pour +illustrates +Angeles +amid +convert +wicked +provoked +Chapman +elbow +videos +coherent +annually +le +rising +disciplines +cliff +boyfriend +novel +controls +sweat +depths +Claudia +cave +balanced +strikes +stretching +pains +Close +Tokyo +Portugal +racism +priced +delightful +evaluate +arbitrary +Chicago +Richards +signature +reversed +heroes +clarity +hit +screamed +adjacent +lid +psychiatric +comprising +honey +temptation +beam +immigration +recordings +worrying +weird +practitioner +unchanged +calculation +tutor +politician +rolling +Athens +expedition +electorate +evolutionary +scattered +abolished +researcher +ports +Chester +dilemma +Carl +loaded +IMF +flung +intimate +fever +parallel +tight +miracle +including +lawn +biology +Lothian +failures +breaks +Angela +shy +appraisal +sporting +wines +cleaned +disciplinary +occurrence +smile +formidable +lexical +graduates +fined +cooking +privacy +needles +Reagan +Black +Ed +sink +march +equations +grim +narrative +HP +charts +polls +Paula +express +OK +limbs +decorated +high +addressing +proceeds +pact +Madame +Merseyside +revenge +vice-president +far from +proceeded +airline +minerals +killing +accused +double +gradual +descent +mount +homeless +courtesy +enhanced +supermarket +Blake +Cheshire +interfere +organisers +managing +monitoring +coming +rat +supporting +Marcus +trace +approve +delays +pm +Reynolds +please +yo +programming +training +renewed +Hull +invention +writings +back +excess +planes +legacy +challenges +gaps +dug +Jason +interpretations +smallest +pulse +analyses +Ashley +rubber +retired +specimen +outdoor +shooting +chosen +embarrassing +wrist +atoms +Hereford +smoking +incidentally +preferred +renewal +Japanese +vanished +hook +loudly +bride +Annie +interactions +bizarre +gospel +realm +mainland +knit +appalling +exchanges +surgeon +crews +orientation +twisted +occupy +flame +hatred +exceed +Maurice +laboratories +reviews +Bosnia +agreed +Butler +utility +conversations +imaginative +pursuing +flour +accepted +wartime +governing +Reid +object +cutting +indirectly +governed +palestinian +vocational +von +modification +slopes +allegedly +parade +free +aluminium +Al +movies +biscuits +motive +register +merchants +hip +print +rabbits +remedies +stress +trainer +welcome +wound +Geneva +configuration +boost +puzzled +encounter +axis +no matter how +Clive +worldwide +Arnold +Allan +lamb +laser +vegetation +reluctance +jazz +databases +strengthened +protocol +enjoyment +organisational +knitting +census +calculate +handicapped +mucosa +theirs +1951 +advertisements +eldest +Carol +1936 +eventual +husbands +fur +followers +wasted +pump +lifting +practised +yacht +toes +stimulate +speeches +1953 +traced +ensured +arrow +journals +weekends +spontaneous +appoint +1949 +binding +superintendent +vivid +corporations +organisms +celebrated +mice +motives +torn +tie +dies +1954 +waiting +classified +organs +lack +worlds +nineteenth-century +faithful +shield +withdrew +reckoned +north-west +rolling +missiles +noisy +hire +organising +quote +sofa +reminder +Venice +ministerial +A +daylight +injection +graph +exchanged +prayers +boost +preparations +borrowing +innovative +strongest +audiences +disclosure +confrontation +constitutes +burnt +liaison +armies +strangely +wounds +Hewlett-Packard +controlled +Newman +cease +incentives +extends +Mitchell +echoed +facilitate +resentment +shout +cage +gloves +1990s +exploring +saving +Leonard +crossing +choir +Gibson +exit +Sydney +assumes +woodland +fog +underneath +promises +Ellen +nationalism +Kenya +commentators +Ferguson +metals +reasoning +acids +hunt +pop +1946 +dirt +Texas +Keynes +conceptual +aiming +stating +technically +heading +economically +constituted +Union +maker +blowing +touching +tours +erected +ambitions +spare +chorus +Bond +bladder +settings +dividends +18th +Gaulle +unusually +phases +adapt +colitis +exploded +Nelson +civic +bells +gall +Macdonald +unwilling +retreat +booklet +enforce +defining +goodbye +meaningful +Gregory +pine +borrowed +bow +disturbing \ No newline at end of file diff --git a/setup/src/Magento/Setup/Model/Complex/Pattern.php b/setup/src/Magento/Setup/Model/Complex/Pattern.php index ee1356ff4d174ea03ad144d2db8b2b6a2ed951d7..a6569b3657de9373b4d459650087a9b177ef5658 100644 --- a/setup/src/Magento/Setup/Model/Complex/Pattern.php +++ b/setup/src/Magento/Setup/Model/Complex/Pattern.php @@ -104,7 +104,7 @@ class Pattern foreach ($this->getHeaders() as $key) { if (isset($row[$key])) { if (is_callable($row[$key])) { - $row[$key] = call_user_func($row[$key], $index); + $row[$key] = call_user_func($row[$key], $index, $generatorKey); } else { $row[$key] = str_replace('%s', $index, $row[$key]); } diff --git a/setup/src/Magento/Setup/Model/DataGenerator.php b/setup/src/Magento/Setup/Model/DataGenerator.php new file mode 100644 index 0000000000000000000000000000000000000000..7ea52bdb26aea5067d98726c52aab00ad8366d6b --- /dev/null +++ b/setup/src/Magento/Setup/Model/DataGenerator.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * A custom adapter that allows generating arbitrary descriptions + */ +namespace Magento\Setup\Model; + +class DataGenerator +{ + /** + * Location for dictionary file. + * + * @var string + */ + private $dictionaryFile; + + /** + * Dictionary data. + * + * @var array + */ + private $dictionaryData; + + /** + * Map of generated values + * + * @var array + */ + private $generatedValues; + + /** + * DataGenerator constructor. + * + * @param string $dictionaryFile + */ + public function __construct($dictionaryFile) + { + $this->dictionaryFile = $dictionaryFile; + $this->readData(); + $this->generatedValues = []; + } + + /** + * Read data from file. + * + * @return void + */ + protected function readData() + { + $f = fopen($this->dictionaryFile, 'r'); + while (!feof($f) && is_array($line = fgetcsv($f))) { + $this->dictionaryData[] = $line[0]; + } + } + + /** + * Generate string of random word data. + * + * @param int $minAmountOfWords + * @param int $maxAmountOfWords + * @param string|null $key + * @return string + */ + public function generate($minAmountOfWords, $maxAmountOfWords, $key = null) + { + $numberOfWords = mt_rand($minAmountOfWords, $maxAmountOfWords); + $result = ''; + + if ($key === null || !array_key_exists($key, $this->generatedValues)) { + for ($i = 0; $i < $numberOfWords; $i++) { + $result .= ' ' . $this->dictionaryData[mt_rand(0, count($this->dictionaryData) - 1)]; + } + $result = trim($result); + + if ($key !== null) { + $this->generatedValues[$key] = $result; + } + } else { + $result = $this->generatedValues[$key]; + } + return $result; + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/AttributeSetsFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/AttributeSetsFixtureTest.php new file mode 100644 index 0000000000000000000000000000000000000000..674f444fbde10666b75aa5dadfef3719e3177152 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/AttributeSetsFixtureTest.php @@ -0,0 +1,288 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Test\Unit\Fixtures; + +use \Magento\Setup\Fixtures\AttributeSetsFixture; + +/** + * @SuppressWarnings(PHPMD) + */ +class AttributeSetsFixtureTest extends \PHPUnit_Framework_TestCase +{ + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Fixtures\FixtureModel + */ + private $fixtureModelMock; + + /** + * @var \Magento\Setup\Fixtures\AttributeSetsFixture + */ + private $model; + + public function setUp() + { + $this->fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new AttributeSetsFixture($this->fixtureModelMock); + } + + public function testExecute() + { + $attributeSets = [ + 'attribute_set' => [ + [ + 'name' => 'attribute set name', + 'attributes' => [ + 'attribute' => [ + [ + 'is_required' => 1, + 'is_visible_on_front' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'default_value' => 'yellow1', + 'attribute_code' => 'mycolor', + 'is_searchable' => '1', + 'frontend_label' => 'mycolor', + 'frontend_input' => 'select', + 'options' => [ + 'option' => [ + [ + 'label' => 'yellow1', + 'value' => '' + ] + ] + ] + ] + ] + ] + ] + ] + ]; + $attributeSet = $attributeSets['attribute_set'][0]; + + // Mock Attribute Sets + $attributeSetMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeSetInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeSetMock->expects($this->once()) + ->method('setAttributeSetName') + ->with("attribute set name"); + $attributeSetMock->expects($this->once()) + ->method('setEntityTypeId') + ->with(\Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE); + $attributeSetMock->expects($this->any()) + ->method('getAttributeSetName') + ->willReturn($attributeSet['name']); + + $attributeSetFactoryMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeSetInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $attributeSetFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($attributeSetMock); + + $attributeSetManagementMock = $this->getMockBuilder(\Magento\Catalog\Api\AttributeSetManagementInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeSetManagementMock->expects($this->once()) + ->method('create') + ->with($attributeSetMock, '4') + ->willReturn($attributeSetMock); + + //Mock Attribute Groups + $attributeGroupMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeGroupInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeGroupMock->expects($this->once()) + ->method('setAttributeGroupName') + ->with($attributeSetMock->getAttributeSetName() . ' - Group'); + $attributeGroupMock->expects($this->once()) + ->method('setAttributeSetId') + ->with($attributeSetMock->getAttributeSetId()); + + $attributeGroupFactoryMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeGroupInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $attributeGroupFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($attributeGroupMock); + + $productAttributeGroupRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeGroupRepoMock->expects($this->once()) + ->method('save') + ->with($attributeGroupMock) + ->willReturn($attributeGroupMock); + + // Mock Attributes + $attributeMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductAttributeInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $attributeFactoryMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $attributeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($attributeMock); + + //Mock Attribute Options + $optionMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeOptionInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $optionFactoryMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeOptionInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $optionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($optionMock); + + $productAttributeRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeRepoMock->expects($this->once()) + ->method('save') + ->with($attributeMock) + ->willReturn($attributeMock); + + $productAttributeManagementMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeManagementInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeManagementMock->expects($this->once()) + ->method('assign') + ->willReturn($attributeMock->getAttributeId()); + + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerMock->expects($this->at(0)) + ->method('create') + ->willReturn($attributeSetManagementMock); + $objectManagerMock->expects($this->at(1)) + ->method('create') + ->willReturn($productAttributeGroupRepoMock); + $objectManagerMock->expects($this->at(2)) + ->method('create') + ->willReturn($attributeSetFactoryMock); + $objectManagerMock->expects($this->at(3)) + ->method('create') + ->willReturn($attributeGroupFactoryMock); + $objectManagerMock->expects($this->at(4)) + ->method('create') + ->willReturn($productAttributeRepoMock); + $objectManagerMock->expects($this->at(5)) + ->method('create') + ->willReturn($productAttributeManagementMock); + $objectManagerMock->expects($this->at(6)) + ->method('create') + ->willReturn($attributeFactoryMock); + $objectManagerMock->expects($this->at(7)) + ->method('create') + ->willReturn($optionFactoryMock); + + $this->fixtureModelMock + ->expects($this->once()) + ->method('getValue') + ->willReturn($attributeSets); + + $this->fixtureModelMock + ->expects($this->any()) + ->method('getObjectManager') + ->will($this->returnValue($objectManagerMock)); + + $this->model->execute(); + } + + public function testNoFixtureConfigValue() + { + $attributeSetManagementMock = $this->getMockBuilder(\Magento\Catalog\Api\AttributeSetManagementInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeSetManagementMock->expects($this->never())->method('create'); + + $productAttributeGroupRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeGroupRepoMock->expects($this->never())->method('save'); + + $productAttributeRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeRepoMock->expects($this->never())->method('save'); + + $productAttributeManagementMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeManagementInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeManagementMock->expects($this->never())->method('assign'); + + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\AttributeSetManagementInterface::class)) + ->willReturn($attributeSetManagementMock); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class)) + ->willReturn($productAttributeGroupRepoMock); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\ProductAttributeRepositoryInterface::class)) + ->willReturn($productAttributeRepoMock); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\ProductAttributeManagementInterface::class)) + ->willReturn($productAttributeManagementMock); + + $this->fixtureModelMock + ->expects($this->never()) + ->method('getObjectManager') + ->will($this->returnValue($objectManagerMock)); + $this->fixtureModelMock + ->expects($this->once()) + ->method('getValue') + ->willReturn(null); + + $this->model->execute(); + } + + public function testGetActionTitle() + { + $this->assertSame('Generating attribute sets', $this->model->getActionTitle()); + } + + public function testIntroduceParamLabels() + { + $this->assertSame([ + 'attribute_sets' => 'Attribute Sets' + ], $this->model->introduceParamLabels()); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php index 7e89f7d807ed8704156fcffd5252185c0a2e0e54..7f2676c53e232ef152b9ad23a990b40f891e7115 100644 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/ConfigurableProductsFixtureTest.php @@ -23,16 +23,25 @@ class ConfigurableProductsFixtureTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->fixtureModelMock = $this->getMock(\Magento\Setup\Fixtures\FixtureModel::class, [], [], '', false); + $this->fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); $this->model = new ConfigurableProductsFixture($this->fixtureModelMock); } + /** + * @SuppressWarnings(PHPMD) + */ public function testExecute() { - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); - $contextMock = $this->getMock(\Magento\Framework\Model\ResourceModel\Db\Context::class, [], [], '', false); + $contextMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\Context::class) + ->disableOriginalConstructor() + ->getMock(); $abstractDbMock = $this->getMockForAbstractClass( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, [$contextMock], @@ -46,7 +55,9 @@ class ConfigurableProductsFixtureTest extends \PHPUnit_Framework_TestCase ->method('getAllChildren') ->will($this->returnValue([1])); - $categoryMock = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false); + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); $categoryMock->expects($this->once()) ->method('getResource') ->will($this->returnValue($abstractDbMock)); @@ -60,12 +71,16 @@ class ConfigurableProductsFixtureTest extends \PHPUnit_Framework_TestCase ->method('load') ->willReturnSelf(); - $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) + ->disableOriginalConstructor() + ->getMock(); $storeMock->expects($this->once()) ->method('getRootCategoryId') ->will($this->returnValue([2])); - $websiteMock = $this->getMock(\Magento\Store\Model\Website::class, [], [], '', false); + $websiteMock = $this->getMockBuilder(\Magento\Store\Model\Website::class) + ->disableOriginalConstructor() + ->getMock(); $websiteMock->expects($this->once()) ->method('getCode') ->will($this->returnValue('website_code')); @@ -73,15 +88,18 @@ class ConfigurableProductsFixtureTest extends \PHPUnit_Framework_TestCase ->method('getGroups') ->will($this->returnValue([$storeMock])); - $storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); + $storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManager::class) + ->disableOriginalConstructor() + ->getMock(); $storeManagerMock->expects($this->once()) ->method('getWebsites') ->will($this->returnValue([$websiteMock])); $source = $this->getMockBuilder(Generator::class)->disableOriginalConstructor()->getMock(); - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); - + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); $objectManagerMock->expects($this->at(0)) ->method('get') ->with(\Magento\Store\Model\StoreManager::class) @@ -103,14 +121,61 @@ class ConfigurableProductsFixtureTest extends \PHPUnit_Framework_TestCase $importMock->expects($this->once())->method('validateSource')->with($source)->willReturn(1); $importMock->expects($this->once())->method('importSource')->willReturn(1); + $valuesMap = [ + ['configurable_products', 0, 1], + ['simple_products', 0, 1], + ['search_terms', null, ['search_term' =>[['term' => 'iphone 6', 'count' => '1']]]], + ['configurable_products_variation', 3, 1], + [ + 'search_config', + null, + [ + 'max_amount_of_words_description' => '200', + 'max_amount_of_words_short_description' => '20', + 'min_amount_of_words_description' => '20', + 'min_amount_of_words_short_description' => '5' + ] + ], + ['attribute_sets', + null, + [ + 'attribute_set' => [ + [ + 'name' => 'attribute set name', + 'attributes' => [ + 'attribute' => [ + [ + 'is_required' => 1, + 'is_visible_on_front' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'default_value' => 'yellow1', + 'attribute_code' => 'mycolor', + 'is_searchable' => '1', + 'frontend_label' => 'mycolor', + 'frontend_input' => 'select', + 'options' => [ + 'option' => [ + [ + 'label' => 'yellow1', + 'value' => '' + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + $this->fixtureModelMock ->expects($this->any()) ->method('getValue') - ->willReturnMap([ - ['configurable_products', 0, 1], - ['configurable_products_variation', 3, 1], - ]); - + ->will($this->returnValueMap($valuesMap)); $this->fixtureModelMock ->expects($this->atLeastOnce()) ->method('getObjectManager') @@ -121,11 +186,15 @@ class ConfigurableProductsFixtureTest extends \PHPUnit_Framework_TestCase public function testNoFixtureConfigValue() { - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); $importMock->expects($this->never())->method('validateSource'); $importMock->expects($this->never())->method('importSource'); - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); $objectManagerMock->expects($this->never()) ->method('create') ->with($this->equalTo(\Magento\ImportExport\Model\Import::class)) @@ -151,7 +220,7 @@ class ConfigurableProductsFixtureTest extends \PHPUnit_Framework_TestCase public function testIntroduceParamLabels() { $this->assertSame([ - 'configurable_products' => 'Configurable products', + 'configurable_products' => 'Configurable products' ], $this->model->introduceParamLabels()); } } diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/FixtureModelTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/FixtureModelTest.php index ee1369bd15d5a46f084a504fdfedbf61eb53f8bc..32b00312880dee07e0f172f97df4668596088abd 100644 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/FixtureModelTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/FixtureModelTest.php @@ -55,11 +55,19 @@ class FixtureModelTest extends \PHPUnit_Framework_TestCase false ); - $fileParserMock = $this->getMock(\Magento\Framework\Xml\Parser::class, ['load', 'xmlToArray'], [], '', false); - $fileParserMock->expects($this->once())->method('xmlToArray')->willReturn( + $fileParserMock = $this->getMock(\Magento\Framework\Xml\Parser::class, ['getDom', 'xmlToArray'], [], '', false); + $fileParserMock->expects($this->exactly(2))->method('xmlToArray')->willReturn( ['config' => [ 'profile' => ['some_key' => 'some_value']]] ); - $fileParserMock->expects($this->once())->method('load')->with('config.file')->willReturn($fileParserMock); + + $domMock = $this->getMock(\DOMDocument::class, ['load', 'xinclude'], [], '', false); + $domMock->expects($this->once())->method('load')->with('config.file')->willReturn( + $fileParserMock->xmlToArray() + ); + $domMock->expects($this->once())->method('xinclude'); + + $fileParserMock->expects($this->exactly(2))->method('getDom')->willReturn($domMock); + $this->model = new FixtureModel($reindexCommandMock, $fileParserMock); $this->model->loadConfig('config.file'); $this->assertSame('some_value', $this->model->getValue('some_key')); diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php index 913b2a1e3f02048ac4c61b894e287791ce421207..5e24863483992ce4ada367846fc9c3350a5082b7 100644 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/SimpleProductsFixtureTest.php @@ -22,19 +22,28 @@ class SimpleProductsFixtureTest extends \PHPUnit_Framework_TestCase public function setUp() { - $this->fixtureModelMock = $this->getMock(\Magento\Setup\Fixtures\FixtureModel::class, [], [], '', false); + $this->fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); $this->model = new SimpleProductsFixture($this->fixtureModelMock); } + /** + * @SuppressWarnings(PHPMD) + */ public function testExecute() { - $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) + ->disableOriginalConstructor() + ->getMock(); $storeMock->expects($this->once()) ->method('getRootCategoryId') ->willReturn(1); - $websiteMock = $this->getMock(\Magento\Store\Model\Website::class, [], [], '', false); + $websiteMock = $this->getMockBuilder(\Magento\Store\Model\Website::class) + ->disableOriginalConstructor() + ->getMock(); $websiteMock->expects($this->once()) ->method('getCode') ->willReturn('website_code'); @@ -42,14 +51,24 @@ class SimpleProductsFixtureTest extends \PHPUnit_Framework_TestCase ->method('getGroups') ->willReturn([$storeMock]); - $storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); + $storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManager::class) + ->disableOriginalConstructor() + ->getMock(); $storeManagerMock->expects($this->once()) ->method('getWebsites') ->willReturn([$websiteMock]); - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $source = $this->getMockBuilder(\Magento\Setup\Model\Generator::class)->disableOriginalConstructor()->getMock(); + + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); + $importMock->expects($this->once())->method('validateSource')->with($source)->willReturn(1); + $importMock->expects($this->once())->method('importSource')->willReturn(1); - $contextMock = $this->getMock(\Magento\Framework\Model\ResourceModel\Db\Context::class, [], [], '', false); + $contextMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\Context::class) + ->disableOriginalConstructor() + ->getMock(); $abstractDbMock = $this->getMockForAbstractClass( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, [$contextMock], @@ -63,7 +82,9 @@ class SimpleProductsFixtureTest extends \PHPUnit_Framework_TestCase ->method('getAllChildren') ->will($this->returnValue([1])); - $categoryMock = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false); + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); $categoryMock->expects($this->once()) ->method('getResource') ->willReturn($abstractDbMock); @@ -77,35 +98,81 @@ class SimpleProductsFixtureTest extends \PHPUnit_Framework_TestCase ->method('getName') ->willReturn('category_name'); - $valueMap = [ - [ - \Magento\ImportExport\Model\Import::class, - [ - 'data' => [ - 'entity' => 'catalog_product', - 'behavior' => 'append', - 'validation_strategy' => 'validation-stop-on-errors' - ] - ], - $importMock - ], - [\Magento\Store\Model\StoreManager::class, [], $storeManagerMock] - ]; - - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); - $objectManagerMock->expects($this->exactly(2)) + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock->expects($this->at(0)) ->method('create') - ->will($this->returnValueMap($valueMap)); - $objectManagerMock->expects($this->once()) + ->with(\Magento\Store\Model\StoreManager::class) + ->willReturn($storeManagerMock); + $objectManagerMock->expects($this->at(1)) ->method('get') ->willReturn($categoryMock); + $objectManagerMock->expects($this->at(2)) + ->method('create') + ->with(\Magento\Setup\Model\Generator::class) + ->willReturn($source); + $objectManagerMock->expects($this->at(3)) + ->method('create') + ->with(\Magento\ImportExport\Model\Import::class) + ->willReturn($importMock); + $valuesMap = [ + ['simple_products', 0, 1], + ['configurable_products', 0, 1], + ['search_terms', null, ['search_term' =>[['term' => 'iphone 6', 'count' => '1']]]], + [ + 'search_config', + null, + [ + 'max_amount_of_words_description' => '200', + 'max_amount_of_words_short_description' => '20', + 'min_amount_of_words_description' => '20', + 'min_amount_of_words_short_description' => '5' + ] + ], + [ + 'attribute_sets', + null, + [ + 'attribute_set' => [ + [ + 'name' => 'attribute set name', + 'attributes' => [ + 'attribute' => [ + [ + 'is_required' => 1, + 'is_visible_on_front' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'default_value' => 'yellow1', + 'attribute_code' => 'mycolor', + 'is_searchable' => '1', + 'frontend_label' => 'mycolor', + 'frontend_input' => 'select', + 'options' => [ + 'option' => [ + [ + 'label' => 'yellow1', + 'value' => '' + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; $this->fixtureModelMock - ->expects($this->once()) + ->expects($this->any()) ->method('getValue') - ->willReturn(1); + ->will($this->returnValueMap($valuesMap)); $this->fixtureModelMock - ->expects($this->exactly(3)) + ->expects($this->any()) ->method('getObjectManager') ->willReturn($objectManagerMock); @@ -114,11 +181,15 @@ class SimpleProductsFixtureTest extends \PHPUnit_Framework_TestCase public function testNoFixtureConfigValue() { - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); $importMock->expects($this->never())->method('validateSource'); $importMock->expects($this->never())->method('importSource'); - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); $objectManagerMock->expects($this->never()) ->method('create') ->with($this->equalTo(\Magento\ImportExport\Model\Import::class)) @@ -129,7 +200,7 @@ class SimpleProductsFixtureTest extends \PHPUnit_Framework_TestCase ->method('getObjectManager') ->will($this->returnValue($objectManagerMock)); $this->fixtureModelMock - ->expects($this->once()) + ->expects($this->any()) ->method('getValue') ->willReturn(false); diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Complex/PatternTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Complex/PatternTest.php index 4adac2b0fb0edadf4a22d36f4fcd6f44d5357e35..0123fcd8ca032a79ff0b4ff5616747d8fb517bc7 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Complex/PatternTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/Complex/PatternTest.php @@ -42,8 +42,8 @@ class PatternTest extends \PHPUnit_Framework_TestCase [ 'id' => '%s', 'name' => 'Static', - 'calculated' => function ($index) { - return $index * 10; + 'calculated' => function ($index, $generatedKey) { + return $index * 10 + $generatedKey; }, ], [ @@ -53,7 +53,7 @@ class PatternTest extends \PHPUnit_Framework_TestCase 'name' => 'yyy %s' ], ], - 'ecpectedCount' => 3, + 'expectedCount' => 3, 'expectedRowsResult' => [ ['id' => '1', 'name' => 'Static', 'calculated' => 10], ['id' => '', 'name' => 'xxx 1', 'calculated' => ''], @@ -68,7 +68,7 @@ class PatternTest extends \PHPUnit_Framework_TestCase 'calculated' => 'calc %s', ], ], - 'ecpectedCount' => 1, + 'expectedCount' => 1, 'expectedRowsResult' => [ ['id' => '1', 'name' => 'Dynamic 1', 'calculated' => 'calc 1'], ], diff --git a/setup/src/Magento/Setup/Test/Unit/Model/DataGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Model/DataGeneratorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..65f92488c1a62fc62a4f36be3d8140ffe118eecd --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Model/DataGeneratorTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Test\Unit\Model; + +use Magento\Setup\Model\DataGenerator; + +class DataGeneratorTest extends \PHPUnit_Framework_TestCase +{ + + const PATH_TO_CSV_FILE = '/_files/dictionary.csv'; + + /** + * @test + * + * @return void + */ + public function testGenerate() + { + $data = file(__DIR__ . self::PATH_TO_CSV_FILE); + $wordCount = count($data); + $model = new DataGenerator(__DIR__ . self::PATH_TO_CSV_FILE); + $result = $model->generate($wordCount, $wordCount); + + $found = false; + foreach ($data as $word) { + $found = (strpos($result, $word[0]) !== false) || $found; + } + $this->assertTrue($found); + $this->assertEquals($wordCount, count(explode(" ", $result))); + } + + public function testGenerateWithKey() + { + $key = 'generate-test'; + + $data = file(__DIR__ . self::PATH_TO_CSV_FILE); + $wordCount = mt_rand(1, count($data)); + $model = new DataGenerator(__DIR__ . self::PATH_TO_CSV_FILE); + $result = $model->generate($wordCount, $wordCount, $key); + + $foundResult = $model->generate($wordCount, $wordCount, $key); + + $this->assertEquals($wordCount, count(explode(" ", $result))); + $this->assertEquals($result, $foundResult); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/_files/dictionary.csv b/setup/src/Magento/Setup/Test/Unit/Model/_files/dictionary.csv new file mode 100644 index 0000000000000000000000000000000000000000..da9dfd0f0ca08670a550cbfcd2af61526f9eede1 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Model/_files/dictionary.csv @@ -0,0 +1,5 @@ +one +two +three +four +five \ No newline at end of file