diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 54208dcdba534..ceb5580307c22 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1416,7 +1416,7 @@ protected function initMediaGalleryResources() } /** - * Get existing images for current bucnh + * Get existing images for current bunch * * @param array $bunch * @return array @@ -1436,7 +1436,21 @@ protected function getExistingImages($bunch) )->joinInner( ['mgvte' => $this->mediaGalleryEntityToValueTableName], '(mg.value_id = mgvte.value_id)', - [$this->getProductEntityLinkField() => 'mgvte.' . $this->getProductEntityLinkField()] + [ + $this->getProductEntityLinkField() => 'mgvte.' . $this->getProductEntityLinkField(), + 'value_id' => 'mgvte.value_id' + ] + )->joinLeft( + ['mgv' => $this->mediaGalleryValueTableName], + sprintf( + '(mg.value_id = mgv.value_id AND mgv.%s = mgvte.%s AND mgv.store_id = %d)', + $this->getProductEntityLinkField(), + $this->getProductEntityLinkField(), + \Magento\Store\Model\Store::DEFAULT_STORE_ID + ), + [ + 'label' => 'mgv.label' + ] )->joinInner( ['pe' => $this->productEntityTableName], "(mgvte.{$this->getProductEntityLinkField()} = pe.{$this->getProductEntityLinkField()})", @@ -1447,7 +1461,7 @@ protected function getExistingImages($bunch) ); foreach ($this->_connection->fetchAll($select) as $image) { - $result[$image['sku']][$image['value']] = true; + $result[$image['sku']][$image['value']] = $image; } return $result; @@ -1462,22 +1476,21 @@ public function getImagesFromRow(array $rowData) $images = []; $labels = []; foreach ($this->_imagesArrayKeys as $column) { - $images[$column] = []; - $labels[$column] = []; if (!empty($rowData[$column])) { $images[$column] = array_unique( - explode($this->getMultipleValueSeparator(), $rowData[$column]) + array_map( + 'trim', + explode($this->getMultipleValueSeparator(), $rowData[$column]) + ) ); - } - if (!empty($rowData[$column . '_label'])) { - $labels[$column] = explode($this->getMultipleValueSeparator(), $rowData[$column . '_label']); - } + if (!empty($rowData[$column . '_label'])) { + $labels[$column] = $this->parseMultipleValues($rowData[$column . '_label']); - if (count($labels[$column]) > count($images[$column])) { - $labels[$column] = array_slice($labels[$column], 0, count($images[$column])); - } elseif (count($labels[$column]) < count($images[$column])) { - $labels[$column] = array_pad($labels[$column], count($images[$column]), ''); + if (count($labels[$column]) > count($images[$column])) { + $labels[$column] = array_slice($labels[$column], 0, count($images[$column])); + } + } } } @@ -1507,6 +1520,7 @@ protected function _saveProducts() $this->categoriesCache = []; $tierPrices = []; $mediaGallery = []; + $labelsForUpdate = []; $uploadedImages = []; $previousType = null; $prevAttributeSet = null; @@ -1616,7 +1630,7 @@ protected function _saveProducts() foreach ($rowImages as $column => $columnImages) { foreach ($columnImages as $position => $columnImage) { if (!isset($uploadedImages[$columnImage])) { - $uploadedFile = $this->uploadMediaFiles(trim($columnImage), true); + $uploadedFile = $this->uploadMediaFiles($columnImage, true); if ($uploadedFile) { $uploadedImages[$columnImage] = $uploadedFile; } else { @@ -1636,20 +1650,28 @@ protected function _saveProducts() $rowData[$column] = $uploadedFile; } - $imageNotAssigned = !isset($existingImages[$rowSku][$uploadedFile]); - - if ($uploadedFile && $imageNotAssigned) { - if ($column == self::COL_MEDIA_IMAGE) { - $rowData[$column][] = $uploadedFile; + if ($uploadedFile && !isset($mediaGallery[$rowSku][$uploadedFile])) { + if (isset($existingImages[$rowSku][$uploadedFile])) { + if (isset($rowLabels[$column][$position]) + && $rowLabels[$column][$position] != $existingImages[$rowSku][$uploadedFile]['label'] + ) { + $labelsForUpdate[] = [ + 'label' => $rowLabels[$column][$position], + 'imageData' => $existingImages[$rowSku][$uploadedFile] + ]; + } + } else { + if ($column == self::COL_MEDIA_IMAGE) { + $rowData[$column][] = $uploadedFile; + } + $mediaGallery[$rowSku][$uploadedFile] = [ + 'attribute_id' => $this->getMediaGalleryAttributeId(), + 'label' => isset($rowLabels[$column][$position]) ? $rowLabels[$column][$position] : '', + 'position' => $position + 1, + 'disabled' => isset($disabledImages[$columnImage]) ? '1' : '0', + 'value' => $uploadedFile, + ]; } - $mediaGallery[$rowSku][] = [ - 'attribute_id' => $this->getMediaGalleryAttributeId(), - 'label' => isset($rowLabels[$column][$position]) ? $rowLabels[$column][$position] : '', - 'position' => $position + 1, - 'disabled' => isset($disabledImages[$columnImage]) ? '1' : '0', - 'value' => $uploadedFile, - ]; - $existingImages[$rowSku][$uploadedFile] = true; } } } @@ -1767,6 +1789,8 @@ protected function _saveProducts() $mediaGallery )->_saveProductAttributes( $attributes + )->updateMediaGalleryLabels( + $labelsForUpdate ); $this->_eventManager->dispatch( @@ -2535,12 +2559,13 @@ private function parseAttributesWithWrappedValues($attributesData) * Parse values of multiselect attributes depends on "Fields Enclosure" parameter * * @param string $values + * @param string $delimiter * @return array */ - public function parseMultiselectValues($values) + public function parseMultiselectValues($values, $delimiter = self::PSEUDO_MULTI_LINE_SEPARATOR) { if (empty($this->_parameters[Import::FIELDS_ENCLOSURE])) { - return explode(self::PSEUDO_MULTI_LINE_SEPARATOR, $values); + return explode($delimiter, $values); } if (preg_match_all('~"((?:[^"]|"")*)"~', $values, $matches)) { return $values = array_map(function ($value) { @@ -2752,4 +2777,64 @@ private function getProductIdentifierField() } return $this->productEntityIdentifierField; } + + /** + * Update media gallery labels + * + * @param array $labels + * @return void + */ + private function updateMediaGalleryLabels(array $labels) + { + if (empty($labels)) { + return; + } + + $insertData = []; + foreach ($labels as $label) { + $imageData = $label['imageData']; + + if ($imageData['label'] === null) { + $insertData[] = [ + 'label' => $label['label'], + $this->getProductEntityLinkField() => $imageData[$this->getProductEntityLinkField()], + 'value_id' => $imageData['value_id'], + 'store_id' => \Magento\Store\Model\Store::DEFAULT_STORE_ID + ]; + } else { + $this->_connection->update( + $this->mediaGalleryValueTableName, + [ + 'label' => $label['label'] + ], + [ + $this->getProductEntityLinkField() . ' = ?' => $imageData[$this->getProductEntityLinkField()], + 'value_id = ?' => $imageData['value_id'], + 'store_id = ?' => \Magento\Store\Model\Store::DEFAULT_STORE_ID + ] + ); + } + } + + if (!empty($insertData)) { + $this->_connection->insertMultiple( + $this->mediaGalleryValueTableName, + $insertData + ); + } + } + + /** + * Parse values from multiple attributes fields + * + * @param string $labelRow + * @return array + */ + private function parseMultipleValues($labelRow) + { + return $this->parseMultiselectValues( + $labelRow, + $this->getMultipleValueSeparator() + ); + } } diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php index 0b728ee503887..3067aa3c2b2eb 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php @@ -5,7 +5,6 @@ */ namespace Magento\CatalogImportExport\Model\Import\Product\Validator; -use Magento\CatalogImportExport\Model\Import\Product\Validator\AbstractImportValidator; use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface; class Media extends AbstractImportValidator implements RowValidatorInterface @@ -16,19 +15,15 @@ class Media extends AbstractImportValidator implements RowValidatorInterface const ADDITIONAL_IMAGES = 'additional_images'; + /** + * @deprecated + * @see \Magento\CatalogImportExport\Model\Import\Product::getMultipleValueSeparator() + */ const ADDITIONAL_IMAGES_DELIMITER = ','; /** @var array */ protected $mediaAttributes = ['image', 'small_image', 'thumbnail']; - /** - * {@inheritdoc} - */ - public function init($context) - { - return parent::init($context); - } - /** * @param string $string * @return bool @@ -83,7 +78,7 @@ public function isValid($value) } } if (isset($value[self::ADDITIONAL_IMAGES]) && strlen($value[self::ADDITIONAL_IMAGES])) { - foreach (explode(self::ADDITIONAL_IMAGES_DELIMITER, $value[self::ADDITIONAL_IMAGES]) as $image) { + foreach (explode($this->context->getMultipleValueSeparator(), $value[self::ADDITIONAL_IMAGES]) as $image) { if (!$this->checkPath($image) && !$this->checkValidUrl($image)) { $this->_addMessages( [ diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php index a4a937f25cf81..df7b33c72995b 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Validator/MediaTest.php @@ -6,11 +6,14 @@ namespace Magento\CatalogImportExport\Test\Unit\Model\Import\Product\Validator; +use Magento\CatalogImportExport\Model\Import\Product; +use Magento\CatalogImportExport\Model\Import\Product\Validator\Media; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\ImportExport\Model\Import; class MediaTest extends \PHPUnit_Framework_TestCase { - /** @var \Magento\CatalogImportExport\Model\Import\Product\Validator\Media */ + /** @var Media */ protected $media; /** @var ObjectManagerHelper */ @@ -21,7 +24,7 @@ protected function setUp() $this->objectManagerHelper = new ObjectManagerHelper($this); $this->media = $this->objectManagerHelper->getObject( - \Magento\CatalogImportExport\Model\Import\Product\Validator\Media::class, + Media::class, [ ] @@ -41,6 +44,18 @@ public function testInit() */ public function testIsValid($data, $expected) { + $contextMock = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->getMock(); + $contextMock->expects($this->any()) + ->method('getMultipleValueSeparator') + ->willReturn(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR); + $contextMock->expects($this->any()) + ->method('retrieveMessageTemplate') + ->with(Media::ERROR_INVALID_MEDIA_URL_OR_PATH) + ->willReturn('%s'); + $this->media->init($contextMock); + $result = $this->media->isValid($data); $this->assertEquals($expected['result'], $result); $messages = $this->media->getMessages(); @@ -50,7 +65,7 @@ public function testIsValid($data, $expected) public function testIsValidClearMessagesCall() { $media = $this->getMock( - \Magento\CatalogImportExport\Model\Import\Product\Validator\Media::class, + Media::class, ['_clearMessages'], [], '', @@ -78,6 +93,14 @@ public function isMediaValidDataProvider() 'invalid' => [ ['_media_image' => 1], ['result' => true,'messages' => []], + ], + 'additional_images' => [ + ['additional_images' => 'image1.png,image2.jpg'], + ['result' => true, 'messages' => []] + ], + 'additional_images_fail' => [ + ['additional_images' => 'image1.png|image2.jpg|image3.gif'], + ['result' => false, 'messages' => [0 => 'additional_images']] ] ]; } diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php index bf9c694d949d4..cd1fedf82fe85 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/ProductTest.php @@ -1280,6 +1280,43 @@ public function testValidateValidateOptionEntity() $importProduct->validateRow($rowData, $rowNum); } + /** + * @dataProvider getImagesFromRowDataProvider + */ + public function testGetImagesFromRow($rowData, $expectedResult) + { + $this->assertEquals( + $this->importProduct->getImagesFromRow($rowData), + $expectedResult + ); + } + + public function getImagesFromRowDataProvider() + { + return [ + [ + [], + [[], []] + ], + [ + [ + 'image' => 'image3.jpg', + '_media_image' => 'image1.jpg,image2.png', + '_media_image_label' => 'label1,label2' + ], + [ + [ + 'image' => ['image3.jpg'], + '_media_image' => ['image1.jpg', 'image2.png'] + ], + [ + '_media_image' => ['label1', 'label2'] + ], + ] + ] + ]; + } + public function validateRowValidateNewProductTypeAddRowErrorCallDataProvider() { return [ diff --git a/app/code/Magento/Cms/Setup/UpgradeData.php b/app/code/Magento/Cms/Setup/UpgradeData.php index 41a28989439af..6d22f782b25b1 100644 --- a/app/code/Magento/Cms/Setup/UpgradeData.php +++ b/app/code/Magento/Cms/Setup/UpgradeData.php @@ -13,6 +13,9 @@ class UpgradeData implements UpgradeDataInterface { + /** + * @deprecated + */ const PRIVACY_COOKIE_PAGE_ID = 4; /** @@ -234,7 +237,10 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface EOD; - $privacyAndCookiePolicyPage = $this->createPage()->load(self::PRIVACY_COOKIE_PAGE_ID); + $privacyAndCookiePolicyPage = $this->createPage()->load( + 'privacy-policy-cookie-restriction-mode', + 'identifier' + ); $privacyAndCookiePolicyPageId = $privacyAndCookiePolicyPage->getId(); if ($privacyAndCookiePolicyPageId) { $privacyAndCookiePolicyPage->setContent($newPageContent); diff --git a/app/code/Magento/SampleData/Model/Dependency.php b/app/code/Magento/SampleData/Model/Dependency.php index 09f0c16aac848..2a1849364bd77 100644 --- a/app/code/Magento/SampleData/Model/Dependency.php +++ b/app/code/Magento/SampleData/Model/Dependency.php @@ -88,6 +88,10 @@ protected function getSuggestsFromModules() foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) { $file = $moduleDir . '/composer.json'; + if (!file_exists($file) || !is_readable($file)) { + continue; + } + /** @var Package $package */ $package = $this->getModuleComposerPackage($file); $suggest = json_decode(json_encode($package->get('suggest')), true); diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index d8b2189e9f0d2..c0e4541095271 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -568,52 +568,9 @@ protected function getOptionValues(\Magento\Catalog\Model\Product\Option $option */ public function testSaveMediaImage() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Framework\Filesystem::class); - $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); - - $source = $this->objectManager->create( - \Magento\ImportExport\Model\Import\Source\Csv::class, - [ - 'file' => __DIR__ . '/_files/import_media.csv', - 'directory' => $directory - ] - ); - $this->_model->setParameters( - [ - 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, - 'entity' => 'catalog_product', - 'import_images_file_dir' => 'pub/media/import' - ] - ); - $appParams = \Magento\TestFramework\Helper\Bootstrap::getInstance() - ->getBootstrap() - ->getApplication() - ->getInitParams()[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]; - $uploader = $this->_model->getUploader(); + $this->importDataForMediaTest('import_media.csv'); + $product = $this->getProductBySku('simple_new'); - $destDir = $directory->getRelativePath($appParams[DirectoryList::MEDIA][DirectoryList::PATH] . '/catalog/product'); - $tmpDir = $directory->getRelativePath($appParams[DirectoryList::MEDIA][DirectoryList::PATH] . '/import'); - - $directory->create($destDir); - $this->assertTrue($uploader->setDestDir($destDir)); - $this->assertTrue($uploader->setTmpDir($tmpDir)); - $errors = $this->_model->setSource( - $source - )->validateData(); - - $this->assertTrue($errors->getErrorsCount() == 0); - $this->_model->importData(); - $this->assertTrue($this->_model->getErrorAggregator()->getErrorsCount() == 0); - - $resource = $objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class); - $productId = $resource->getIdBySku('simple_new'); - - $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Product::class - ); - $product->load($productId); $this->assertEquals('/m/a/magento_image.jpg', $product->getData('swatch_image')); $gallery = $product->getMediaGalleryImages(); $this->assertInstanceOf(\Magento\Framework\Data\Collection::class, $gallery); @@ -625,6 +582,25 @@ public function testSaveMediaImage() $this->assertEquals('Image Label', $item->getLabel()); } + /** + * Test that image labels updates after import + * + * @magentoDataFixture mediaImportImageFixture + * @magentoDataFixture Magento/Catalog/_files/product_with_image.php + */ + public function testUpdateImageLabel() + { + $this->importDataForMediaTest('import_media_update_label.csv'); + $product = $this->getProductBySku('simple'); + + $gallery = $product->getMediaGalleryImages(); + $items = $gallery->getItems(); + $this->assertCount(1, $items); + $item = array_pop($items); + $this->assertInstanceOf(\Magento\Framework\DataObject::class, $item); + $this->assertEquals('Updated Image Label', $item->getLabel()); + } + /** * Copy a fixture image into media import directory */ @@ -1432,6 +1408,68 @@ public function testProductWithWrappedAdditionalAttributes() $product2->getData('multiselect_attribute')); } + /** + * Import and check data from file + * + * @param string $fileName + */ + private function importDataForMediaTest($fileName) + { + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/' . $fileName, + 'directory' => $directory + ] + ); + $this->_model->setParameters( + [ + 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, + 'entity' => 'catalog_product', + 'import_images_file_dir' => 'pub/media/import' + ] + ); + $appParams = \Magento\TestFramework\Helper\Bootstrap::getInstance() + ->getBootstrap() + ->getApplication() + ->getInitParams()[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]; + $uploader = $this->_model->getUploader(); + + $mediaPath = $appParams[DirectoryList::MEDIA][DirectoryList::PATH]; + $destDir = $directory->getRelativePath($mediaPath . '/catalog/product'); + $tmpDir = $directory->getRelativePath($mediaPath . '/import'); + + $directory->create($destDir); + $this->assertTrue($uploader->setDestDir($destDir)); + $this->assertTrue($uploader->setTmpDir($tmpDir)); + $errors = $this->_model->setSource( + $source + )->validateData(); + $this->assertTrue($errors->getErrorsCount() == 0); + + $this->_model->importData(); + $this->assertTrue($this->_model->getErrorAggregator()->getErrorsCount() == 0); + } + + /** + * Load product by given product sku + * + * @param string $sku + * @return \Magento\Catalog\Model\Product + */ + private function getProductBySku($sku) + { + $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class); + $productId = $resource->getIdBySku($sku); + $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class); + $product->load($productId); + + return $product; + } + /** * @param array $row * @param string|null $behavior diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_update_label.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_update_label.csv new file mode 100644 index 0000000000000..4e62e28af7ff3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_update_label.csv @@ -0,0 +1,2 @@ +sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus +simple,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,magento_image.jpg,,magento_image.jpg,,magento_image.jpg,,magento_image.jpg,,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,magento_image.jpg,Updated Image Label,,,,,,,, diff --git a/dev/tests/integration/testsuite/Magento/SampleData/Model/DependencyTest.php b/dev/tests/integration/testsuite/Magento/SampleData/Model/DependencyTest.php new file mode 100644 index 0000000000000..4ff9104cec879 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/Model/DependencyTest.php @@ -0,0 +1,73 @@ +composerInformationMock = $this->getMockBuilder(ComposerInformation::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $this->componentRegistrarMock = $this->getMockBuilder(ComponentRegistrar::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $objectManager->create( + \Magento\SampleData\Model\Dependency::class, + [ + 'composerInformation' => $this->composerInformationMock, + 'filesystem' => $objectManager->get(Filesystem::class), + 'packageFactory' => $objectManager->get(PackageFactory::class), + 'componentRegistrar' => $this->componentRegistrarMock + ] + ); + } + + public function testGetSampleDataPackages() + { + $this->composerInformationMock->expects($this->once()) + ->method('getSuggestedPackages') + ->willReturn([]); + $this->componentRegistrarMock->expects($this->once()) + ->method('getPaths') + ->with(ComponentRegistrar::MODULE) + ->willReturn([ + __DIR__ . '/../_files/Modules/FirstModule', + __DIR__ . '/../_files/Modules/SecondModule', + __DIR__ . '/../_files/Modules/ThirdModule', + __DIR__ . '/../_files/Modules/FourthModule' + ]); + + $this->assertSame( + ['magento/module-first-sample-data' => '777.7.*'], + $this->model->getSampleDataPackages() + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/FirstModule/composer.json b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/FirstModule/composer.json new file mode 100644 index 0000000000000..d3f063976ea91 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/FirstModule/composer.json @@ -0,0 +1,9 @@ +{ + "name": "magento/module-first", + "description": "N/A", + "suggest": { + "magento/module-first-sample-data": "Sample Data version:777.7.*" + }, + "type": "magento2-module", + "version": "777.7.7" +} diff --git a/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/SecondModule/composer.json b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/SecondModule/composer.json new file mode 100644 index 0000000000000..b9e027b7bb6f5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/SecondModule/composer.json @@ -0,0 +1,9 @@ +{ + "name": "magento/module-second", + "description": "N/A", + "suggest": { + "magento/module-some-module": "Some Module:888.8.*" + }, + "type": "magento2-module", + "version": "777.7.7" +} diff --git a/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/ThirdModule/composer.json b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/ThirdModule/composer.json new file mode 100644 index 0000000000000..2a0d642e8e282 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/ThirdModule/composer.json @@ -0,0 +1,6 @@ +{ + "name": "magento/module-second", + "description": "N/A", + "type": "magento2-module", + "version": "777.7.7" +} diff --git a/lib/internal/Magento/Framework/App/Http.php b/lib/internal/Magento/Framework/App/Http.php index b98998c55a401..e3de37bfc01f9 100644 --- a/lib/internal/Magento/Framework/App/Http.php +++ b/lib/internal/Magento/Framework/App/Http.php @@ -241,8 +241,7 @@ private function redirectToSetup(Bootstrap $bootstrap, \Exception $exception) . "because the Magento setup directory cannot be accessed. \n" . 'You can install Magento using either the command line or you must restore access ' . 'to the following directory: ' . $setupInfo->getDir($projectRoot) . "\n"; - $newMessage .= 'If you are using the sample nginx configuration, please go to ' - . $this->_request->getScheme(). '://' . $this->_request->getHttpHost() . $setupInfo->getUrl(); + throw new \Exception($newMessage, 0, $exception); } } diff --git a/lib/internal/Magento/Framework/App/SetupInfo.php b/lib/internal/Magento/Framework/App/SetupInfo.php index b52daaac333e8..731ec97ee7dd2 100644 --- a/lib/internal/Magento/Framework/App/SetupInfo.php +++ b/lib/internal/Magento/Framework/App/SetupInfo.php @@ -147,6 +147,14 @@ public function isAvailable() { $setupDir = $this->getDir($this->projectRoot); $isSubDir = false !== strpos($setupDir . '/', $this->docRoot . '/'); + // Setup is not accessible from pub folder + $setupDir = rtrim($setupDir, '/'); + $lastOccurrence = strrpos($setupDir, '/pub/setup'); + + if (false !== $lastOccurrence) { + $setupDir = substr_replace($setupDir, '/setup', $lastOccurrence, strlen('/pub/setup')); + } + return $isSubDir && realpath($setupDir); } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/SetupInfoTest.php b/lib/internal/Magento/Framework/App/Test/Unit/SetupInfoTest.php index 99ca759490f14..61f0a34d8a0d7 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/SetupInfoTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/SetupInfoTest.php @@ -193,6 +193,13 @@ public function isAvailableDataProvider() ], true ], + 'root within doc root + pub, existent sub-directory' => [ + [ + 'DOCUMENT_ROOT' => __DIR__ . '/_files/pub/', + 'SCRIPT_FILENAME' => __DIR__ . '/_files/pub/index.php', + ], + true + ], ]; } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/_files/pub/index.php b/lib/internal/Magento/Framework/App/Test/Unit/_files/pub/index.php new file mode 100644 index 0000000000000..2a0cd37c68d37 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/_files/pub/index.php @@ -0,0 +1,5 @@ + +SetHandler default-handler + + ############################################ diff --git a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php index bbd0a44254e89..ad2ad3d7b6969 100644 --- a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php +++ b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php @@ -71,7 +71,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $installer->installSchema(); $installer->installDataFixtures(); if (!$keepGenerated) { - $output->writeln('Please re-run Magento compile command'); + $output->writeln('Please re-run Magento compile command. Use the command "setup:di:compile"'); } return \Magento\Framework\Console\Cli::RETURN_SUCCESS; diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php index 6209df88bd5f0..dcbdc876db607 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php @@ -11,7 +11,12 @@ class UpgradeCommandTest extends \PHPUnit_Framework_TestCase { - public function testExecute() + /** + * @param array $options + * @param string $expectedString + * @dataProvider executeDataProvider + */ + public function testExecute($options = [], $expectedString = '') { $installerFactory = $this->getMock(\Magento\Setup\Model\InstallerFactory::class, [], [], '', false); $installer = $this->getMock(\Magento\Setup\Model\Installer::class, [], [], '', false); @@ -20,6 +25,25 @@ public function testExecute() $installer->expects($this->at(2))->method('installDataFixtures'); $installerFactory->expects($this->once())->method('create')->willReturn($installer); $commandTester = new CommandTester(new UpgradeCommand($installerFactory)); - $this->assertSame(Cli::RETURN_SUCCESS, $commandTester->execute([])); + $this->assertSame(Cli::RETURN_SUCCESS, $commandTester->execute($options)); + $this->assertEquals($expectedString, $commandTester->getDisplay()); + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + [ + 'options' => [], + 'expectedString' => 'Please re-run Magento compile command. Use the command "setup:di:compile"' + . PHP_EOL + ], + [ + 'options' => ['--keep-generated' => true], + 'expectedString' => '' + ], + ]; } }