From e89a604e1010c98e37956719db96416fec515a96 Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Fri, 6 Sep 2019 11:50:58 +0200 Subject: [PATCH 001/272] Fix return type --- .../Magento/Framework/Pricing/PriceCurrencyInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php index eb379b54d257f..72068586e3027 100644 --- a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php +++ b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php @@ -47,7 +47,7 @@ public function convertAndRound($amount, $scope = null, $currency = null, $preci * @param int $precision * @param null|string|bool|int|\Magento\Framework\App\ScopeInterface $scope * @param \Magento\Framework\Model\AbstractModel|string|null $currency - * @return float + * @return string */ public function format( $amount, From 098770d4dca34b3a5c10d3ed5f7bc27c12d3f20d Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <51681487+engcom-Foxtrot@users.noreply.github.com> Date: Mon, 9 Sep 2019 14:41:50 +0300 Subject: [PATCH 002/272] magento/magento2#24485: Static test fix. --- .../Magento/Framework/Pricing/PriceCurrencyInterface.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php index 72068586e3027..ab3d26f3e0c6c 100644 --- a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php +++ b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php @@ -13,9 +13,6 @@ */ interface PriceCurrencyInterface { - /** - * Default precision - */ const DEFAULT_PRECISION = 2; /** From cd3b244cf3140821ee34bb52fc1cf8259988386d Mon Sep 17 00:00:00 2001 From: Vinai Kopp Date: Mon, 2 Sep 2019 12:21:00 +0200 Subject: [PATCH 003/272] Allow construction of products with custom_attributes This patch does two things: 1. Currently it is not possible to pass an array with `custom_attributes` to the `\Magento\Catalog\Model\Product` constructor (it causes a fatal error). The reason is because the `filterCustomAttribute` and `eavConfig` arguments are assigned after the call to `parent::__construct`. However, the properties are used during the `parent::__construct` calls. The flow of execution is as follows: Product::__construct -> Catalog\Model\AbstractModel::__construct Catalog\Model\AbstractModel::__construct -> AbstractExtensibleModel::__construct AbstractExtensibleModel::__construct -> AbstractExtensibleModel::filterCustomAttributes AbstractExtensibleModel::filterCustomAttributes -> AbstractExtensibleModel::getCustomAttributesCodes ...which is overridden by Product::getCustomAttributesCodes getCustomAttributesCodes expectes the `filterCustomAttribute` and `eavConfig` properties to be set if `custom_attributes` are present in `$data`, but they are still null because the `Product::__construct` method has not yet completed. The fix this PR applies is to assign the properties before the call to `parent::__construct`. The bug and fix are covered by the integration test: `\Magento\Catalog\Model\ProductTest::testConstructionWithCustomAttributesMapInData` 2. The method `AbstractExtensibleModel::filterCustomAttribute` expects the `custom_attributes` in `$data` to be a simple map from codes to values, e.g. `['category_ids => '1,2']`. However, the method `\Magento\Framework\Reflection\DataObjectProcessor::buildOutputDataArray` generates a numerically indexed custom attributes array, where each custom attribute is a sub-array with a `attribute_code` and `value` record. This PR allows passing such an `custom_attributes` array into the `Product` model constructor. Currently it would be ignored, but with this patch the code checks if `custom_attributes` is numerically indexed, and if so, flattens the sub-arrays into the expected map format. To illustrate the difference of the `custom_attributes` array formats: Map: [ 'custom_attributes' => [ 'category_ids' => '1,2', 'tax_class_id' => '3', ] ] Numerically indexed array of sub-arrays: [ 'custom_attributes' => [ [ 'attribute_code' => 'category_ids', 'value' => '1,2' ], [ 'attribute_code' => 'tax_class_id', 'value' => '3' ], ] ] This improvement is covered by the integration test `\Magento\Catalog\Model\ProductTest::testConstructionWithCustomAttributesArrayInData` --- app/code/Magento/Catalog/Model/Product.php | 19 +++---- .../Magento/Catalog/Model/ProductTest.php | 54 ++++++++++++++++--- .../Model/AbstractExtensibleModel.php | 29 +++++++++- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index 1b7552c82276d..2f3c219d66cbb 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -472,6 +472,9 @@ public function __construct( $this->mediaGalleryEntryConverterPool = $mediaGalleryEntryConverterPool; $this->dataObjectHelper = $dataObjectHelper; $this->joinProcessor = $joinProcessor; + $this->eavConfig = $config ?? ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class); + $this->filterCustomAttribute = $filterCustomAttribute + ?? ObjectManager::getInstance()->get(FilterProductCustomAttribute::class); parent::__construct( $context, $registry, @@ -482,9 +485,6 @@ public function __construct( $resourceCollection, $data ); - $this->eavConfig = $config ?? ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class); - $this->filterCustomAttribute = $filterCustomAttribute - ?? ObjectManager::getInstance()->get(FilterProductCustomAttribute::class); } /** @@ -835,12 +835,13 @@ public function getStoreIds() if (!$this->isObjectNew() && $this->_storeManager->isSingleStoreMode()) { $websiteIds = array_keys($websiteIds); } - foreach ($websiteIds as $websiteId) { - $websiteStores = $this->_storeManager->getWebsite($websiteId)->getStoreIds(); - foreach ($websiteStores as $websiteStore) { - $storeIds []= $websiteStore; - } - } + $websiteStoreIds = array_map( + function ($websiteId): array { + return $this->_storeManager->getWebsite($websiteId)->getStoreIds(); + }, + $websiteIds + ); + $storeIds = array_merge($storeIds, ...$websiteStoreIds); } $this->setStoreIds($storeIds); } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php index c34120404a950..0754ec0c06633 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductTest.php @@ -8,7 +8,9 @@ namespace Magento\Catalog\Model; +use Magento\Eav\Model\Config as EavConfig; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\TestFramework\ObjectManager; /** * Tests product model: @@ -49,8 +51,8 @@ protected function setUp() } /** - * @throws \Magento\Framework\Exception\FileSystemException * @return void + * @throws \Magento\Framework\Exception\FileSystemException */ public static function tearDownAfterClass() { @@ -307,9 +309,9 @@ public function testIsSalable() $this->_model = $this->productRepository->get('simple'); // fixture - $this->assertTrue((bool)$this->_model->isSalable()); - $this->assertTrue((bool)$this->_model->isSaleable()); - $this->assertTrue((bool)$this->_model->isAvailable()); + $this->assertTrue((bool) $this->_model->isSalable()); + $this->assertTrue((bool) $this->_model->isSaleable()); + $this->assertTrue((bool) $this->_model->isAvailable()); $this->assertTrue($this->_model->isInStock()); } @@ -324,9 +326,9 @@ public function testIsNotSalableWhenStatusDisabled() $this->_model = $this->productRepository->get('simple'); $this->_model->setStatus(0); - $this->assertFalse((bool)$this->_model->isSalable()); - $this->assertFalse((bool)$this->_model->isSaleable()); - $this->assertFalse((bool)$this->_model->isAvailable()); + $this->assertFalse((bool) $this->_model->isSalable()); + $this->assertFalse((bool) $this->_model->isSaleable()); + $this->assertFalse((bool) $this->_model->isAvailable()); $this->assertFalse($this->_model->isInStock()); } @@ -585,7 +587,7 @@ public function testGetOptions() continue; } foreach ($option->getValues() as $value) { - $this->assertEquals($expectedValue[$value->getSku()], (float)$value->getPrice()); + $this->assertEquals($expectedValue[$value->getSku()], (float) $value->getPrice()); } } } @@ -632,4 +634,40 @@ public function productWithBackordersDataProvider(): array [1, 1, true], ]; } + + public function testConstructionWithCustomAttributesMapInData() + { + $data = [ + 'custom_attributes' => [ + 'tax_class_id' => '3', + 'category_ids' => '1,2' + ], + ]; + + /** @var Product $product */ + $product = ObjectManager::getInstance()->create(Product::class, ['data' => $data]); + $this->assertSame($product->getCustomAttribute('tax_class_id')->getValue(), '3'); + $this->assertSame($product->getCustomAttribute('category_ids')->getValue(), '1,2'); + } + + public function testConstructionWithCustomAttributesArrayInData() + { + $data = [ + 'custom_attributes' => [ + [ + 'attribute_code' => 'tax_class_id', + 'value' => '3' + ], + [ + 'attribute_code' => 'category_ids', + 'value' => '1,2' + ] + ], + ]; + + /** @var Product $product */ + $product = ObjectManager::getInstance()->create(Product::class, ['data' => $data]); + $this->assertSame($product->getCustomAttribute('tax_class_id')->getValue(), '3'); + $this->assertSame($product->getCustomAttribute('category_ids')->getValue(), '1,2'); + } } diff --git a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php index 949e002a14208..b88954bd21ce8 100644 --- a/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php +++ b/lib/internal/Magento/Framework/Model/AbstractExtensibleModel.php @@ -74,6 +74,28 @@ public function __construct( } } + /** + * Convert the custom attributes array format to map format + * + * The method \Magento\Framework\Reflection\DataObjectProcessor::buildOutputDataArray generates a custom_attributes + * array representation where each custom attribute is a sub-array with a `attribute_code and value key. + * This method maps such an array to the plain code => value map format exprected by filterCustomAttributes + * + * @param array[] $customAttributesData + * @return array + */ + private function flattenCustomAttributesArrayToMap(array $customAttributesData): array + { + return array_reduce( + $customAttributesData, + function (array $acc, array $customAttribute): array { + $acc[$customAttribute['attribute_code']] = $customAttribute['value']; + return $acc; + }, + [] + ); + } + /** * Verify custom attributes set on $data and unset if not a valid custom attribute * @@ -85,9 +107,12 @@ protected function filterCustomAttributes($data) if (empty($data[self::CUSTOM_ATTRIBUTES])) { return $data; } - $customAttributesCodes = $this->getCustomAttributesCodes(); + if (isset($data[self::CUSTOM_ATTRIBUTES][0])) { + $data[self::CUSTOM_ATTRIBUTES] = $this->flattenCustomAttributesArrayToMap($data[self::CUSTOM_ATTRIBUTES]); + } + $customAttributesCodes = $this->getCustomAttributesCodes(); $data[self::CUSTOM_ATTRIBUTES] = array_intersect_key( - (array)$data[self::CUSTOM_ATTRIBUTES], + (array) $data[self::CUSTOM_ATTRIBUTES], array_flip($customAttributesCodes) ); foreach ($data[self::CUSTOM_ATTRIBUTES] as $code => $value) { From d56f3c6d908634dd71117f713c32cf7f5fa7e045 Mon Sep 17 00:00:00 2001 From: George Babarus Date: Fri, 5 Jul 2019 11:55:36 +0300 Subject: [PATCH 004/272] reduce resetData calls on DeploymentConfig --- .../Model/Logger/Handler/DebugTest.php | 1 + .../Framework/App/DeploymentConfig.php | 39 ++++--- .../App/Test/Unit/DeploymentConfigTest.php | 108 ++++++++++++------ .../Magento/Framework/Module/ModuleList.php | 19 +-- .../Module/Test/Unit/ModuleListTest.php | 8 +- .../ModuleEnableDisableCommandTest.php | 23 ++-- 6 files changed, 124 insertions(+), 74 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php index f7a47017f8b18..fec71206accd8 100644 --- a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php +++ b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php @@ -173,6 +173,7 @@ private function reinitDeploymentConfig() { $this->etcDirectory->delete(self::$configFile); $this->etcDirectory->copyFile(self::$backupFile, self::$configFile); + $this->deploymentConfig->resetData(); } /** diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig.php b/lib/internal/Magento/Framework/App/DeploymentConfig.php index 40b03b068d6ab..ddd7faa80b906 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig.php @@ -7,6 +7,9 @@ namespace Magento\Framework\App; use Magento\Framework\Config\ConfigOptionsListConstants; +use Magento\Framework\Exception\FileSystemException; +use Magento\Framework\Exception\RuntimeException; +use Magento\Framework\Phrase; /** * Application deployment configuration @@ -63,6 +66,8 @@ public function __construct(DeploymentConfig\Reader $reader, $overrideData = []) * @param string $key * @param mixed $defaultValue * @return mixed|null + * @throws FileSystemException + * @throws RuntimeException */ public function get($key = null, $defaultValue = null) { @@ -82,10 +87,11 @@ public function get($key = null, $defaultValue = null) * Checks if data available * * @return bool + * @throws FileSystemException + * @throws RuntimeException */ public function isAvailable() { - $this->data = null; $this->load(); return isset($this->flatData[ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE]); } @@ -95,6 +101,8 @@ public function isAvailable() * * @param string $key * @return null|mixed + * @throws FileSystemException + * @throws RuntimeException */ public function getConfigData($key = null) { @@ -104,11 +112,7 @@ public function getConfigData($key = null) return null; } - if (isset($this->data[$key])) { - return $this->data[$key]; - } - - return $this->data; + return $this->data[$key] ?? $this->data; } /** @@ -125,6 +129,8 @@ public function resetData() * Check if data from deploy files is available * * @return bool + * @throws FileSystemException + * @throws RuntimeException * @since 100.1.3 */ public function isDbAvailable() @@ -137,6 +143,8 @@ public function isDbAvailable() * Loads the configuration data * * @return void + * @throws FileSystemException + * @throws RuntimeException */ private function load() { @@ -158,12 +166,15 @@ private function load() * * @param array $params * @param string $path + * @param array $flattenResult * @return array - * @throws \Exception + * @throws RuntimeException */ - private function flattenParams(array $params, $path = null) + private function flattenParams(array $params, $path = null, array &$flattenResult = null) : array { - $cache = []; + if (null === $flattenResult) { + $flattenResult = []; + } foreach ($params as $key => $param) { if ($path) { @@ -171,15 +182,15 @@ private function flattenParams(array $params, $path = null) } else { $newPath = $key; } - if (isset($cache[$newPath])) { - throw new \Exception("Key collision {$newPath} is already defined."); + if (isset($flattenResult[$newPath])) { + throw new RuntimeException(new Phrase("Key collision '%1' is already defined.", [$newPath])); } - $cache[$newPath] = $param; + $flattenResult[$newPath] = $param; if (is_array($param)) { - $cache = array_merge($cache, $this->flattenParams($param, $newPath)); + $this->flattenParams($param, $newPath, $flattenResult); } } - return $cache; + return $flattenResult; } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php index 80ab2302dc91c..81a4f842bdf1d 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfigTest.php @@ -14,27 +14,33 @@ class DeploymentConfigTest extends \PHPUnit\Framework\TestCase /** * @var array */ - private static $fixture = [ - 'configData1' => 'scalar_value', - 'configData2' => [ - 'foo' => 1, - 'bar' => ['baz' => 2], - ], - ]; + private static $fixture + = [ + 'configData1' => 'scalar_value', + 'configData2' => [ + 'foo' => 1, + 'bar' => ['baz' => 2], + ], + 'configData3' => null, + 'test_override' => 'original', + ]; /** * @var array */ - private static $flattenedFixture = [ - 'configData1' => 'scalar_value', - 'configData2' => [ - 'foo' => 1, - 'bar' => ['baz' => 2], - ], - 'configData2/foo' => 1, - 'configData2/bar' => ['baz' => 2], - 'configData2/bar/baz' => 2, - ]; + private static $flattenedFixture + = [ + 'configData1' => 'scalar_value', + 'configData2' => [ + 'foo' => 1, + 'bar' => ['baz' => 2], + ], + 'configData2/foo' => 1, + 'configData2/bar' => ['baz' => 2], + 'configData2/bar/baz' => 2, + 'configData3' => null, + 'test_override' => 'overridden', + ]; /** * @var array @@ -63,21 +69,24 @@ class DeploymentConfigTest extends \PHPUnit\Framework\TestCase public static function setUpBeforeClass() { - self::$fixtureConfig = require __DIR__ . '/_files/config.php'; - self::$fixtureConfigMerged = require __DIR__ . '/_files/other/local_developer_merged.php'; + self::$fixtureConfig = require __DIR__.'/_files/config.php'; + self::$fixtureConfigMerged = require __DIR__.'/_files/other/local_developer_merged.php'; } protected function setUp() { - $this->reader = $this->createMock(\Magento\Framework\App\DeploymentConfig\Reader::class); - $this->_deploymentConfig = new \Magento\Framework\App\DeploymentConfig($this->reader, []); + $this->reader = $this->createMock(\Magento\Framework\App\DeploymentConfig\Reader::class); + $this->_deploymentConfig = new \Magento\Framework\App\DeploymentConfig( + $this->reader, + ['test_override' => 'overridden'] + ); $this->_deploymentConfigMerged = new \Magento\Framework\App\DeploymentConfig( $this->reader, - require __DIR__ . '/_files/other/local_developer.php' + require __DIR__.'/_files/other/local_developer.php' ); } - public function testGetters() + public function testGetters(): void { $this->reader->expects($this->once())->method('load')->willReturn(self::$fixture); $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get()); @@ -85,33 +94,40 @@ public function testGetters() $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get()); $this->assertSame('scalar_value', $this->_deploymentConfig->getConfigData('configData1')); $this->assertSame(self::$fixture['configData2'], $this->_deploymentConfig->getConfigData('configData2')); + $this->assertSame(self::$fixture['configData3'], $this->_deploymentConfig->getConfigData('configData3')); + $this->assertSame('', $this->_deploymentConfig->get('configData3')); + $this->assertSame('defaultValue', $this->_deploymentConfig->get('invalid_key', 'defaultValue')); + $this->assertNull($this->_deploymentConfig->getConfigData('invalid_key')); + $this->assertSame('overridden', $this->_deploymentConfig->get('test_override')); } - public function testIsAvailable() + public function testIsAvailable(): void { - $this->reader->expects($this->once())->method('load')->willReturn([ - ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE => 1 - ]); + $this->reader->expects($this->once())->method('load')->willReturn( + [ + ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE => 1, + ] + ); $object = new DeploymentConfig($this->reader); $this->assertTrue($object->isAvailable()); } - public function testNotAvailable() + public function testNotAvailable(): void { $this->reader->expects($this->once())->method('load')->willReturn([]); $object = new DeploymentConfig($this->reader); $this->assertFalse($object->isAvailable()); } - public function testNotAvailableThenAvailable() + /** + * test if the configuration changes during the same request, the configuration remain the same + */ + public function testNotAvailableThenAvailable(): void { - $this->reader->expects($this->at(0))->method('load')->willReturn([]); - $this->reader->expects($this->at(1))->method('load')->willReturn([ - ConfigOptionsListConstants::CONFIG_PATH_INSTALL_DATE => 1 - ]); + $this->reader->expects($this->once())->method('load')->willReturn([]); $object = new DeploymentConfig($this->reader); $this->assertFalse($object->isAvailable()); - $this->assertTrue($object->isAvailable()); + $this->assertFalse($object->isAvailable()); } /** @@ -120,7 +136,7 @@ public function testNotAvailableThenAvailable() * @expectedExceptionMessage Key collision * @dataProvider keyCollisionDataProvider */ - public function testKeyCollision(array $data) + public function testKeyCollision(array $data): void { $this->reader->expects($this->once())->method('load')->willReturn($data); $object = new DeploymentConfig($this->reader); @@ -130,14 +146,32 @@ public function testKeyCollision(array $data) /** * @return array */ - public function keyCollisionDataProvider() + public function keyCollisionDataProvider(): array { return [ [ ['foo' => ['bar' => '1'], 'foo/bar' => '2'], ['foo/bar' => '1', 'foo' => ['bar' => '2']], ['foo' => ['subfoo' => ['subbar' => '1'], 'subfoo/subbar' => '2'], 'bar' => '3'], - ] + ], ]; } + + public function testResetData(): void + { + $this->reader->expects($this->exactly(2))->method('load')->willReturn(self::$fixture); + $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get()); + $this->_deploymentConfig->resetData(); + // second time to ensure loader will be invoked only once after reset + $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get()); + $this->assertSame(self::$flattenedFixture, $this->_deploymentConfig->get()); + } + + public function testIsDbAvailable(): void + { + $this->reader->expects($this->exactly(2))->method('load')->willReturnOnConsecutiveCalls([], ['db' => []]); + $this->assertFalse($this->_deploymentConfig->isDbAvailable()); + $this->_deploymentConfig->resetData(); + $this->assertTrue($this->_deploymentConfig->isDbAvailable()); + } } diff --git a/lib/internal/Magento/Framework/Module/ModuleList.php b/lib/internal/Magento/Framework/Module/ModuleList.php index 6ee061cffb3d0..5a60a1c102b05 100644 --- a/lib/internal/Magento/Framework/Module/ModuleList.php +++ b/lib/internal/Magento/Framework/Module/ModuleList.php @@ -59,7 +59,7 @@ public function __construct(DeploymentConfig $config, ModuleList\Loader $loader) } /** - * {@inheritdoc} + * @inheritdoc * * Note that this triggers loading definitions of all existing modules in the system. * Use this method only when you actually need modules' declared meta-information. @@ -84,8 +84,7 @@ public function getAll() } /** - * {@inheritdoc} - * @see has() + * @inheritdoc */ public function getOne($name) { @@ -94,7 +93,7 @@ public function getOne($name) } /** - * {@inheritdoc} + * @inheritdoc */ public function getNames() { @@ -107,7 +106,7 @@ public function getNames() } /** - * {@inheritdoc} + * @inheritdoc */ public function has($name) { @@ -136,12 +135,16 @@ public function isModuleInfoAvailable() * Loads configuration data only * * @return void + * @throws \Magento\Framework\Exception\FileSystemException + * @throws \Magento\Framework\Exception\RuntimeException */ private function loadConfigData() { - $this->config->resetData(); - if (null === $this->configData && null !== $this->config->get(ConfigOptionsListConstants::KEY_MODULES)) { - $this->configData = $this->config->get(ConfigOptionsListConstants::KEY_MODULES); + if (null === $this->configData) { + $this->config->resetData(); + if (null !== $this->config->get(ConfigOptionsListConstants::KEY_MODULES)) { + $this->configData = $this->config->get(ConfigOptionsListConstants::KEY_MODULES); + } } } } diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/ModuleListTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/ModuleListTest.php index 9b4f238725138..3142bbbc6771a 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/ModuleListTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/ModuleListTest.php @@ -47,7 +47,7 @@ protected function setUp() public function testGetAll() { - $this->config->expects($this->exactly(2))->method('resetData'); + $this->config->expects($this->once())->method('resetData'); $this->setLoadAllExpectation(); $this->setLoadConfigExpectation(); $expected = ['foo' => self::$allFixture['foo']]; @@ -65,7 +65,7 @@ public function testGetAllNoData() public function testGetOne() { - $this->config->expects($this->exactly(2))->method('resetData'); + $this->config->expects($this->once())->method('resetData'); $this->setLoadAllExpectation(); $this->setLoadConfigExpectation(); $this->assertSame(['key' => 'value'], $this->model->getOne('foo')); @@ -74,7 +74,7 @@ public function testGetOne() public function testGetNames() { - $this->config->expects($this->exactly(2))->method('resetData'); + $this->config->expects($this->once())->method('resetData'); $this->setLoadAllExpectation(false); $this->setLoadConfigExpectation(); $this->assertSame(['foo'], $this->model->getNames()); @@ -83,7 +83,7 @@ public function testGetNames() public function testHas() { - $this->config->expects($this->exactly(2))->method('resetData'); + $this->config->expects($this->once())->method('resetData'); $this->setLoadAllExpectation(false); $this->setLoadConfigExpectation(); $this->assertTrue($this->model->has('foo')); diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php index 4ff2b0c7bca58..8eb13a9c1ec5e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleEnableDisableCommandTest.php @@ -53,23 +53,24 @@ protected function setUp() { $this->objectManagerProviderMock = $this->createMock(\Magento\Setup\Model\ObjectManagerProvider::class); $objectManager = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class); - $this->objectManagerProviderMock->expects($this->any()) + $this->objectManagerProviderMock ->method('get') - ->will($this->returnValue($objectManager)); + ->willReturn($objectManager); $this->statusMock = $this->createMock(\Magento\Framework\Module\Status::class); $this->cacheMock = $this->createMock(\Magento\Framework\App\Cache::class); $this->cleanupFilesMock = $this->createMock(\Magento\Framework\App\State\CleanupFiles::class); $this->fullModuleListMock = $this->createMock(\Magento\Framework\Module\FullModuleList::class); $this->deploymentConfigMock = $this->createMock(\Magento\Framework\App\DeploymentConfig::class); $this->generatedFiles = $this->createMock(\Magento\Framework\Code\GeneratedFiles::class); - $objectManager->expects($this->any()) - ->method('get') - ->will($this->returnValueMap([ - [\Magento\Framework\Module\Status::class, $this->statusMock], - [\Magento\Framework\App\Cache::class, $this->cacheMock], - [\Magento\Framework\App\State\CleanupFiles::class, $this->cleanupFilesMock], - [\Magento\Framework\Module\FullModuleList::class, $this->fullModuleListMock], - ])); + $objectManager->method('get') + ->willReturnMap( + [ + [\Magento\Framework\Module\Status::class, $this->statusMock], + [\Magento\Framework\App\Cache::class, $this->cacheMock], + [\Magento\Framework\App\State\CleanupFiles::class, $this->cleanupFilesMock], + [\Magento\Framework\Module\FullModuleList::class, $this->fullModuleListMock], + ] + ); } /** @@ -189,7 +190,7 @@ public function testExecuteAll($isEnable, $expectedMessage) if ($isEnable) { $this->deploymentConfigMock->expects($this->once()) ->method('isAvailable') - ->willReturn(['Magento_Module1']); + ->willReturn(true); } else { $this->deploymentConfigMock->expects($this->never()) ->method('isAvailable'); From 2769f7c8d8caa58fab0f1e6c6f27879859d1b573 Mon Sep 17 00:00:00 2001 From: Jens Scherbl Date: Sun, 22 Sep 2019 15:13:39 +0200 Subject: [PATCH 005/272] Allows additional payment checks in payment method list --- app/code/Magento/Payment/Model/MethodList.php | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Payment/Model/MethodList.php b/app/code/Magento/Payment/Model/MethodList.php index 5a426d72e4cfd..e5b961f87e426 100644 --- a/app/code/Magento/Payment/Model/MethodList.php +++ b/app/code/Magento/Payment/Model/MethodList.php @@ -39,16 +39,24 @@ class MethodList */ private $paymentMethodInstanceFactory; + /** + * @var array + */ + private $additionalChecks; + /** * @param \Magento\Payment\Helper\Data $paymentHelper - * @param Checks\SpecificationFactory $specificationFactory + * @param Checks\SpecificationFactory $specificationFactory + * @param array $additionalChecks */ public function __construct( \Magento\Payment\Helper\Data $paymentHelper, - \Magento\Payment\Model\Checks\SpecificationFactory $specificationFactory + \Magento\Payment\Model\Checks\SpecificationFactory $specificationFactory, + array $additionalChecks = [] ) { $this->paymentHelper = $paymentHelper; $this->methodSpecificationFactory = $specificationFactory; + $this->additionalChecks = $additionalChecks; } /** @@ -80,12 +88,15 @@ public function getAvailableMethods(\Magento\Quote\Api\Data\CartInterface $quote protected function _canUseMethod($method, \Magento\Quote\Api\Data\CartInterface $quote) { return $this->methodSpecificationFactory->create( - [ - AbstractMethod::CHECK_USE_CHECKOUT, - AbstractMethod::CHECK_USE_FOR_COUNTRY, - AbstractMethod::CHECK_USE_FOR_CURRENCY, - AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX, - ] + array_merge( + [ + AbstractMethod::CHECK_USE_CHECKOUT, + AbstractMethod::CHECK_USE_FOR_COUNTRY, + AbstractMethod::CHECK_USE_FOR_CURRENCY, + AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX, + ], + $this->additionalChecks + ) )->isApplicable( $method, $quote From 882868a5c33712691a79f62dfdf05459427cc31d Mon Sep 17 00:00:00 2001 From: Jens Scherbl Date: Sun, 22 Sep 2019 16:34:48 +0200 Subject: [PATCH 006/272] Fixes unrelated code style issues --- app/code/Magento/Payment/Model/MethodList.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Payment/Model/MethodList.php b/app/code/Magento/Payment/Model/MethodList.php index e5b961f87e426..746306cbd0bbf 100644 --- a/app/code/Magento/Payment/Model/MethodList.php +++ b/app/code/Magento/Payment/Model/MethodList.php @@ -60,6 +60,8 @@ public function __construct( } /** + * Returns all available payment methods for the given quote. + * * @param \Magento\Quote\Api\Data\CartInterface $quote * @return \Magento\Payment\Model\MethodInterface[] */ From 91d61bdc5e5b85dcc5b51f7b539055e187a16790 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Tue, 24 Sep 2019 17:01:57 +0300 Subject: [PATCH 007/272] magento/magento2#24460: Multiline custom attributes save fix. --- .../Model/Address/AbstractAddress.php | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index 158461b4d9c17..fb067decd0b37 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -281,7 +281,13 @@ public function setData($key, $value = null) $key = $this->_implodeArrayField($key); } elseif (is_array($value) && $this->isAddressMultilineAttribute($key)) { $value = $this->_implodeArrayValues($value); + } elseif (self::CUSTOM_ATTRIBUTES === $key && is_array($value)) { + foreach ($value as &$attribute) { + $attribute = is_array($attribute) ? $attribute : $attribute->__toArray(); + $attribute = $this->processCustomAttribute($attribute); + } } + return parent::setData($key, $value); } @@ -637,8 +643,8 @@ public function unsRegion() * Is company required * * @return bool - * @since 100.2.0 * @throws \Magento\Framework\Exception\LocalizedException + * @since 100.2.0 */ protected function isCompanyRequired() { @@ -649,8 +655,8 @@ protected function isCompanyRequired() * Is telephone required * * @return bool - * @since 100.2.0 * @throws \Magento\Framework\Exception\LocalizedException + * @since 100.2.0 */ protected function isTelephoneRequired() { @@ -661,11 +667,30 @@ protected function isTelephoneRequired() * Is fax required * * @return bool - * @since 100.2.0 * @throws \Magento\Framework\Exception\LocalizedException + * @since 100.2.0 */ protected function isFaxRequired() { return ($this->_eavConfig->getAttribute('customer_address', 'fax')->getIsRequired()); } + + /** + * Unify attribute format. + * + * @param array $attribute + * @return array + */ + private function processCustomAttribute(array $attribute): array + { + if (isset($attribute['attribute_code']) && + isset($attribute['value']) && + is_array($attribute['value']) && + $this->isAddressMultilineAttribute($attribute['attribute_code']) + ) { + $attribute['value'] = $this->_implodeArrayValues($attribute['value']); + } + + return $attribute; + } } From 738792efa1feb761dc4e9d5b6d8da3f7298db33c Mon Sep 17 00:00:00 2001 From: Andrey Nikolaev Date: Fri, 25 Oct 2019 08:51:32 +0300 Subject: [PATCH 008/272] Add lib wrapper for UUID validation. --- app/etc/di.xml | 1 + .../DataObject/IdentityValidator.php | 23 +++++++++++++++++++ .../DataObject/IdentityValidatorInterface.php | 21 +++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 lib/internal/Magento/Framework/DataObject/IdentityValidator.php create mode 100644 lib/internal/Magento/Framework/DataObject/IdentityValidatorInterface.php diff --git a/app/etc/di.xml b/app/etc/di.xml index f8818de2af842..27b85f0a924c0 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -167,6 +167,7 @@ + diff --git a/lib/internal/Magento/Framework/DataObject/IdentityValidator.php b/lib/internal/Magento/Framework/DataObject/IdentityValidator.php new file mode 100644 index 0000000000000..0aeb16dfbd9bd --- /dev/null +++ b/lib/internal/Magento/Framework/DataObject/IdentityValidator.php @@ -0,0 +1,23 @@ + Date: Sun, 27 Oct 2019 12:39:20 +0300 Subject: [PATCH 009/272] Declare strict types --- .../Magento/Framework/DataObject/IdentityValidator.php | 4 +++- .../Framework/DataObject/IdentityValidatorInterface.php | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/DataObject/IdentityValidator.php b/lib/internal/Magento/Framework/DataObject/IdentityValidator.php index 0aeb16dfbd9bd..b17e04585531a 100644 --- a/lib/internal/Magento/Framework/DataObject/IdentityValidator.php +++ b/lib/internal/Magento/Framework/DataObject/IdentityValidator.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Framework\DataObject; use Ramsey\Uuid\Uuid; @@ -15,7 +17,7 @@ class IdentityValidator implements IdentityValidatorInterface /** * @inheritDoc */ - public function isValid($value) + public function isValid(string $value): bool { $isValid = Uuid::isValid($value); return $isValid; diff --git a/lib/internal/Magento/Framework/DataObject/IdentityValidatorInterface.php b/lib/internal/Magento/Framework/DataObject/IdentityValidatorInterface.php index fd8b835665baf..a1979721f0cc9 100644 --- a/lib/internal/Magento/Framework/DataObject/IdentityValidatorInterface.php +++ b/lib/internal/Magento/Framework/DataObject/IdentityValidatorInterface.php @@ -15,7 +15,7 @@ interface IdentityValidatorInterface * * @param string $value * - * @return string + * @return bool */ - public function isValid($value); + public function isValid(string $value): bool; } From bf87df0b47014a7c083ff8fd4a3f6b4e0c157a61 Mon Sep 17 00:00:00 2001 From: Andrey Nikolaev Date: Sun, 27 Oct 2019 17:59:07 +0300 Subject: [PATCH 010/272] Cover identity validator with integration tests --- .../DataObject/IdentityValidatorTest.php | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/DataObject/IdentityValidatorTest.php diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/IdentityValidatorTest.php b/dev/tests/integration/testsuite/Magento/Framework/DataObject/IdentityValidatorTest.php new file mode 100644 index 0000000000000..15f54ba01a795 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/DataObject/IdentityValidatorTest.php @@ -0,0 +1,41 @@ +identityValidator = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(IdentityValidator::class); + } + + public function testIsValid() + { + $isValid = $this->identityValidator->isValid(self::VALID_UUID); + $this->assertEquals(true, $isValid); + } + + public function testIsNotValid() + { + $isValid = $this->identityValidator->isValid(self::INVALID_UUID); + $this->assertEquals(false, $isValid); + } + + public function testEmptyValue() + { + $isValid = $this->identityValidator->isValid(''); + $this->assertEquals(false, $isValid); + } +} From b6bd937a8276924191c8bf753889941636cecd2d Mon Sep 17 00:00:00 2001 From: Raul Verdugo Date: Sun, 27 Oct 2019 16:56:56 +0100 Subject: [PATCH 011/272] #13865 create a popup to advice about navigator blocked cookies --- .../frontend/layout/default_head_blocks.xml | 1 + .../Theme/view/frontend/requirejs-config.js | 3 +- .../frontend/templates/js/cookie_status.phtml | 20 ++++++++++ .../view/frontend/web/js/cookie-status.js | 38 +++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml create mode 100644 app/code/Magento/Theme/view/frontend/web/js/cookie-status.js diff --git a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml index ab4dabfa6d1a0..a4a10ef3f6ee9 100644 --- a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml +++ b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml @@ -23,6 +23,7 @@ + diff --git a/app/code/Magento/Theme/view/frontend/requirejs-config.js b/app/code/Magento/Theme/view/frontend/requirejs-config.js index c41a0602ef3e8..b5ffd358c893b 100644 --- a/app/code/Magento/Theme/view/frontend/requirejs-config.js +++ b/app/code/Magento/Theme/view/frontend/requirejs-config.js @@ -30,7 +30,8 @@ var config = { 'welcome': 'Magento_Theme/js/view/welcome', 'breadcrumbs': 'Magento_Theme/js/view/breadcrumbs', 'criticalCssLoader': 'Magento_Theme/js/view/critical-css-loader', - 'jquery/ui': 'jquery/compat' + 'jquery/ui': 'jquery/compat', + 'cookieStatus': 'Magento_Theme/js/cookie-status' } }, deps: [ diff --git a/app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml b/app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml new file mode 100644 index 0000000000000..833daf43a4570 --- /dev/null +++ b/app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/app/code/Magento/Theme/view/frontend/web/js/cookie-status.js b/app/code/Magento/Theme/view/frontend/web/js/cookie-status.js new file mode 100644 index 0000000000000..f736d4366440c --- /dev/null +++ b/app/code/Magento/Theme/view/frontend/web/js/cookie-status.js @@ -0,0 +1,38 @@ +define([ + 'jquery', + 'mage/translate', + 'Magento_Ui/js/modal/modal' +], function($, $tr, modal){ + 'use strict'; + + $.widget('mage.cookieStatus', { + /** + * Init object + * @private + */ + _init: function () { + + if(!navigator.cookieEnabled) { + console.log('popup'); + + const options = { + type: 'popup', + responsive: true, + innerScroll: true, + autoOpen: true, + buttons: [{ + text: $.mage.__('Close'), + class: 'cookie-status', + click: function () { + this.closeModal(); + } + }] + }; + + modal(options, $('#cookie-status')); + } + } + }); + + return $.mage.cookieStatus; +}); \ No newline at end of file From 7e527d8706a4590075219fb10080e009d8da3422 Mon Sep 17 00:00:00 2001 From: Raul Verdugo Date: Sun, 27 Oct 2019 17:01:15 +0100 Subject: [PATCH 012/272] #13865 remove console log --- app/code/Magento/Theme/view/frontend/web/js/cookie-status.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/Theme/view/frontend/web/js/cookie-status.js b/app/code/Magento/Theme/view/frontend/web/js/cookie-status.js index f736d4366440c..20090bc67befc 100644 --- a/app/code/Magento/Theme/view/frontend/web/js/cookie-status.js +++ b/app/code/Magento/Theme/view/frontend/web/js/cookie-status.js @@ -13,8 +13,6 @@ define([ _init: function () { if(!navigator.cookieEnabled) { - console.log('popup'); - const options = { type: 'popup', responsive: true, From 60117ee2523187a546cf0aee5b1c4d1ef8ee49b8 Mon Sep 17 00:00:00 2001 From: Raul Verdugo Date: Tue, 29 Oct 2019 12:53:51 +0100 Subject: [PATCH 013/272] #13865 add scapeHtml to popup text --- .../Theme/view/frontend/templates/js/cookie_status.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml b/app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml index 833daf43a4570..2da71c90b5657 100644 --- a/app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/js/cookie_status.phtml @@ -6,7 +6,7 @@ ?>