diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 54208dcdba534139c96e8fd975e0757f9ecb11e1..ceb5580307c22e07486effd290c61e88f768c84a 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1416,7 +1416,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity } /** - * Get existing images for current bucnh + * Get existing images for current bunch * * @param array $bunch * @return array @@ -1436,7 +1436,21 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity )->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 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity ); 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 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity $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 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity $this->categoriesCache = []; $tierPrices = []; $mediaGallery = []; + $labelsForUpdate = []; $uploadedImages = []; $previousType = null; $prevAttributeSet = null; @@ -1616,7 +1630,7 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity 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 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity $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 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity $mediaGallery )->_saveProductAttributes( $attributes + )->updateMediaGalleryLabels( + $labelsForUpdate ); $this->_eventManager->dispatch( @@ -2535,12 +2559,13 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity * 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 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity } 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 0b728ee5038873ddbb7a56eab967fcdf53c6c419..3067aa3c2b2eb29eb032201b0c6d062ab54baa08 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 @@ class Media extends AbstractImportValidator implements RowValidatorInterface } } 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 a4a937f25cf81334e19ef1aa079c1d274f79bacd..df7b33c72995b1a7a78faa6f0d5d74daf7ce8a5e 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 @@ class MediaTest extends \PHPUnit_Framework_TestCase $this->objectManagerHelper = new ObjectManagerHelper($this); $this->media = $this->objectManagerHelper->getObject( - \Magento\CatalogImportExport\Model\Import\Product\Validator\Media::class, + Media::class, [ ] @@ -41,6 +44,18 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ 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 @@ class MediaTest extends \PHPUnit_Framework_TestCase public function testIsValidClearMessagesCall() { $media = $this->getMock( - \Magento\CatalogImportExport\Model\Import\Product\Validator\Media::class, + Media::class, ['_clearMessages'], [], '', @@ -78,6 +93,14 @@ class MediaTest extends \PHPUnit_Framework_TestCase '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 bf9c694d949d44709be47b73f08dd4eeb2c50c18..cd1fedf82fe85a4b0ea0b55ff056c38cd5ee8e4c 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 @@ class ProductTest extends \Magento\ImportExport\Test\Unit\Model\Import\AbstractI $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/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php index 21b085c4c419f0d03bcb72389627ec665582f298..cb30f7abc71792b72d0b78e24b4ba89e25303d67 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php @@ -42,13 +42,18 @@ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface /** * @param \Magento\Framework\Event\Observer $observer * @return void + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute(\Magento\Framework\Event\Observer $observer) { /** @var Category $category */ $category = $observer->getEvent()->getCategory(); if ($category->getUrlKey() !== false) { - $category->setUrlKey($this->categoryUrlPathGenerator->getUrlKey($category)) + $resultUrlKey = $this->categoryUrlPathGenerator->getUrlKey($category); + if (empty($resultUrlKey)) { + throw new \Magento\Framework\Exception\LocalizedException(__('Invalid URL key')); + } + $category->setUrlKey($resultUrlKey) ->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); if (!$category->isObjectNew()) { $category->getResource()->saveAttribute($category, 'url_path'); diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php b/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php index f2d10d59e02c499fca965ce2a38a03804adc3654..45a74260e927001bcf39148dc2f5d9a9574d0189 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php @@ -30,18 +30,38 @@ class Save extends \Magento\Backend\App\Action */ protected $dataPersistor; + /** + * @var \Magento\Cms\Model\PageFactory + */ + private $pageFactory; + + /** + * @var \Magento\Cms\Api\PageRepositoryInterface + */ + private $pageRepository; + /** * @param Action\Context $context * @param PostDataProcessor $dataProcessor * @param DataPersistorInterface $dataPersistor + * @param \Magento\Cms\Model\PageFactory $pageFactory + * @param \Magento\Cms\Api\PageRepositoryInterface $pageRepository + * */ public function __construct( Action\Context $context, PostDataProcessor $dataProcessor, - DataPersistorInterface $dataPersistor + DataPersistorInterface $dataPersistor, + \Magento\Cms\Model\PageFactory $pageFactory = null, + \Magento\Cms\Api\PageRepositoryInterface $pageRepository = null ) { $this->dataProcessor = $dataProcessor; $this->dataPersistor = $dataPersistor; + $this->pageFactory = $pageFactory + ?: \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Cms\Model\PageFactory::class); + $this->pageRepository = $pageRepository + ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Cms\Api\PageRepositoryInterface::class); parent::__construct($context); } @@ -66,7 +86,7 @@ class Save extends \Magento\Backend\App\Action } /** @var \Magento\Cms\Model\Page $model */ - $model = $this->_objectManager->create(\Magento\Cms\Model\Page::class); + $model = $this->pageFactory->create(); $id = $this->getRequest()->getParam('page_id'); if ($id) { @@ -85,7 +105,7 @@ class Save extends \Magento\Backend\App\Action } try { - $model->save(); + $this->pageRepository->save($model); $this->messageManager->addSuccess(__('You saved the page.')); $this->dataPersistor->clear('cms_page'); if ($this->getRequest()->getParam('back')) { diff --git a/app/code/Magento/Cms/Setup/UpgradeData.php b/app/code/Magento/Cms/Setup/UpgradeData.php index 41a28989439af2e9ae14fe270b603e7e8c254abb..6d22f782b25b130b0cca1174e5386e7fb92cd5a7 100644 --- a/app/code/Magento/Cms/Setup/UpgradeData.php +++ b/app/code/Magento/Cms/Setup/UpgradeData.php @@ -13,6 +13,9 @@ use Magento\Framework\Setup\UpgradeDataInterface; class UpgradeData implements UpgradeDataInterface { + /** + * @deprecated + */ const PRIVACY_COOKIE_PAGE_ID = 4; /** @@ -234,7 +237,10 @@ class UpgradeData implements UpgradeDataInterface </table> </div> 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/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php index 7495a2ad1bad924c241e9fae564785574f13a3a1..12057d2681c20cf8cbc5822d6180b9df96b095ee 100644 --- a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php +++ b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php @@ -13,73 +13,61 @@ class SaveTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $requestMock; + private $requestMock; /** * @var \Magento\Cms\Controller\Adminhtml\Page\PostDataProcessor|\PHPUnit_Framework_MockObject_MockObject */ - protected $dataProcessorMock; + private $dataProcessorMock; /** * @var \Magento\Framework\App\Request\DataPersistorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $dataPersistorMock; + private $dataPersistorMock; /** * @var \Magento\Backend\Model\View\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $resultRedirectFactory; + private $resultRedirectFactory; /** * @var \Magento\Backend\Model\View\Result\Redirect|\PHPUnit_Framework_MockObject_MockObject */ - protected $resultRedirect; + private $resultRedirect; /** - * @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject - */ - protected $contextMock; - - /** - * @var \Magento\Framework\ObjectManager\ObjectManager|\PHPUnit_Framework_MockObject_MockObject - */ - protected $objectManagerMock; - - /** - * @var \Magento\Cms\Model\Page|\PHPUnit_Framework_MockObject_MockObject $pageMock + * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $pageMock; + private $messageManagerMock; /** - * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $messageManagerMock; + private $eventManagerMock; /** - * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Cms\Model\PageFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $eventManagerMock; + private $pageFactory; /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + * @var \Magento\Cms\Api\PageRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $objectManager; + private $pageRepository; /** * @var \Magento\Cms\Controller\Adminhtml\Page\Save */ - protected $saveController; + private $saveController; /** * @var int */ - protected $pageId = 1; + private $pageId = 1; protected function setUp() { - $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - - $this->contextMock = $this->getMock(\Magento\Backend\App\Action\Context::class, [], [], '', false); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->resultRedirectFactory = $this->getMockBuilder(\Magento\Backend\Model\View\Result\RedirectFactory::class) ->disableOriginalConstructor() @@ -91,69 +79,37 @@ class SaveTest extends \PHPUnit_Framework_TestCase $this->resultRedirectFactory->expects($this->atLeastOnce()) ->method('create') ->willReturn($this->resultRedirect); - - $this->dataProcessorMock = $this->getMock( - \Magento\Cms\Controller\Adminhtml\Page\PostDataProcessor::class, - ['filter'], - [], - '', - false - ); - + $this->dataProcessorMock = $this->getMockBuilder( + \Magento\Cms\Controller\Adminhtml\Page\PostDataProcessor::class + )->setMethods(['filter'])->disableOriginalConstructor()->getMock(); $this->dataPersistorMock = $this->getMockBuilder(\Magento\Framework\App\Request\DataPersistorInterface::class) ->getMock(); - - $this->requestMock = $this->getMockForAbstractClass( - \Magento\Framework\App\RequestInterface::class, - [], - '', - false, - true, - true, - ['getParam', 'getPostValue'] - ); - - $this->pageMock = $this->getMockBuilder( - \Magento\Cms\Model\Page::class - )->disableOriginalConstructor()->getMock(); - - $this->messageManagerMock = $this->getMock( - \Magento\Framework\Message\ManagerInterface::class, - [], - [], - '', - false - ); - - $this->eventManagerMock = $this->getMockForAbstractClass( - \Magento\Framework\Event\ManagerInterface::class, - [], - '', - false, - true, - true, - ['dispatch'] - ); - - $this->objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->setMethods(['getParam', 'getPostValue']) + ->getMockForAbstractClass(); + $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) + ->getMockForAbstractClass(); + $this->eventManagerMock = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class) + ->setMethods(['dispatch']) + ->getMockForAbstractClass(); + $this->pageFactory = $this->getMockBuilder(\Magento\Cms\Model\PageFactory::class) ->disableOriginalConstructor() - ->setMethods(['get', 'create']) + ->setMethods(['create']) ->getMock(); - - $this->contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->any())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->any())->method('getEventManager')->willReturn($this->eventManagerMock); - $this->contextMock->expects($this->any()) - ->method('getResultRedirectFactory') - ->willReturn($this->resultRedirectFactory); - - $this->saveController = $this->objectManager->getObject( + $this->pageRepository = $this->getMockBuilder(\Magento\Cms\Api\PageRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->saveController = $objectManager->getObject( \Magento\Cms\Controller\Adminhtml\Page\Save::class, [ - 'context' => $this->contextMock, + 'request' => $this->requestMock, + 'messageManager' => $this->messageManagerMock, + 'eventManager' => $this->eventManagerMock, + 'resultRedirectFactory' => $this->resultRedirectFactory, 'dataProcessor' => $this->dataProcessorMock, 'dataPersistor' => $this->dataPersistorMock, + 'pageFactory' => $this->pageFactory, + 'pageRepository' => $this->pageRepository ] ); } @@ -190,20 +146,21 @@ class SaveTest extends \PHPUnit_Framework_TestCase ['back', null, false], ] ); - - $this->objectManagerMock->expects($this->atLeastOnce()) + $page = $this->getMockBuilder(\Magento\Cms\Model\Page::class) + ->disableOriginalConstructor() + ->getMock(); + $this->pageFactory->expects($this->atLeastOnce()) ->method('create') - ->with($this->equalTo(\Magento\Cms\Model\Page::class)) - ->willReturn($this->pageMock); + ->willReturn($page); - $this->pageMock->expects($this->any()) + $page->expects($this->any()) ->method('load') ->willReturnSelf(); - $this->pageMock->expects($this->any()) + $page->expects($this->any()) ->method('getId') ->willReturn(true); - $this->pageMock->expects($this->once())->method('setData'); - $this->pageMock->expects($this->once())->method('save'); + $page->expects($this->once())->method('setData'); + $this->pageRepository->expects($this->once())->method('save')->with($page); $this->dataPersistorMock->expects($this->any()) ->method('clear') @@ -240,20 +197,21 @@ class SaveTest extends \PHPUnit_Framework_TestCase $this->dataProcessorMock->expects($this->any()) ->method('filter') ->willReturnArgument(0); - - $this->objectManagerMock->expects($this->atLeastOnce()) + $page = $this->getMockBuilder(\Magento\Cms\Model\Page::class) + ->disableOriginalConstructor() + ->getMock(); + $this->pageFactory->expects($this->atLeastOnce()) ->method('create') - ->with($this->equalTo(\Magento\Cms\Model\Page::class)) - ->willReturn($this->pageMock); + ->willReturn($page); - $this->pageMock->expects($this->any()) + $page->expects($this->any()) ->method('load') ->willReturnSelf(); - $this->pageMock->expects($this->any()) + $page->expects($this->any()) ->method('getId') ->willReturn(true); - $this->pageMock->expects($this->once())->method('setData'); - $this->pageMock->expects($this->once())->method('save'); + $page->expects($this->once())->method('setData'); + $this->pageRepository->expects($this->once())->method('save')->with($page); $this->messageManagerMock->expects($this->once()) ->method('addSuccess') @@ -286,20 +244,22 @@ class SaveTest extends \PHPUnit_Framework_TestCase $this->dataProcessorMock->expects($this->any()) ->method('filter') ->willReturnArgument(0); - - $this->objectManagerMock->expects($this->atLeastOnce()) + $page = $this->getMockBuilder(\Magento\Cms\Model\Page::class) + ->disableOriginalConstructor() + ->getMock(); + $this->pageFactory->expects($this->atLeastOnce()) ->method('create') - ->with($this->equalTo(\Magento\Cms\Model\Page::class)) - ->willReturn($this->pageMock); + ->willReturn($page); - $this->pageMock->expects($this->any()) + $page->expects($this->any()) ->method('load') ->willReturnSelf(); - $this->pageMock->expects($this->any()) + $page->expects($this->any()) ->method('getId') ->willReturn(true); - $this->pageMock->expects($this->once())->method('setData'); - $this->pageMock->expects($this->once())->method('save')->willThrowException(new \Exception('Error message.')); + $page->expects($this->once())->method('setData'); + $this->pageRepository->expects($this->once())->method('save')->with($page) + ->willThrowException(new \Exception('Error message.')); $this->messageManagerMock->expects($this->never()) ->method('addSuccess'); diff --git a/app/code/Magento/CmsUrlRewrite/Test/Unit/Model/CmsPageUrlRewriteGeneratorTest.php b/app/code/Magento/CmsUrlRewrite/Test/Unit/Model/CmsPageUrlRewriteGeneratorTest.php new file mode 100644 index 0000000000000000000000000000000000000000..96a964c3d2d33aa7b0e49baec1db61666718a6a9 --- /dev/null +++ b/app/code/Magento/CmsUrlRewrite/Test/Unit/Model/CmsPageUrlRewriteGeneratorTest.php @@ -0,0 +1,133 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\CmsUrlRewrite\Test\Unit\Model; + + +class CmsPageUrlRewriteGeneratorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ + private $objectManager; + + /** + * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $storeManager; + + /** + * @var \Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $urlRewriteFactory; + + /** + * @var \Magento\CmsUrlRewrite\Model\CmsPageUrlPathGenerator|\PHPUnit_Framework_MockObject_MockObject + */ + private $urlPathGenerator; + + /** + * @var \Magento\CmsUrlRewrite\Model\CmsPageUrlRewriteGenerator + */ + private $urlRewriteGenerator; + + /** + * @return void + */ + protected function setUp() + { + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) + ->getMockForAbstractClass(); + $this->urlRewriteFactory = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->urlPathGenerator = $this->getMockBuilder(\Magento\CmsUrlRewrite\Model\CmsPageUrlPathGenerator::class) + ->disableOriginalConstructor() + ->getMock(); + $this->urlRewriteGenerator = $this->objectManager->getObject( + \Magento\CmsUrlRewrite\Model\CmsPageUrlRewriteGenerator::class, + [ + 'storeManager' => $this->storeManager, + 'urlRewriteFactory' => $this->urlRewriteFactory, + 'cmsPageUrlPathGenerator' => $this->urlPathGenerator + ] + ); + } + + public function testGenerateForAllStores() + { + $initializesStores = [0]; + $cmsPageId = 1; + $cmsPage = $this->getMockBuilder(\Magento\Cms\Model\Page::class) + ->disableOriginalConstructor() + ->getMock(); + $cmsPage->expects($this->any())->method('getStores')->willReturn($initializesStores); + $store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->setMethods(['getStoreId']) + ->getMockForAbstractClass(); + $this->storeManager->expects($this->any())->method('getStores')->willReturn([$store]); + $store->expects($this->any())->method('getStoreId')->willReturn($initializesStores[0]); + $urlRewrite = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class) + ->getMockForAbstractClass(); + $this->urlRewriteFactory->expects($this->any())->method('create')->willReturn($urlRewrite); + $cmsPage->expects($this->any())->method('getId')->willReturn($cmsPageId); + $cmsPage->expects($this->any())->method('getIdentifier')->willReturn('request_path'); + $this->urlPathGenerator->expects($this->any())->method('getCanonicalUrlPath')->with($cmsPage) + ->willReturn('cms/page/view/page_id/' . $cmsPageId); + + $urls = $this->urlRewriteGenerator->generate($cmsPage); + $this->assertEquals($initializesStores[0], $urls[0]->getStoreId()); + $this->assertFalse(isset($urls[1])); + } + + public function testGenerateForSpecificStores() + { + $initializesStores = [1, 2]; + $cmsPageId = 1; + $cmsPage = $this->getMockBuilder(\Magento\Cms\Model\Page::class) + ->disableOriginalConstructor() + ->getMock(); + $cmsPage->expects($this->any())->method('getStores')->willReturn($initializesStores); + $firstStore = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->setMethods(['getStoreId']) + ->getMockForAbstractClass(); + $secondStore = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->setMethods(['getStoreId']) + ->getMockForAbstractClass(); + $this->storeManager->expects($this->any())->method('getStores')->willReturn( + [ + 1 => $firstStore, + 2 => $secondStore + ] + ); + $firstStore->expects($this->any())->method('getStoreId')->willReturn($initializesStores[0]); + $secondStore->expects($this->any())->method('getStoreId')->willReturn($initializesStores[1]); + + $urlRewriteFirst = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class) + ->getMockForAbstractClass(); + $urlRewriteSecond = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class) + ->getMockForAbstractClass(); + $this->urlRewriteFactory->expects($this->at(0))->method('create')->willReturn($urlRewriteFirst); + $this->urlRewriteFactory->expects($this->at(1))->method('create')->willReturn($urlRewriteSecond); + + $cmsPage->expects($this->any())->method('getId')->willReturn($cmsPageId); + $cmsPage->expects($this->any())->method('getIdentifier')->willReturn('request_path'); + $this->urlPathGenerator->expects($this->any())->method('getCanonicalUrlPath')->with($cmsPage) + ->willReturn('cms/page/view/page_id/' . $cmsPageId); + $urls = $this->urlRewriteGenerator->generate($cmsPage); + $this->assertEquals( + [ + $initializesStores[0], + $initializesStores[1] + ], + [ + $urls[0]->getStoreId(), + $urls[1]->getStoreId(), + ] + ); + } +} diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/templates/product/view/type/options/configurable.phtml b/app/code/Magento/ConfigurableProduct/view/frontend/templates/product/view/type/options/configurable.phtml index e75831e28cf166290fbb042d6e09705a67442b82..75967a670279fba002fbce666b9f9d440669724b 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/templates/product/view/type/options/configurable.phtml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/templates/product/view/type/options/configurable.phtml @@ -35,7 +35,8 @@ $_attributes = $block->decorateArray($block->getAllowAttributes()); "#product_addtocart_form": { "configurable": { "spConfig": <?php /* @escapeNotVerified */ echo $block->getJsonConfig() ?>, - "onlyMainImg": <?php /* @escapeNotVerified */ echo $block->getVar('change_only_base_image', 'Magento_ConfigurableProduct') ?: 'false'; ?> + "gallerySwitchStrategy": "<?php /* @escapeNotVerified */ echo $block->getVar('gallery_switch_strategy', + 'Magento_ConfigurableProduct') ?: 'replace'; ?>" } } } diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js index 7bea20e78620134fff06d4cd259fee029f4fe637..59b313bcb497ddb64e1fdca9bc480afdbbb2f1d9 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js @@ -29,7 +29,16 @@ define([ mediaGallerySelector: '[data-gallery-role=gallery-placeholder]', mediaGalleryInitial: null, slyOldPriceSelector: '.sly-old-price', - onlyMainImg: false + + /** + * Defines the mechanism of how images of a gallery should be + * updated when user switches between configurations of a product. + * + * As for now value of this option can be either 'replace' or 'prepend'. + * + * @type {String} + */ + gallerySwitchStrategy: 'replace' }, /** @@ -85,10 +94,10 @@ define([ this.inputSimpleProduct = this.element.find(options.selectSimpleProduct); - gallery.on('gallery:loaded', function () { - var galleryObject = gallery.data('gallery'); - options.mediaGalleryInitial = galleryObject.returnCurrentImages(); - }); + gallery.data('gallery') ? + this._onGalleryLoaded(gallery) : + gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery)); + }, /** @@ -259,46 +268,33 @@ define([ */ _changeProductImage: function () { var images, - initialImages = $.extend(true, [], this.options.mediaGalleryInitial), + initialImages = this.options.mediaGalleryInitial, galleryObject = $(this.options.mediaGallerySelector).data('gallery'); - if (this.options.spConfig.images[this.simpleProduct]) { - images = $.extend(true, [], this.options.spConfig.images[this.simpleProduct]); + if (!galleryObject) { + return; } - function updateGallery(imagesArr) { - var imgToUpdate, - mainImg; + images = this.options.spConfig.images[this.simpleProduct]; - mainImg = imagesArr.filter(function (img) { - return img.isMain; - }); + if (images) { + if (this.options.gallerySwitchStrategy === 'prepend') { + images = images.concat(initialImages); + } - imgToUpdate = mainImg.length ? mainImg[0] : imagesArr[0]; - galleryObject.updateDataByIndex(0, imgToUpdate); - galleryObject.seek(1); - } + images = $.extend(true, [], images); - if (galleryObject) { - if (images) { - images.map(function (img) { - img.type = 'image'; - }); + images.forEach(function (img) { + img.type = 'image'; + }); - if (this.options.onlyMainImg) { - updateGallery(images); - } else { - galleryObject.updateData(images) - } - } else { - if (this.options.onlyMainImg) { - updateGallery(initialImages); - } else { - galleryObject.updateData(this.options.mediaGalleryInitial); - $(this.options.mediaGallerySelector).AddFotoramaVideoEvents(); - } - } + galleryObject.updateData(images); + } else { + galleryObject.updateData(initialImages); + $(this.options.mediaGallerySelector).AddFotoramaVideoEvents(); } + + galleryObject.first(); }, /** @@ -506,8 +502,18 @@ define([ } else { $(this.options.slyOldPriceSelector).hide(); } - } + }, + /** + * Callback which fired after gallery gets initialized. + * + * @param {HTMLElement} element - DOM element associated with gallery. + */ + _onGalleryLoaded: function (element) { + var galleryObject = element.data('gallery'); + + this.options.mediaGalleryInitial = galleryObject.returnCurrentImages(); + } }); return $.mage.configurable; diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index d079c962cad3716d557feb593a10d246433bdd66..602c5db5c226e78ad2320e5ff6e2f0525ed32864 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -600,74 +600,74 @@ class ProcessCronQueueObserverTest extends \PHPUnit_Framework_TestCase public function testDispatchGenerate() { $jobConfig = [ - 'test_group' => [ - 'default' => [ - 'test_job1' => [ - 'instance' => 'CronJob', - 'method' => 'execute', - ], + 'default' => [ + 'test_job1' => [ + 'instance' => 'CronJob', + 'method' => 'execute', ], ], ]; - $this->_config->expects($this->at(0))->method('getJobs')->will($this->returnValue($jobConfig)); $jobs = [ - 'test_group' => [ - 'default' => [ - 'job1' => ['config_path' => 'test/path'], - 'job2' => ['schedule' => ''], - 'job3' => ['schedule' => '* * * * *'], - ], + 'default' => [ + 'job1' => ['config_path' => 'test/path'], + 'job2' => ['schedule' => ''], + 'job3' => ['schedule' => '* * * * *'], ], ]; - $this->_config->expects($this->at(1))->method('getJobs')->will($this->returnValue($jobs)); - $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group')); + $this->_config->expects($this->at(0))->method('getJobs')->willReturn($jobConfig); + $this->_config->expects($this->at(1))->method('getJobs')->willReturn($jobs); + $this->_request->expects($this->any())->method('getParam')->willReturn('default'); $this->_cache->expects( $this->at(0) )->method( 'load' )->with( - $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'test_group') - )->will( - $this->returnValue(time() - 10000000) - ); + $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'default') + )->willReturn(time() - 10000000); $this->_cache->expects( $this->at(2) )->method( 'load' )->with( - $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'test_group') - )->will( - $this->returnValue(time() + 10000000) - ); + $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'default') + )->willReturn(time() + 10000000); - $this->_scopeConfig->expects($this->at(0))->method('getValue')->will($this->returnValue(0)); + $this->_scopeConfig->expects($this->any())->method('getValue')->willReturnMap( + [ + [ + 'system/cron/default/schedule_generate_every', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + null, + 0 + ], + [ + 'system/cron/default/schedule_ahead_for', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + null, + 2 + ] + ] + ); - $scheduleMethods = ['getJobCode', 'getScheduledAt', 'trySchedule', 'unsScheduleId', 'save', '__wakeup']; $schedule = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->setMethods( - $scheduleMethods + ['getJobCode', 'save', 'getScheduledAt', 'unsScheduleId', 'trySchedule', 'getCollection'] )->disableOriginalConstructor()->getMock(); - $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('job_code1')); - $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue('* * * * *')); - $schedule->expects($this->any())->method('unsScheduleId')->will($this->returnSelf()); - $schedule->expects($this->any())->method('trySchedule')->will($this->returnSelf()); + $schedule->expects($this->any())->method('getJobCode')->willReturn('job_code1'); + $schedule->expects($this->once())->method('getScheduledAt')->willReturn('* * * * *'); + $schedule->expects($this->any())->method('unsScheduleId')->willReturnSelf(); + $schedule->expects($this->any())->method('trySchedule')->willReturnSelf(); + $schedule->expects($this->any())->method('getCollection')->willReturn($this->_collection); + $schedule->expects($this->exactly(1))->method('save')->willReturnSelf(); $this->_collection->addItem(new \Magento\Framework\DataObject()); $this->_collection->addItem($schedule); $this->_cache->expects($this->any())->method('save'); - $scheduleMock = $this->getMockBuilder( - \Magento\Cron\Model\Schedule::class - )->disableOriginalConstructor()->setMethods( - ['getCollection', '__wakeup'] - )->getMock(); - $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($scheduleMock)); - - $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($schedule)); + $this->_scheduleFactory->expects($this->any())->method('create')->willReturn($schedule); $this->_observer->execute($this->observer); } diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index ac03bd02553c762535ba575a7ca1ad398afb606a..5a1470959b60d37758bc698cdc2abaeadd3aea25 100644 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -9,6 +9,7 @@ use Magento\Customer\Model\Session; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\App\RequestInterface; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Url\HostChecker; use Magento\Framework\UrlInterface; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; @@ -53,6 +54,7 @@ class Redirect protected $customerUrl; /** + * @deprecated * @var UrlInterface */ protected $url; @@ -67,6 +69,11 @@ class Redirect */ protected $cookieManager; + /** + * @var HostChecker + */ + private $hostChecker; + /** * @param RequestInterface $request * @param Session $customerSession @@ -76,6 +83,7 @@ class Redirect * @param DecoderInterface $urlDecoder * @param CustomerUrl $customerUrl * @param ResultFactory $resultFactory + * @param HostChecker|null $hostChecker */ public function __construct( RequestInterface $request, @@ -85,7 +93,8 @@ class Redirect UrlInterface $url, DecoderInterface $urlDecoder, CustomerUrl $customerUrl, - ResultFactory $resultFactory + ResultFactory $resultFactory, + HostChecker $hostChecker = null ) { $this->request = $request; $this->session = $customerSession; @@ -95,6 +104,7 @@ class Redirect $this->urlDecoder = $urlDecoder; $this->customerUrl = $customerUrl; $this->resultFactory = $resultFactory; + $this->hostChecker = $hostChecker ?: ObjectManager::getInstance()->get(HostChecker::class); } /** @@ -196,7 +206,7 @@ class Redirect $referer = $this->request->getParam(CustomerUrl::REFERER_QUERY_PARAM_NAME); if ($referer) { $referer = $this->urlDecoder->decode($referer); - if ($this->url->isOwnOriginUrl()) { + if ($this->hostChecker->isOwnOrigin($referer)) { $this->applyRedirect($referer); } } diff --git a/app/code/Magento/Customer/Model/Url.php b/app/code/Magento/Customer/Model/Url.php index fa2ff49aafd3abfab8d69c21589b0c6366150424..470093717549a871fb3deb6d74690dcfc45f4f2b 100644 --- a/app/code/Magento/Customer/Model/Url.php +++ b/app/code/Magento/Customer/Model/Url.php @@ -56,25 +56,43 @@ class Url */ protected $urlEncoder; + /** + * @var \Magento\Framework\Url\DecoderInterface + */ + private $urlDecoder; + + /** + * @var \Magento\Framework\Url\HostChecker + */ + private $hostChecker; + /** * @param Session $customerSession * @param ScopeConfigInterface $scopeConfig * @param RequestInterface $request * @param UrlInterface $urlBuilder * @param EncoderInterface $urlEncoder + * @param \Magento\Framework\Url\DecoderInterface|null $urlDecoder + * @param \Magento\Framework\Url\HostChecker|null $hostChecker */ public function __construct( Session $customerSession, ScopeConfigInterface $scopeConfig, RequestInterface $request, UrlInterface $urlBuilder, - EncoderInterface $urlEncoder + EncoderInterface $urlEncoder, + \Magento\Framework\Url\DecoderInterface $urlDecoder = null, + \Magento\Framework\Url\HostChecker $hostChecker = null ) { $this->request = $request; $this->urlBuilder = $urlBuilder; $this->scopeConfig = $scopeConfig; $this->customerSession = $customerSession; $this->urlEncoder = $urlEncoder; + $this->urlDecoder = $urlDecoder ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Url\DecoderInterface::class); + $this->hostChecker = $hostChecker ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Url\HostChecker::class); } /** @@ -95,7 +113,7 @@ class Url public function getLoginUrlParams() { $params = []; - $referer = $this->request->getParam(self::REFERER_QUERY_PARAM_NAME); + $referer = $this->getRequestReferrer(); if (!$referer && !$this->scopeConfig->isSetFlag( self::XML_PATH_CUSTOMER_STARTUP_REDIRECT_TO_DASHBOARD, @@ -122,9 +140,10 @@ class Url public function getLoginPostUrl() { $params = []; - if ($this->request->getParam(self::REFERER_QUERY_PARAM_NAME)) { + $referer = $this->getRequestReferrer(); + if ($referer) { $params = [ - self::REFERER_QUERY_PARAM_NAME => $this->request->getParam(self::REFERER_QUERY_PARAM_NAME), + self::REFERER_QUERY_PARAM_NAME => $referer, ]; } return $this->urlBuilder->getUrl('customer/account/loginPost', $params); @@ -220,4 +239,16 @@ class Url { return $this->urlBuilder->getUrl('customer/account/confirmation', ['email' => $email]); } + + /** + * @return mixed|null + */ + private function getRequestReferrer() + { + $referer = $this->request->getParam(self::REFERER_QUERY_PARAM_NAME); + if ($referer && $this->hostChecker->isOwnOrigin($this->urlDecoder->decode($referer))) { + return $referer; + } + return null; + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php index 5d512bcc6bda1a4fc0f154447a9ec91d74b74228..47b7ea669de30ead287169d1170acbb2c18ae301 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -13,6 +13,7 @@ namespace Magento\Customer\Test\Unit\Model\Account; use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Url\HostChecker; use Magento\Store\Model\ScopeInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -81,6 +82,11 @@ class RedirectTest extends \PHPUnit_Framework_TestCase */ protected $resultFactory; + /** + * @var HostChecker | \PHPUnit_Framework_MockObject_MockObject + */ + private $hostChecker; + protected function setUp() { $this->request = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class); @@ -134,6 +140,10 @@ class RedirectTest extends \PHPUnit_Framework_TestCase ->disableOriginalConstructor() ->getMock(); + $this->hostChecker = $this->getMockBuilder(HostChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); $this->model = $objectManager->getObject( \Magento\Customer\Model\Account\Redirect::class, @@ -145,7 +155,8 @@ class RedirectTest extends \PHPUnit_Framework_TestCase 'url' => $this->url, 'urlDecoder' => $this->urlDecoder, 'customerUrl' => $this->customerUrl, - 'resultFactory' => $this->resultFactory + 'resultFactory' => $this->resultFactory, + 'hostChecker' => $this->hostChecker ] ); } @@ -254,6 +265,7 @@ class RedirectTest extends \PHPUnit_Framework_TestCase $this->resultRedirect->expects($this->once()) ->method('setUrl') + ->with($beforeAuthUrl) ->willReturnSelf(); $this->resultFactory->expects($this->once()) @@ -286,6 +298,7 @@ class RedirectTest extends \PHPUnit_Framework_TestCase return [ // Loggend In, Redirect by Referer [1, 2, 'referer', 'base', '', '', 'account', '', '', '', true, false], + [1, 2, 'http://referer.com/', 'http://base.com/', '', '', 'account', '', '', 'dashboard', true, false], // Loggend In, Redirect by AfterAuthUrl [1, 2, 'referer', 'base', '', 'defined', 'account', '', '', '', true, true], // Not logged In, Redirect by LoginUrl diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml index 6d09c4d7601890d4948c5d40fb801b51371bd57f..4a9af33449b61c80b709998cf663b5601df26447 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml @@ -40,9 +40,7 @@ </div> <script> require(["Magento_Sales/order/create/form"], function(){ - <?php if($_methodsCount == 1):?> - order.switchPaymentMethod('<?php /* @escapeNotVerified */ echo $block->getSelectedMethodCode(); ?>'); - <?php else: ?> + <?php if($_methodsCount != 1):?> order.setPaymentMethod('<?php /* @escapeNotVerified */ echo $block->getSelectedMethodCode(); ?>'); <?php endif; ?> }); diff --git a/app/code/Magento/SampleData/Model/Dependency.php b/app/code/Magento/SampleData/Model/Dependency.php index 09f0c16aac848cafa797441137c9bc62f90a37ce..2a1849364bd77e0c43d19876579b3e2e7129b7ac 100644 --- a/app/code/Magento/SampleData/Model/Dependency.php +++ b/app/code/Magento/SampleData/Model/Dependency.php @@ -88,6 +88,10 @@ class Dependency 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/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml index 19419d4c0a7eef2db8fe472c80b99f9246828993..478d6da720a79bf38df1bcf0b24ed1cc51061b3c 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml @@ -16,8 +16,8 @@ "jsonSwatchConfig": <?php /* @escapeNotVerified */ echo $swatchOptions = $block->getJsonSwatchConfig(); ?>, "mediaCallback": "<?php /* @escapeNotVerified */ echo $block->getMediaCallback() ?>", - "onlyMainImg": <?php /* @escapeNotVerified */ echo $block->getVar('change_only_base_image', - 'Magento_Swatches') ?: 'false'; ?> + "gallerySwitchStrategy": "<?php /* @escapeNotVerified */ echo $block->getVar('gallery_switch_strategy', + 'Magento_ConfigurableProduct') ?: 'replace'; ?>" } } } diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js index 452c9b6f94d3c60e83bd35a5a932c6b5f8a9092f..8af48829df438261aaed469c88245fc50a349853 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js @@ -243,8 +243,15 @@ define([ // Cache for BaseProduct images. Needed when option unset mediaGalleryInitial: [{}], - // - onlyMainImg: false, + /** + * Defines the mechanism of how images of a gallery should be + * updated when user switches between configurations of a product. + * + * As for now value of this option can be either 'replace' or 'prepend'. + * + * @type {String} + */ + gallerySwitchStrategy: 'replace', // whether swatches are rendered in product list or on product page inProductList: false @@ -295,11 +302,9 @@ define([ this.element.parents('.product-item-info'); if (isProductViewExist) { - gallery.on('gallery:loaded', function () { - var galleryObject = gallery.data('gallery'); - - options.mediaGalleryInitial = galleryObject.returnCurrentImages(); - }); + gallery.data('gallery') ? + this._onGalleryLoaded(gallery) : + gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery)); } else { options.mediaGalleryInitial = [{ 'img': $main.find('.product-image-photo').attr('src') @@ -1032,26 +1037,27 @@ define([ */ updateBaseImage: function (images, context, isProductViewExist) { var justAnImage = images[0], - updateImg, - imagesToUpdate, + initialImages = this.options.mediaGalleryInitial, gallery = context.find(this.options.mediaGallerySelector).data('gallery'), - item; + imagesToUpdate, + isInitial; if (isProductViewExist) { imagesToUpdate = images.length ? this._setImageType($.extend(true, [], images)) : []; + isInitial = _.isEqual(imagesToUpdate, initialImages); - if (this.options.onlyMainImg) { - updateImg = imagesToUpdate.filter(function (img) { - return img.isMain; - }); - item = updateImg.length ? updateImg[0] : imagesToUpdate[0]; - gallery.updateDataByIndex(0, item); + if (this.options.gallerySwitchStrategy === 'prepend' && !isInitial) { + imagesToUpdate = imagesToUpdate.concat(initialImages); + } - gallery.seek(1); - } else { - gallery.updateData(imagesToUpdate); + gallery.updateData(imagesToUpdate); + + if (isInitial) { $(this.options.mediaGallerySelector).AddFotoramaVideoEvents(); } + + gallery.first(); + } else if (justAnImage && justAnImage.img) { context.find('.product-image-photo').attr('src', justAnImage.img); } @@ -1127,6 +1133,17 @@ define([ } return selectedAttributes; + }, + + /** + * Callback which fired after gallery gets initialized. + * + * @param {HTMLElement} element - DOM element associated with a gallery. + */ + _onGalleryLoaded: function (element) { + var galleryObject = element.data('gallery'); + + this.options.mediaGalleryInitial = galleryObject.returnCurrentImages(); } }); diff --git a/app/design/frontend/Magento/luma/etc/view.xml b/app/design/frontend/Magento/luma/etc/view.xml index e0fc864e000840ebe770a85f6a78506f0d962a2f..12a51ee065edba43c9afde39ce31c2aace3d00a8 100644 --- a/app/design/frontend/Magento/luma/etc/view.xml +++ b/app/design/frontend/Magento/luma/etc/view.xml @@ -253,10 +253,7 @@ </vars> <vars module="Magento_ConfigurableProduct"> - <var name="change_only_base_image">true</var> - </vars> - <vars module="Magento_Swatches"> - <var name="change_only_base_image">true</var> + <var name="gallery_switch_strategy">prepend</var> </vars> <vars module="Js_Bundle"> diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml index a341341cf7c1dfd873ed552c202a2ece65c4ef6c..fcf6e2ac0c4d0ece60aa742dfcb438456a0d9bd5 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml @@ -212,5 +212,21 @@ <item name="inherit" xsi:type="string">1</item> </field> </dataset> + <dataset name="enable_single_store_mode"> + <field name="general/single_store_mode/enabled" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">Yes</item> + <item name="value" xsi:type="number">1</item> + </field> + </dataset> + <dataset name="enable_single_store_mode_rollback"> + <field name="general/single_store_mode/enabled" xsi:type="array"> + <item name="scope" xsi:type="string">default</item> + <item name="scope_id" xsi:type="number">0</item> + <item name="label" xsi:type="string">No</item> + <item name="value" xsi:type="number">0</item> + </field> + </dataset> </repository> </config> diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageFormSingleStoreMode.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageFormSingleStoreMode.php new file mode 100644 index 0000000000000000000000000000000000000000..4f96b2e3944751082b3371393d976e469bc7b81a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageFormSingleStoreMode.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Cms\Test\Constraint; + +use Magento\Cms\Test\Fixture\CmsPage; +use Magento\Cms\Test\Page\Adminhtml\CmsPageIndex; +use Magento\Cms\Test\Page\Adminhtml\CmsPageNew; + +/** + * Assert that displayed CMS page data on edit page equals passed from fixture. + */ +class AssertCmsPageFormSingleStoreMode extends AssertCmsPageForm +{ + /** + * Assert that displayed CMS page data on edit page equals passed from fixture with enabled single store mode. + * + * @param CmsPage $cms + * @param CmsPageIndex $cmsIndex + * @param CmsPageNew $cmsPageNew + * @return void + */ + public function processAssert( + CmsPage $cms, + CmsPageIndex $cmsIndex, + CmsPageNew $cmsPageNew + ) { + $cmsIndex->open(); + $filter = ['title' => $cms->getTitle()]; + $cmsIndex->getCmsPageGridBlock()->searchAndOpen($filter); + + $cmsFormData = $cmsPageNew->getPageForm()->getData($cms); + $cmsFixtureData = $cms->getData(); + $errors = $this->verifyData($cmsFixtureData, $cmsFormData); + \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php index 250c55ff00d444635f08c2ea4a5f31d8b225fe10..4f02e7c4caf245528fab63d09d959ff3b8981779 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php @@ -6,6 +6,7 @@ namespace Magento\Cms\Test\TestCase; +use Magento\Config\Test\Fixture\ConfigData; use Magento\Cms\Test\Fixture\CmsPage as CmsPageFixture; use Magento\Cms\Test\Page\Adminhtml\CmsPageIndex; use Magento\Cms\Test\Page\Adminhtml\CmsPageNew; @@ -53,6 +54,13 @@ class CreateCmsPageEntityTest extends Injectable */ protected $fixtureFactory; + /** + * Configuration data. + * + * @var string + */ + private $configData; + /** * Inject pages. * @@ -73,10 +81,18 @@ class CreateCmsPageEntityTest extends Injectable * * @param array $data * @param string $fixtureType + * @param string $configData * @return array */ - public function test(array $data, $fixtureType) + public function test(array $data, $fixtureType, $configData = '') { + $this->configData = $configData; + + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); // Steps $cms = $this->fixtureFactory->createByCode($fixtureType, ['data' => $data]); $this->cmsIndex->open(); @@ -86,4 +102,19 @@ class CreateCmsPageEntityTest extends Injectable return ['cms' => $cms]; } + + /** + * Disable single store mode on config level. + * + * @return void + */ + public function tearDown() + { + if ($this->configData) { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => 'enable_single_store_mode', 'rollback' => true] + )->run(); + } + } } diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml index f8b6c8c3d9e06da90b122ba39d0c3f01eebc1978..fc024be14c699d1abb07629e701255ca0c6118f0 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml @@ -67,5 +67,17 @@ <constraint name="Magento\Cms\Test\Constraint\AssertCmsPagePreview" /> <constraint name="Magento\Cms\Test\Constraint\AssertCmsPageOnFrontend" /> </variation> + <variation name="CreateCmsPageEntityTestVariation6" summary="Create CMS page with single store mode" ticketId="MAGETWO-59654"> + <data name="tag" xsi:type="string">test_type:acceptance_test, test_type:extended_acceptance_test</data> + <data name="configData" xsi:type="string">enable_single_store_mode</data> + <data name="fixtureType" xsi:type="string">cmsPage</data> + <data name="data/is_active" xsi:type="string">Yes</data> + <data name="data/title" xsi:type="string">NewCmsPage%isolation%</data> + <data name="data/identifier" xsi:type="string">identifier-%isolation%</data> + <data name="data/content/content" xsi:type="string">cms_page_text_content%isolation%</data> + <constraint name="Magento\Cms\Test\Constraint\AssertCmsPageSuccessSaveMessage" /> + <constraint name="Magento\Cms\Test\Constraint\AssertCmsPageFormSingleStoreMode" /> + <constraint name="Magento\Cms\Test\Constraint\AssertCmsPageOnFrontend" /> + </variation> </testCase> </config> diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php index 568450995f87ae0d0d11edd9dee5b03890e42129..042334a7619d85f31ed00623aff712086873c37a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php @@ -41,6 +41,7 @@ class ProductTest extends \PHPUnit_Framework_TestCase } /** + * @magentoAppArea adminhtml * @magentoDataFixture Magento/Catalog/_files/indexer_catalog_category.php * @magentoDbIsolation enabled */ @@ -214,7 +215,7 @@ class ProductTest extends \PHPUnit_Framework_TestCase \Magento\Catalog\Model\Category::class ); - $result = $category->getCollection()->getItems(); + $result = $category->getCollection()->addAttributeToSelect('name')->getItems(); $result = array_slice($result, 2); return array_slice($result, 0, $count); 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 d8b2189e9f0d267d24d86ea77c67e84b2e2f73c9..c0e45410952717c783686e05b75d54eabdc6a295 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 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase */ 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 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase $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 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase $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 0000000000000000000000000000000000000000..4e62e28af7ff3c55232e5636334cb6023cbf2604 --- /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/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php index 991d598401236c81a6be641b384e5a6587d55914..93fe95f83cbc98676bd14be0320b8517258ee7f3 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php @@ -25,13 +25,6 @@ class CategoryUrlRewriteGeneratorTest extends \PHPUnit_Framework_TestCase $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); } - public function tearDown() - { - $category = $this->objectManager->create(\Magento\Catalog\Model\Category::class); - $category->load(3); - $category->delete(); - } - /** * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php * @magentoDbIsolation enabled @@ -96,6 +89,37 @@ class CategoryUrlRewriteGeneratorTest extends \PHPUnit_Framework_TestCase $this->assertResults($categoryExpectedResult, $actualResults); } + /** + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @param string $urlKey + * @dataProvider incorrectUrlRewritesDataProvider + */ + public function testGenerateUrlRewritesWithIncorrectUrlKey($urlKey) + { + $this->setExpectedException( + \Magento\Framework\Exception\LocalizedException::class, + 'Invalid URL key' + ); + /** @var \Magento\Catalog\Api\CategoryRepositoryInterface $repository */ + $repository = $this->objectManager->get(\Magento\Catalog\Api\CategoryRepositoryInterface::class); + $category = $repository->get(3); + $category->setUrlKey($urlKey); + $repository->save($category); + } + + /** + * @return array + */ + public function incorrectUrlRewritesDataProvider() + { + return [ + ['#'], + ['//'] + ]; + } + /** * @param array $filter * @return array diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/View/Deployment/VersionTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/View/Deployment/VersionTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5a313c318f9e9126ac84848a3b7ddf62e71d6585 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/App/View/Deployment/VersionTest.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\App\View\Deployment; + +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\App\State; +use Magento\Framework\App\View\Deployment\Version\Storage\File; +use Magento\Framework\Filesystem\Directory\WriteInterface; + +class VersionTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var File + */ + private $fileStorage; + + /** + * @var WriteInterface + */ + private $directoryWrite; + + /** + * @var string + */ + private $fileName = 'deployed_version.txt'; + + public function setUp() + { + $this->fileStorage = ObjectManager::getInstance()->create( + File::class, + [ + 'directoryCode' => DirectoryList::STATIC_VIEW, + 'fileName' => $this->fileName + ] + ); + /** @var \Magento\TestFramework\App\Filesystem $filesystem */ + $filesystem = ObjectManager::getInstance()->get(\Magento\TestFramework\App\Filesystem::class); + $this->directoryWrite = $filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); + $this->removeDeployVersionFile(); + } + + /** + * @param string $mode + * @return Version + */ + public function getVersionModel($mode) + { + $appState = ObjectManager::getInstance()->create( + State::class, + [ + 'mode' => $mode + ] + ); + return ObjectManager::getInstance()->create( + Version::class, + [ + 'appState' => $appState + ] + ); + } + + protected function tearDown() + { + $this->removeDeployVersionFile(); + } + + private function removeDeployVersionFile() + { + if ($this->directoryWrite->isExist($this->fileName)) { + $this->directoryWrite->delete($this->fileName); + } + } + + /** + * @expectedException \UnexpectedValueException + */ + public function testGetValueInProductionModeWithoutVersion() + { + $this->assertFalse($this->directoryWrite->isExist($this->fileName)); + $this->getVersionModel(State::MODE_PRODUCTION)->getValue(); + } + + public function testGetValueInDeveloperMode() + { + $this->assertFalse($this->directoryWrite->isExist($this->fileName)); + $this->getVersionModel(State::MODE_DEVELOPER)->getValue(); + $this->assertTrue($this->directoryWrite->isExist($this->fileName)); + } + + /** + * Assert that version is not regenerated on each request in developer mode + */ + public function testGetValue() + { + $this->assertFalse($this->directoryWrite->isExist($this->fileName)); + $versionModel = $this->getVersionModel(State::MODE_DEVELOPER); + $version = $versionModel->getValue(); + $this->assertTrue($this->directoryWrite->isExist($this->fileName)); + $this->assertEquals($version, $versionModel->getValue()); + } +} 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 0000000000000000000000000000000000000000..4ff9104cec879f48f48edc28f9f9860a599519d9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/Model/DependencyTest.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\SampleData\Model; + +use Magento\Framework\Composer\ComposerInformation; +use Magento\Framework\Component\ComponentRegistrar; +use Magento\Framework\Filesystem; +use Magento\Framework\Config\Composer\PackageFactory; + +class DependencyTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Magento\SampleData\Model\Dependency + */ + private $model; + + /** + * @var ComposerInformation|\PHPUnit_Framework_MockObject_MockObject + */ + private $composerInformationMock; + + /** + * @var ComponentRegistrar|\PHPUnit_Framework_MockObject_MockObject + */ + private $componentRegistrarMock; + + protected function setUp() + { + $this->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 0000000000000000000000000000000000000000..d3f063976ea9180bc790e3597e771179f8f26563 --- /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 0000000000000000000000000000000000000000..b9e027b7bb6f5625dee2d8a64c26a9be6056c36b --- /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 0000000000000000000000000000000000000000..2a0d642e8e282ecb2cec8ccb755a1dd3284f5a48 --- /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/dev/tools/grunt/configs/clean.js b/dev/tools/grunt/configs/clean.js index 53bcd8a1d830ebda056e59c6ba592106abcdde72..e720b6c40c27e45e8ca27579727ee6dec67bd400 100644 --- a/dev/tools/grunt/configs/clean.js +++ b/dev/tools/grunt/configs/clean.js @@ -21,7 +21,8 @@ _.each(themes, function(theme, name) { "<%= path.tmp %>/cache/**/*", "<%= combo.autopath(\""+name+"\", path.pub ) %>**/*", "<%= combo.autopath(\""+name+"\", path.tmpLess) %>**/*", - "<%= combo.autopath(\""+name+"\", path.tmpSource) %>**/*" + "<%= combo.autopath(\""+name+"\", path.tmpSource) %>**/*", + "<%= path.deployedVersion %>" ] } ] @@ -56,7 +57,8 @@ var cleanOptions = { "dot": true, "src": [ "<%= path.pub %>frontend/**/*", - "<%= path.pub %>adminhtml/**/*" + "<%= path.pub %>adminhtml/**/*", + "<%= path.deployedVersion %>" ] } ] @@ -73,7 +75,8 @@ var cleanOptions = { "<%= path.pub %>frontend/**/*.less", "<%= path.pub %>frontend/**/*.css", "<%= path.pub %>adminhtml/**/*.less", - "<%= path.pub %>adminhtml/**/*.css" + "<%= path.pub %>adminhtml/**/*.css", + "<%= path.deployedVersion %>" ] } ] @@ -102,7 +105,8 @@ var cleanOptions = { "src": [ "<%= path.pub %>**/*.js", "<%= path.pub %>**/*.html", - "<%= path.pub %>_requirejs/**/*" + "<%= path.pub %>_requirejs/**/*", + "<%= path.deployedVersion %>" ] } ] diff --git a/dev/tools/grunt/configs/path.js b/dev/tools/grunt/configs/path.js index 03621998c14a602c46eec390263aa8450dfc2657..e6a9cf71e81354b8e6b95e6d1623bbf799d831cf 100644 --- a/dev/tools/grunt/configs/path.js +++ b/dev/tools/grunt/configs/path.js @@ -13,6 +13,7 @@ module.exports = { tmpLess: 'var/view_preprocessed/less/', tmpSource: 'var/view_preprocessed/source/', tmp: 'var', + deployedVersion: 'pub/static/deployed_version.txt', css: { setup: 'setup/pub/styles', updater: '../magento2-updater/pub/css' diff --git a/lib/internal/Magento/Framework/App/Http.php b/lib/internal/Magento/Framework/App/Http.php index b98998c55a40155ea785a9680c9b2e02beb85da9..e3de37bfc01f937618ae53ca897f16dc0b7fb188 100644 --- a/lib/internal/Magento/Framework/App/Http.php +++ b/lib/internal/Magento/Framework/App/Http.php @@ -241,8 +241,7 @@ class Http implements \Magento\Framework\AppInterface . "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 b52daaac333e8c7f978aea2bcd156a68782bd6f1..731ec97ee7dd2d5dae8c2a372f454f11cf5755a7 100644 --- a/lib/internal/Magento/Framework/App/SetupInfo.php +++ b/lib/internal/Magento/Framework/App/SetupInfo.php @@ -147,6 +147,14 @@ class SetupInfo { $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 99ca759490f14d66d47988c70e34bf5d4e021ea2..61f0a34d8a0d78ebfe4d685d5f6ce5d30d1a057a 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 @@ class SetupInfoTest extends \PHPUnit_Framework_TestCase ], 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/View/Deployment/Version/Storage/FileTest.php b/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/Version/Storage/FileTest.php index 3981511ad47018c8847c8c9cddf889122e059d58..e7206bf5566075f4df04a977185b5f343ed42b8f 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/Version/Storage/FileTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/Version/Storage/FileTest.php @@ -34,48 +34,15 @@ class FileTest extends \PHPUnit_Framework_TestCase public function testLoad() { - $this->directory - ->expects($this->once()) - ->method('readFile') + $this->directory->expects($this->once()) + ->method('isReadable') ->with('fixture_file.txt') - ->will($this->returnValue('123')); - $this->assertEquals('123', $this->object->load()); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Exception to be propagated - */ - public function testLoadExceptionPropagation() - { - $this->directory - ->expects($this->once()) + ->willReturn(true); + $this->directory->expects($this->once()) ->method('readFile') ->with('fixture_file.txt') - ->will($this->throwException(new \Exception('Exception to be propagated'))); - $this->object->load(); - } - - /** - * @expectedException \UnexpectedValueException - * @expectedExceptionMessage Unable to retrieve deployment version of static files from the file system - */ - public function testLoadExceptionWrapping() - { - $filesystemException = new \Magento\Framework\Exception\FileSystemException( - new \Magento\Framework\Phrase('File does not exist') - ); - $this->directory - ->expects($this->once()) - ->method('readFile') - ->with('fixture_file.txt') - ->will($this->throwException($filesystemException)); - try { - $this->object->load(); - } catch (\Exception $e) { - $this->assertSame($filesystemException, $e->getPrevious(), 'Wrapping of original exception is expected'); - throw $e; - } + ->willReturn('123'); + $this->assertEquals('123', $this->object->load()); } public function testSave() diff --git a/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php b/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php index 187c043945d059992d6dc59a8713fc413b1a9752..8d804102f7a56038fded4118692931030593caa7 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php @@ -6,7 +6,6 @@ namespace Magento\Framework\App\Test\Unit\View\Deployment; use Magento\Framework\App\View\Deployment\Version; -use Magento\Framework\Exception\FileSystemException; /** * Class VersionTest @@ -45,17 +44,6 @@ class VersionTest extends \PHPUnit_Framework_TestCase $objectManager->setBackwardCompatibleProperty($this->object, 'logger', $this->loggerMock); } - public function testGetValueDeveloperMode() - { - $this->appStateMock - ->expects($this->once()) - ->method('getMode') - ->will($this->returnValue(\Magento\Framework\App\State::MODE_DEVELOPER)); - $this->versionStorageMock->expects($this->never())->method($this->anything()); - $this->assertInternalType('integer', $this->object->getValue()); - $this->object->getValue(); // Ensure computation occurs only once and result is cached in memory - } - /** * @param string $appMode * @dataProvider getValueFromStorageDataProvider @@ -81,106 +69,46 @@ class VersionTest extends \PHPUnit_Framework_TestCase ]; } - /** - * $param bool $isUnexpectedValueExceptionThrown - * $param bool $isFileSystemExceptionThrown - * @dataProvider getValueDefaultModeDataProvider - */ - public function testGetValueDefaultMode( - $isUnexpectedValueExceptionThrown, - $isFileSystemExceptionThrown = null - ) { - $versionType = 'integer'; - $this->appStateMock - ->expects($this->once()) - ->method('getMode') - ->willReturn(\Magento\Framework\App\State::MODE_DEFAULT); - if ($isUnexpectedValueExceptionThrown) { - $storageException = new \UnexpectedValueException('Does not exist in the storage'); - $this->versionStorageMock - ->expects($this->once()) - ->method('load') - ->will($this->throwException($storageException)); - $this->versionStorageMock->expects($this->once()) - ->method('save') - ->with($this->isType($versionType)); - if ($isFileSystemExceptionThrown) { - $fileSystemException = new FileSystemException( - new \Magento\Framework\Phrase('Can not load static content version') - ); - $this->versionStorageMock - ->expects($this->once()) - ->method('save') - ->will($this->throwException($fileSystemException)); - $this->loggerMock->expects($this->once()) - ->method('critical') - ->with('Can not save static content version.'); - } else { - $this->loggerMock->expects($this->never()) - ->method('critical'); - } - } else { - $this->versionStorageMock - ->expects($this->once()) - ->method('load') - ->willReturn(1475779229); - $this->loggerMock->expects($this->never()) - ->method('critical'); - } - $this->assertInternalType($versionType, $this->object->getValue()); + public function testGetValueInNonProductionMode() + { + $version = 123123123123; + $this->versionStorageMock->expects($this->once()) + ->method('load') + ->willReturn($version); + + $this->assertEquals($version, $this->object->getValue()); $this->object->getValue(); } /** - * @return array + * @expectedException \UnexpectedValueException */ - public function getValueDefaultModeDataProvider() + public function testGetValueWithProductionModeAndException() { - return [ - [false], - [true, false], - [true, true] - ]; - } - - /** - * @param bool $isUnexpectedValueExceptionThrown - * @dataProvider getValueProductionModeDataProvider - */ - public function testGetValueProductionMode( - $isUnexpectedValueExceptionThrown - ) { - $this->appStateMock - ->expects($this->once()) + $this->versionStorageMock->expects($this->once()) + ->method('load') + ->willReturn(false); + $this->appStateMock->expects($this->once()) ->method('getMode') ->willReturn(\Magento\Framework\App\State::MODE_PRODUCTION); - if ($isUnexpectedValueExceptionThrown) { - $storageException = new \UnexpectedValueException('Does not exist in the storage'); - $this->versionStorageMock - ->expects($this->once()) - ->method('load') - ->will($this->throwException($storageException)); - $this->loggerMock->expects($this->once()) - ->method('critical') - ->with('Can not load static content version.'); - } else { - $this->versionStorageMock - ->expects($this->once()) - ->method('load') - ->willReturn(1475779229); - } - $this->assertInternalType('integer', $this->object->getValue()); + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with('Can not load static content version.'); + $this->object->getValue(); } - /** - * @return array - */ - public function getValueProductionModeDataProvider() + public function testGetValueWithProductionMode() { - return [ - [false], - [true], - ]; + $this->versionStorageMock->expects($this->once()) + ->method('load') + ->willReturn(false); + $this->appStateMock->expects($this->once()) + ->method('getMode') + ->willReturn(\Magento\Framework\App\State::MODE_DEFAULT); + $this->versionStorageMock->expects($this->once()) + ->method('save'); + + $this->assertNotNull($this->object->getValue()); } } 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 0000000000000000000000000000000000000000..2a0cd37c68d37453c3e881693f25953bac966c1e --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/_files/pub/index.php @@ -0,0 +1,5 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/_files/setup/index.php b/lib/internal/Magento/Framework/App/Test/Unit/_files/setup/index.php new file mode 100644 index 0000000000000000000000000000000000000000..2a0cd37c68d37453c3e881693f25953bac966c1e --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/_files/setup/index.php @@ -0,0 +1,5 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ diff --git a/lib/internal/Magento/Framework/App/View/Deployment/Version.php b/lib/internal/Magento/Framework/App/View/Deployment/Version.php index 7f6dc7fa9285ccc3987d84091bc9edb76d09f794..73d4a0c926cea88c5b2cfbd6db34888f3ef651fb 100644 --- a/lib/internal/Magento/Framework/App/View/Deployment/Version.php +++ b/lib/internal/Magento/Framework/App/View/Deployment/Version.php @@ -7,7 +7,6 @@ namespace Magento\Framework\App\View\Deployment; use Psr\Log\LoggerInterface; -use Magento\Framework\Exception\FileSystemException; /** * Deployment version of static files @@ -67,23 +66,16 @@ class Version */ protected function readValue($appMode) { - if ($appMode == \Magento\Framework\App\State::MODE_DEVELOPER) { - $result = $this->generateVersion(); - } else { - try { - $result = $this->versionStorage->load(); - } catch (\UnexpectedValueException $e) { - $result = $this->generateVersion(); - if ($appMode == \Magento\Framework\App\State::MODE_DEFAULT) { - try { - $this->versionStorage->save($result); - } catch (FileSystemException $e) { - $this->getLogger()->critical('Can not save static content version.'); - } - } else { - $this->getLogger()->critical('Can not load static content version.'); - } + $result = $this->versionStorage->load(); + if (!$result) { + if ($appMode == \Magento\Framework\App\State::MODE_PRODUCTION) { + $this->getLogger()->critical('Can not load static content version.'); + throw new \UnexpectedValueException( + "Unable to retrieve deployment version of static files from the file system." + ); } + $result = $this->generateVersion(); + $this->versionStorage->save($result); } return $result; } diff --git a/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php b/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php index 4f8813df774d7edc9a7490e31f447e6827dd2e38..0967cb634cbd706689bc0d54aa2c9a1b5b7a8b5e 100644 --- a/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php +++ b/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php @@ -40,15 +40,10 @@ class File implements \Magento\Framework\App\View\Deployment\Version\StorageInte */ public function load() { - try { + if ($this->directory->isReadable($this->fileName)) { return $this->directory->readFile($this->fileName); - } catch (\Magento\Framework\Exception\FileSystemException $e) { - throw new \UnexpectedValueException( - 'Unable to retrieve deployment version of static files from the file system.', - 0, - $e - ); } + return false; } /** diff --git a/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/Import.php b/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/Import.php index 524ccc8c11fe311837d3390a8f9ec10ee890d375..260f6216b09bd1dd03fdee39f5102c1a717df32e 100644 --- a/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/Import.php +++ b/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/Import.php @@ -4,8 +4,6 @@ * See COPYING.txt for license details. */ -// @codingStandardsIgnoreFile - namespace Magento\Framework\Css\PreProcessor\Instruction; use Magento\Framework\View\Asset\LocalInterface; @@ -22,7 +20,10 @@ class Import implements PreProcessorInterface * Pattern of @import instruction */ const REPLACE_PATTERN = - '#@import\s+(\((?P<type>\w+)\)\s+)?[\'\"](?P<path>(?![/\\\]|\w:[/\\\])[^\"\']+)[\'\"]\s*?(?P<media>.*?);#'; + '#@import(?!.*?\surl\(.*?)' + . '(?P<start>[\(\),\w\s]*?[\'\"])' + . '(?P<path>(?![/\\\]|\w*?:[/\\\])[^\"\']+)' + . '(?P<end>[\'\"][\s\w\(\)]*?);#'; /** * @var \Magento\Framework\View\Asset\NotationResolver\Module @@ -133,9 +134,9 @@ class Import implements PreProcessorInterface $matchedFileId = $this->fixFileExtension($matchedContent['path'], $contentType); $this->recordRelatedFile($matchedFileId, $asset); $resolvedPath = $this->notationResolver->convertModuleNotationToPath($asset, $matchedFileId); - $typeString = empty($matchedContent['type']) ? '' : '(' . $matchedContent['type'] . ') '; - $mediaString = empty($matchedContent['media']) ? '' : ' ' . trim($matchedContent['media']); - return "@import {$typeString}'{$resolvedPath}'{$mediaString};"; + $start = $matchedContent['start']; + $end = $matchedContent['end']; + return "@import{$start}{$resolvedPath}{$end};"; } /** diff --git a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/ImportTest.php b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/ImportTest.php index 2441422bb182103100c3181bcfae4150423ef0b3..dc45ea75e0eb86f13771c7108a959376caad54f3 100644 --- a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/ImportTest.php +++ b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/ImportTest.php @@ -39,7 +39,7 @@ class ImportTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->notationResolver = $this->getMock( + $this->notationResolver = $this->getMock( \Magento\Framework\View\Asset\NotationResolver\Module::class, [], [], '', false ); $this->asset = $this->getMock(\Magento\Framework\View\Asset\File::class, [], [], '', false); @@ -63,7 +63,11 @@ class ImportTest extends \PHPUnit_Framework_TestCase public function testProcess($originalContent, $foundPath, $resolvedPath, $expectedContent) { $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'less', 'path'); - $this->notationResolver->expects($this->once()) + $invoke = $this->once(); + if (preg_match('/^(http:|https:|\/+)/', $foundPath)) { + $invoke = $this->never(); + } + $this->notationResolver->expects($invoke) ->method('convertModuleNotationToPath') ->with($this->asset, $foundPath) ->will($this->returnValue($resolvedPath)); @@ -78,50 +82,70 @@ class ImportTest extends \PHPUnit_Framework_TestCase public function processDataProvider() { return [ - 'non-modular notation' => [ - '@import (type) "some/file.css" media;', - 'some/file.css', - 'some/file.css', - "@import (type) 'some/file.css' media;", + 'non-modular notation, no extension' => [ + '@import (type) \'some/file\' media;', + 'some/file.less', + 'some/file.less', + '@import (type) \'some/file.less\' media;', ], 'modular, with extension' => [ '@import (type) "Magento_Module::something.css" media;', 'Magento_Module::something.css', 'Magento_Module/something.css', - "@import (type) 'Magento_Module/something.css' media;", + '@import (type) "Magento_Module/something.css" media;', + ], + 'remote file import url()' => [ + '@import (type) url("http://example.com/css/some.css") media;', + 'http://example.com/css/some.css', + null, + '@import (type) url("http://example.com/css/some.css") media;', + ], + 'invalid path' => [ + '@import (type) url("/example.com/css/some.css") media;', + '/example.com/css/some.css', + null, + '@import (type) url("/example.com/css/some.css") media;', ], 'modular, no extension' => [ '@import (type) "Magento_Module::something" media;', 'Magento_Module::something.less', 'Magento_Module/something.less', - "@import (type) 'Magento_Module/something.less' media;", + '@import (type) "Magento_Module/something.less" media;', ], 'no type' => [ '@import "Magento_Module::something.css" media;', 'Magento_Module::something.css', 'Magento_Module/something.css', - "@import 'Magento_Module/something.css' media;", + '@import "Magento_Module/something.css" media;', ], 'no media' => [ '@import (type) "Magento_Module::something.css";', 'Magento_Module::something.css', 'Magento_Module/something.css', - "@import (type) 'Magento_Module/something.css';", + '@import (type) "Magento_Module/something.css";', + ], + 'with single line comment, replace' => [ + '@import (type) "some/file" media;' . PHP_EOL + . '// @import (type) "unnecessary/file.css" media;', + 'some/file.less', + 'some/file.less', + '@import (type) "some/file.less" media;' . PHP_EOL, ], - 'with single line comment' => [ - '@import (type) "some/file.css" media;' . PHP_EOL - . '// @import (type) "unnecessary/file.css" media;', - 'some/file.css', - 'some/file.css', - "@import (type) 'some/file.css' media;" . PHP_EOL, + 'with single line comment, no replace' => [ + '@import (type) "some/file.less" media;' . PHP_EOL + . '// @import (type) "unnecessary/file" media;', + 'some/file.less', + 'some/file.less', + '@import (type) "some/file.less" media;' . PHP_EOL + . '// @import (type) "unnecessary/file" media;', ], 'with multi line comment' => [ - '@import (type) "some/file.css" media;' . PHP_EOL + '@import (type) "some/file" media;' . PHP_EOL . '/* @import (type) "unnecessary/file.css" media;' . PHP_EOL . '@import (type) "another/unnecessary/file.css" media; */', - 'some/file.css', - 'some/file.css', - "@import (type) 'some/file.css' media;" . PHP_EOL, + 'some/file.less', + 'some/file.less', + '@import (type) "some/file.less" media;' . PHP_EOL, ], ]; } diff --git a/lib/internal/Magento/Framework/Test/Unit/ObjectManager/Config/CompiledTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php similarity index 98% rename from lib/internal/Magento/Framework/Test/Unit/ObjectManager/Config/CompiledTest.php rename to lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php index 3dd9f5065a1421ec822d4a81377ea81a5c3f8f52..1fcf3176540db6279e3fec6754fb3a7a22b3cc59 100644 --- a/lib/internal/Magento/Framework/Test/Unit/ObjectManager/Config/CompiledTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/CompiledTest.php @@ -3,7 +3,7 @@ * Copyright © 2016 Magento. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Framework\Test\Unit\ObjectManager\Config; +namespace Magento\Framework\ObjectManager\Test\Unit\Config; use Magento\Framework\ObjectManager\Config\Compiled as CompiledConfig; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; diff --git a/lib/internal/Magento/Framework/Test/Unit/UrlTest.php b/lib/internal/Magento/Framework/Test/Unit/UrlTest.php index 36fce179395b5463fc3cf522defc5075038fc5c1..939e9a39bea584adc34037fcb9a899c4d3fe3e68 100644 --- a/lib/internal/Magento/Framework/Test/Unit/UrlTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/UrlTest.php @@ -7,6 +7,7 @@ // @codingStandardsIgnoreFile namespace Magento\Framework\Test\Unit; +use Magento\Framework\Url\HostChecker; /** * Test class for Magento\Framework\Url @@ -59,6 +60,11 @@ class UrlTest extends \PHPUnit_Framework_TestCase */ protected $urlModifier; + /** + * @var HostChecker|\PHPUnit_Framework_MockObject_MockObject + */ + private $hostChecker; + protected function setUp() { $this->routeParamsResolverMock = $this->getMock( @@ -549,18 +555,17 @@ class UrlTest extends \PHPUnit_Framework_TestCase /** * @param bool $result - * @param string $baseUrl * @param string $referrer * @dataProvider isOwnOriginUrlDataProvider */ - public function testIsOwnOriginUrl($result, $baseUrl, $referrer) + public function testIsOwnOriginUrl($result, $referrer) { $requestMock = $this->getRequestMock(); - $model = $this->getUrlModel(['scopeResolver' => $this->scopeResolverMock, 'request' => $requestMock]); + $this->hostChecker = $this->getMockBuilder(HostChecker::class) + ->disableOriginalConstructor()->getMock(); + $this->hostChecker->expects($this->once())->method('isOwnOrigin')->with($referrer)->willReturn($result); + $model = $this->getUrlModel(['hostChecker' => $this->hostChecker, 'request' => $requestMock]); - $this->scopeMock->expects($this->any())->method('getBaseUrl')->will($this->returnValue($baseUrl)); - $this->scopeResolverMock->expects($this->any())->method('getScopes') - ->will($this->returnValue([$this->scopeMock])); $requestMock->expects($this->once())->method('getServer')->with('HTTP_REFERER') ->will($this->returnValue($referrer)); @@ -570,8 +575,8 @@ class UrlTest extends \PHPUnit_Framework_TestCase public function isOwnOriginUrlDataProvider() { return [ - 'is origin url' => [true, 'http://localhost/', 'http://localhost/'], - 'is not origin url' => [false, 'http://localhost/', 'http://example.com/'], + 'is origin url' => [true, 'http://localhost/'], + 'is not origin url' => [false, 'http://example.com/'], ]; } diff --git a/lib/internal/Magento/Framework/Url.php b/lib/internal/Magento/Framework/Url.php index 7361fdb336dd8ecd9ce58507dda027f1731f1d58..30af3528b2baba392095ecb86f9e65eb78bfd8a1 100644 --- a/lib/internal/Magento/Framework/Url.php +++ b/lib/internal/Magento/Framework/Url.php @@ -8,6 +8,8 @@ namespace Magento\Framework; +use Magento\Framework\Url\HostChecker; + /** * URL * @@ -178,6 +180,11 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur */ private $escaper; + /** + * @var HostChecker + */ + private $hostChecker; + /** * @param \Magento\Framework\App\Route\ConfigInterface $routeConfig * @param \Magento\Framework\App\RequestInterface $request @@ -191,6 +198,7 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur * @param \Magento\Framework\Url\RouteParamsPreprocessorInterface $routeParamsPreprocessor * @param string $scopeType * @param array $data + * @param HostChecker|null $hostChecker * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -205,7 +213,8 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Framework\Url\RouteParamsPreprocessorInterface $routeParamsPreprocessor, $scopeType, - array $data = [] + array $data = [], + HostChecker $hostChecker = null ) { $this->_request = $request; $this->_routeConfig = $routeConfig; @@ -218,6 +227,8 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur $this->_scopeConfig = $scopeConfig; $this->routeParamsPreprocessor = $routeParamsPreprocessor; $this->_scopeType = $scopeType; + $this->hostChecker = $hostChecker ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(HostChecker::class); parent::__construct($data); } @@ -1086,17 +1097,7 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur */ public function isOwnOriginUrl() { - $scopeDomains = []; - $referer = parse_url($this->_request->getServer('HTTP_REFERER'), PHP_URL_HOST); - foreach ($this->_scopeResolver->getScopes() as $scope) { - $scopeDomains[] = parse_url($scope->getBaseUrl(), PHP_URL_HOST); - $scopeDomains[] = parse_url($scope->getBaseUrl(UrlInterface::URL_TYPE_LINK, true), PHP_URL_HOST); - } - $scopeDomains = array_unique($scopeDomains); - if (empty($referer) || in_array($referer, $scopeDomains)) { - return true; - } - return false; + return $this->hostChecker->isOwnOrigin($this->_request->getServer('HTTP_REFERER')); } /** @@ -1163,7 +1164,7 @@ class Url extends \Magento\Framework\DataObject implements \Magento\Framework\Ur private function getUrlModifier() { if ($this->urlModifier === null) { - $this->urlModifier = \Magento\Framework\App\ObjectManager::getInstance()->get( + $this->urlModifier = \Magento\Framework\App\ObjectManager::getInstance()->get( \Magento\Framework\Url\ModifierInterface::class ); } diff --git a/lib/internal/Magento/Framework/Url/HostChecker.php b/lib/internal/Magento/Framework/Url/HostChecker.php new file mode 100644 index 0000000000000000000000000000000000000000..32546595a040dee59dfd9de3dae2577c35bbf444 --- /dev/null +++ b/lib/internal/Magento/Framework/Url/HostChecker.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Url; + +use Magento\Framework\UrlInterface; + +/** + * Class provides functionality for checks of a host name + */ +class HostChecker +{ + /** + * @var \Magento\Framework\Url\ScopeResolverInterface + */ + private $scopeResolver; + + /** + * @param ScopeResolverInterface $scopeResolver + */ + public function __construct(ScopeResolverInterface $scopeResolver) + { + $this->scopeResolver = $scopeResolver; + } + + /** + * Check if provided URL is one of the domain URLs assigned to scopes + * + * @param string $url + * @return bool + */ + public function isOwnOrigin($url) + { + $scopeHostNames = []; + $hostName = parse_url($url, PHP_URL_HOST); + if (empty($hostName)) { + return true; + } + foreach ($this->scopeResolver->getScopes() as $scope) { + $scopeHostNames[] = parse_url($scope->getBaseUrl(), PHP_URL_HOST); + $scopeHostNames[] = parse_url($scope->getBaseUrl(UrlInterface::URL_TYPE_LINK, true), PHP_URL_HOST); + } + $scopeHostNames = array_unique($scopeHostNames); + return in_array($hostName, $scopeHostNames); + } +} diff --git a/lib/internal/Magento/Framework/Url/Test/Unit/HostCheckerTest.php b/lib/internal/Magento/Framework/Url/Test/Unit/HostCheckerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..a6be097ac38ea19c2d1bdc2f8bac4cc12306f7b6 --- /dev/null +++ b/lib/internal/Magento/Framework/Url/Test/Unit/HostCheckerTest.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Url\Test\Unit; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class HostCheckerTest extends \PHPUnit_Framework_TestCase +{ + /** @var \Magento\Framework\Url\HostChecker */ + private $object; + + /** @var \Magento\Framework\Url\ScopeResolverInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $scopeResolver; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->scopeResolver = $this->getMockBuilder( + \Magento\Framework\Url\ScopeResolverInterface::class + )->getMock(); + + $objectManager = new ObjectManager($this); + $this->object = $objectManager->getObject( + \Magento\Framework\Url\HostChecker::class, + [ + 'scopeResolver' => $this->scopeResolver + ] + ); + } + + /** + * @dataProvider isOwnOriginDataProvider + * @param string $url + * @param boolean $result + */ + public function testIsOwnOrigin($url, $result) + { + $scopes[0] = $this->getMockBuilder(\Magento\Framework\Url\ScopeInterface::class)->getMock(); + $scopes[0]->expects($this->any())->method('getBaseUrl')->willReturn('http://www.example.com'); + $scopes[1] = $this->getMockBuilder(\Magento\Framework\Url\ScopeInterface::class)->getMock(); + $scopes[1]->expects($this->any())->method('getBaseUrl')->willReturn('https://www.example2.com'); + + $this->scopeResolver->expects($this->atLeastOnce())->method('getScopes')->willReturn($scopes); + + $this->assertEquals($result, $this->object->isOwnOrigin($url)); + } + + /** + * @return array + */ + public function isOwnOriginDataProvider() + { + return [ + ['http://www.example.com/some/page/', true], + ['http://www.test.com/other/page/', false], + ]; + } +} diff --git a/pub/media/.htaccess b/pub/media/.htaccess index 865ebd31b528b8183593ee5e55894dedc53a46fd..0a3087c096319f5d9974d643d33317ee0a4c4af2 100644 --- a/pub/media/.htaccess +++ b/pub/media/.htaccess @@ -11,6 +11,10 @@ php_flag engine 0 AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi Options -ExecCGI +<FilesMatch ".+\.(ph(p[3457]?|t|tml)|[aj]sp|p[ly]|sh|cgi|shtml?|html?)$"> +SetHandler default-handler +</FilesMatch> + <IfModule mod_rewrite.c> ############################################ diff --git a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php index bbd0a44254e89ce2e84d3bbe7e043ac80c76a435..ad2ad3d7b6969dcf241bd9f273ae4330d9fedcd2 100644 --- a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php +++ b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php @@ -71,7 +71,7 @@ class UpgradeCommand extends AbstractSetupCommand $installer->installSchema(); $installer->installDataFixtures(); if (!$keepGenerated) { - $output->writeln('<info>Please re-run Magento compile command</info>'); + $output->writeln('<info>Please re-run Magento compile command. Use the command "setup:di:compile"</info>'); } 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 6209df88bd5f06880fad8c645128af079d61b482..dcbdc876db607a010e543b76c62d5410a4ca0132 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 @@ use Magento\Framework\Console\Cli; 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 @@ class UpgradeCommandTest extends \PHPUnit_Framework_TestCase $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' => '' + ], + ]; } }