diff --git a/app/code/Magento/Bundle/composer.json b/app/code/Magento/Bundle/composer.json index 0da5b0193e94f..2328da6c4f30a 100644 --- a/app/code/Magento/Bundle/composer.json +++ b/app/code/Magento/Bundle/composer.json @@ -20,7 +20,8 @@ "magento/module-media-storage": "1.0.0-beta" }, "suggest": { - "magento/module-webapi": "1.0.0-beta" + "magento/module-webapi": "1.0.0-beta", + "magento/module-bundle-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/Catalog/composer.json b/app/code/Magento/Catalog/composer.json index 4b2838d34c1d3..13bfaf244ac1f 100644 --- a/app/code/Magento/Catalog/composer.json +++ b/app/code/Magento/Catalog/composer.json @@ -30,7 +30,8 @@ "magento/module-ui": "self.version" }, "suggest": { - "magento/module-cookie": "1.0.0-beta" + "magento/module-cookie": "1.0.0-beta", + "magento/module-catalog-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php index 7fe262fbf57c0..2f96c607ae3c6 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractType.php @@ -480,9 +480,9 @@ public function prepareAttributesWithDefaultValueForSave(array $rowData, $withDe foreach ($this->_getProductAttributes($rowData) as $attrCode => $attrParams) { if (!$attrParams['is_static']) { if (isset($rowData[$attrCode]) && strlen($rowData[$attrCode])) { - $resultAttrs[$attrCode] = 'select' == $attrParams['type'] ? $attrParams['options'][strtolower( - $rowData[$attrCode] - )] : $rowData[$attrCode]; + $resultAttrs[$attrCode] = in_array($attrParams['type'], ['select', 'boolean']) + ? $attrParams['options'][strtolower($rowData[$attrCode])] + : $rowData[$attrCode]; if ('multiselect' == $attrParams['type']) { $resultAttrs[$attrCode] = []; foreach (explode(Product::PSEUDO_MULTI_LINE_SEPARATOR, $rowData[$attrCode]) as $value) { diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php index 980535ce2d8b5..89230e1da3463 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator.php @@ -141,6 +141,7 @@ public function isAttributeValid($attrCode, array $attrParams, array $rowData) $valid = $this->numericValidation($attrCode, $attrParams['type']); break; case 'select': + case 'boolean': case 'multiselect': $values = explode(Product::PSEUDO_MULTI_LINE_SEPARATOR, $rowData[$attrCode]); $valid = true; diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php b/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php index a78e978d84c6f..dc0263e99d4f0 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Uploader.php @@ -314,4 +314,12 @@ protected function _moveFile($tmpPath, $destPath) return false; } } + + /** + * {@inheritdoc} + */ + protected function chmod($file) + { + return; + } } diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php index 4b07ee981af02..7ef3548a7a67f 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/AbstractTypeTest.php @@ -117,40 +117,59 @@ protected function setUp() '', false ); - - $entityAttributes = [[ - 'attribute_id' => 'attribute_id', - 'attribute_set_name' => 'attributeSetName', - ]]; - - $this->entityModel->expects($this->any())->method('getEntityTypeId')->willReturn(3); - $this->entityModel->expects($this->any())->method('getAttributeOptions')->willReturn(['option1', 'option2']); - $attrSetColFactory->expects($this->any())->method('create')->willReturn($attrSetCollection); - $attrSetCollection->expects($this->any())->method('setEntityTypeFilter')->willReturn([$attributeSet]); - $attrColFactory->expects($this->any())->method('create')->willReturn($attrCollection); - $attrCollection->expects($this->any())->method('setAttributeSetFilter')->willReturn([$attribute]); - $attributeSet->expects($this->any())->method('getId')->willReturn(1); - $attributeSet->expects($this->any())->method('getAttributeSetName')->willReturn('attribute_set_name'); - $attribute->expects($this->any())->method('getAttributeCode')->willReturn('attr_code'); - $attribute->expects($this->any())->method('getId')->willReturn('1'); $attribute->expects($this->any())->method('getIsVisible')->willReturn(true); $attribute->expects($this->any())->method('getIsGlobal')->willReturn(true); $attribute->expects($this->any())->method('getIsRequired')->willReturn(true); $attribute->expects($this->any())->method('getIsUnique')->willReturn(true); $attribute->expects($this->any())->method('getFrontendLabel')->willReturn('frontend_label'); - $attribute->expects($this->any())->method('isStatic')->willReturn(true); $attribute->expects($this->any())->method('getApplyTo')->willReturn(['simple']); $attribute->expects($this->any())->method('getDefaultValue')->willReturn('default_value'); $attribute->expects($this->any())->method('usesSource')->willReturn(true); - $attribute->expects($this->any())->method('getFrontendInput')->willReturn('multiselect'); + + + $entityAttributes = [ + [ + 'attribute_id' => 'attribute_id', + 'attribute_set_name' => 'attributeSetName', + ], + [ + 'attribute_id' => 'boolean_attribute', + 'attribute_set_name' => 'attributeSetName' + ] + ]; + $attribute1 = clone $attribute; + $attribute2 = clone $attribute; + + $attribute1->expects($this->any())->method('getId')->willReturn('1'); + $attribute1->expects($this->any())->method('getAttributeCode')->willReturn('attr_code'); + $attribute1->expects($this->any())->method('getFrontendInput')->willReturn('multiselect'); + $attribute1->expects($this->any())->method('isStatic')->willReturn(true); + + $attribute2->expects($this->any())->method('getId')->willReturn('2'); + $attribute2->expects($this->any())->method('getAttributeCode')->willReturn('boolean_attribute'); + $attribute2->expects($this->any())->method('getFrontendInput')->willReturn('boolean'); + $attribute2->expects($this->any())->method('isStatic')->willReturn(false); + + $this->entityModel->expects($this->any())->method('getEntityTypeId')->willReturn(3); + $this->entityModel->expects($this->any())->method('getAttributeOptions')->willReturnOnConsecutiveCalls( + ['option1', 'option2'], + ['yes' => 1, 'no' => 0] + ); + $attrSetColFactory->expects($this->any())->method('create')->willReturn($attrSetCollection); + $attrSetCollection->expects($this->any())->method('setEntityTypeFilter')->willReturn([$attributeSet]); + $attrColFactory->expects($this->any())->method('create')->willReturn($attrCollection); + $attrCollection->expects($this->any())->method('setAttributeSetFilter')->willReturn([$attribute1, $attribute2]); + $attributeSet->expects($this->any())->method('getId')->willReturn(1); + $attributeSet->expects($this->any())->method('getAttributeSetName')->willReturn('attribute_set_name'); + $attrCollection ->expects($this->any()) ->method('addFieldToFilter') ->with( 'main_table.attribute_id', - ['in' => ['attribute_id']] + ['in' => ['attribute_id', 'boolean_attribute']] ) - ->willReturn([$attribute]); + ->willReturn([$attribute1, $attribute2]); $this->connection = $this->getMock( 'Magento\Framework\DB\Adapter\Pdo\Mysql', @@ -343,6 +362,7 @@ public function addAttributeOptionDataProvider() /** * @param $object * @param $property + * @return mixed */ protected function getPropertyValue(&$object, $property) { @@ -366,4 +386,14 @@ protected function setPropertyValue(&$object, $property, $value) $reflectionProperty->setValue($object, $value); return $object; } + + public function testPrepareAttributesWithDefaultValueForSave() + { + $rowData = [ + '_attribute_set' => 'attributeSetName', + 'boolean_attribute' => 'Yes' + ]; + $result = $this->simpleType->prepareAttributesWithDefaultValueForSave($rowData); + $this->assertEquals(['boolean_attribute' => 1], $result); + } } diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php index 8e6df5186c075..3541ccbb99338 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/ValidatorTest.php @@ -72,6 +72,25 @@ protected function setUp() $this->validator->init($this->context); } + public function testIsBooleanAttributeValid() + { + $this->context->expects($this->any())->method('getBehavior') + ->willReturn(\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE); + $result = $this->validator->isAttributeValid( + 'boolean_attribute', + [ + 'type' => 'boolean', + 'apply_to' => ['simple'], + 'is_required' => false + ], + [ + 'product_type' => 'simple', + 'boolean_attribute' => 'Yes' + ] + ); + $this->assertTrue($result); + } + public function testIsValidCorrect() { $value = ['product_type' => 'simple']; diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json index 6ecef40f903ca..f102bad572281 100644 --- a/app/code/Magento/CatalogRule/composer.json +++ b/app/code/Magento/CatalogRule/composer.json @@ -12,7 +12,8 @@ "magento/framework": "1.0.0-beta" }, "suggest": { - "magento/module-import-export": "1.0.0-beta" + "magento/module-import-export": "1.0.0-beta", + "magento/module-catalog-rule-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/CatalogUrlRewrite/etc/setup/events.xml b/app/code/Magento/CatalogUrlRewrite/etc/setup/events.xml new file mode 100644 index 0000000000000..943b2d756a246 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/etc/setup/events.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/app/code/Magento/Cms/composer.json b/app/code/Magento/Cms/composer.json index 324eb22f51a41..5cf3cb34f5f51 100644 --- a/app/code/Magento/Cms/composer.json +++ b/app/code/Magento/Cms/composer.json @@ -14,6 +14,9 @@ "magento/module-media-storage": "1.0.0-beta", "magento/framework": "1.0.0-beta" }, + "suggest": { + "magento/module-cms-sample-data": "Sample Data version:1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json index bbf56b1cb0475..afc2c930378c6 100644 --- a/app/code/Magento/ConfigurableProduct/composer.json +++ b/app/code/Magento/ConfigurableProduct/composer.json @@ -17,8 +17,10 @@ "magento/module-ui": "self.version" }, "suggest": { - "magento/module-webapi": "1.0.0-beta", - "magento/module-sales": "1.0.0-beta" + "magento/module-webapi": "1.0.0-beta", + "magento/module-sales": "1.0.0-beta", + "magento/module-configurable-sample-data": "Sample Data version:1.0.0-beta", + "magento/module-product-links-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/Customer/composer.json b/app/code/Magento/Customer/composer.json index 5bf95b1f878c1..b7ef85fb4be90 100644 --- a/app/code/Magento/Customer/composer.json +++ b/app/code/Magento/Customer/composer.json @@ -25,7 +25,8 @@ "magento/module-quote": "1.0.0-beta" }, "suggest": { - "magento/module-cookie": "1.0.0-beta" + "magento/module-cookie": "1.0.0-beta", + "magento/module-customer-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/Deploy/Console/Command/SetModeCommand.php b/app/code/Magento/Deploy/Console/Command/SetModeCommand.php index 0d6e790c593cc..c258c2b811926 100644 --- a/app/code/Magento/Deploy/Console/Command/SetModeCommand.php +++ b/app/code/Magento/Deploy/Console/Command/SetModeCommand.php @@ -52,7 +52,7 @@ public function __construct(ObjectManagerInterface $objectManager) */ protected function configure() { - $description = 'Displays current application mode.'; + $description = 'Set application mode.'; $this->setName('deploy:mode:set') ->setDescription($description) diff --git a/app/code/Magento/Downloadable/composer.json b/app/code/Magento/Downloadable/composer.json index e2d2d2138672e..a1b7591bf9a53 100644 --- a/app/code/Magento/Downloadable/composer.json +++ b/app/code/Magento/Downloadable/composer.json @@ -20,6 +20,9 @@ "magento/module-quote": "1.0.0-beta", "magento/framework": "1.0.0-beta" }, + "suggest": { + "magento/module-downloadable-sample-data": "Sample Data version:1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/GroupedProduct/composer.json b/app/code/Magento/GroupedProduct/composer.json index 3cb4722b9d07d..d1d08ab09e6c2 100644 --- a/app/code/Magento/GroupedProduct/composer.json +++ b/app/code/Magento/GroupedProduct/composer.json @@ -16,6 +16,9 @@ "magento/module-quote": "1.0.0-beta", "magento/framework": "1.0.0-beta" }, + "suggest": { + "magento/module-grouped-product-sample-data": "Sample Data version:1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/ImportExport/Model/Export/Config/Converter.php b/app/code/Magento/ImportExport/Model/Export/Config/Converter.php index b550e4166ab64..3482dae1ccdbf 100644 --- a/app/code/Magento/ImportExport/Model/Export/Config/Converter.php +++ b/app/code/Magento/ImportExport/Model/Export/Config/Converter.php @@ -5,8 +5,24 @@ */ namespace Magento\ImportExport\Model\Export\Config; +use Magento\Framework\Module\Manager; +use Magento\Framework\App\Utility\Classes; + class Converter implements \Magento\Framework\Config\ConverterInterface { + /** + * @var \Magento\Framework\Module\Manager + */ + protected $moduleManager; + + /** + * @param Manager $moduleManager + */ + public function __construct(Manager $moduleManager) + { + $this->moduleManager = $moduleManager; + } + /** * Convert dom node tree to array * @@ -25,6 +41,9 @@ public function convert($source) $name = $attributes->getNamedItem('name')->nodeValue; $label = $attributes->getNamedItem('label')->nodeValue; $model = $attributes->getNamedItem('model')->nodeValue; + if (!$this->moduleManager->isOutputEnabled(Classes::getClassModuleName($model))) { + continue; + } $entityAttributeFilterType = $attributes->getNamedItem('entityAttributeFilterType')->nodeValue; $output['entities'][$name] = [ diff --git a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php index 9ff3b8c8b45ec..82ec9f0695008 100644 --- a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php +++ b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEntity.php @@ -414,7 +414,7 @@ public function getAttributeOptions(\Magento\Eav\Model\Entity\Attribute\Abstract foreach (is_array($option['value']) ? $option['value'] : [$option] as $innerOption) { if (strlen($innerOption['value'])) { // skip ' -- Please Select -- ' option - $options[$innerOption['value']] = $innerOption[$index]; + $options[$innerOption['value']] = (string)$innerOption[$index]; } } } diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php index 94a7c1a6dd3c1..00630ce29e2cf 100644 --- a/app/code/Magento/ImportExport/Model/Import.php +++ b/app/code/Magento/ImportExport/Model/Import.php @@ -316,10 +316,11 @@ public function getOperationResultMessages(ProcessingErrorAggregatorInterface $v */ public static function getAttributeType(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute) { - if ($attribute->usesSource() && in_array($attribute->getFrontendInput(), ['select', 'multiselect'])) { - return $attribute->getFrontendInput() == 'multiselect' ? 'multiselect' : 'select'; + $frontendInput = $attribute->getFrontendInput(); + if ($attribute->usesSource() && in_array($frontendInput, ['select', 'multiselect', 'boolean'])) { + return $frontendInput; } elseif ($attribute->isStatic()) { - return $attribute->getFrontendInput() == 'date' ? 'datetime' : 'varchar'; + return $frontendInput == 'date' ? 'datetime' : 'varchar'; } else { return $attribute->getBackendType(); } diff --git a/app/code/Magento/ImportExport/Model/Import/Config/Converter.php b/app/code/Magento/ImportExport/Model/Import/Config/Converter.php index ef57125968afe..9bf10ab0c8f88 100644 --- a/app/code/Magento/ImportExport/Model/Import/Config/Converter.php +++ b/app/code/Magento/ImportExport/Model/Import/Config/Converter.php @@ -5,8 +5,24 @@ */ namespace Magento\ImportExport\Model\Import\Config; +use Magento\Framework\Module\Manager; +use Magento\Framework\App\Utility\Classes; + class Converter implements \Magento\Framework\Config\ConverterInterface { + /** + * @var \Magento\Framework\Module\Manager + */ + protected $moduleManager; + + /** + * @param Manager $moduleManager + */ + public function __construct(Manager $moduleManager) + { + $this->moduleManager = $moduleManager; + } + /** * Convert dom node tree to array * @@ -26,7 +42,9 @@ public function convert($source) $label = $attributes->getNamedItem('label')->nodeValue; $behaviorModel = $attributes->getNamedItem('behaviorModel')->nodeValue; $model = $attributes->getNamedItem('model')->nodeValue; - + if (!$this->moduleManager->isOutputEnabled(Classes::getClassModuleName($model))) { + continue; + } $output['entities'][$name] = [ 'name' => $name, 'label' => $label, diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/ConverterTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/ConverterTest.php index f47fd710c6b2c..05702baf8cbc2 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/ConverterTest.php +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/ConverterTest.php @@ -10,25 +10,48 @@ class ConverterTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\ImportExport\Model\Export\Config\Converter */ - protected $_model; + protected $model; /** * @var string */ - protected $_filePath; + protected $filePath; + + /** + * @var \Magento\Framework\Module\Manager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $moduleManager; public function setUp() { - $this->_filePath = realpath(__DIR__) . '/_files/'; - $this->_model = new \Magento\ImportExport\Model\Export\Config\Converter(); + $this->filePath = realpath(__DIR__) . '/_files/'; + $this->moduleManager = $this->getMock('Magento\Framework\Module\Manager', ['isOutputEnabled'], [], '', false); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManagerHelper->getObject( + '\Magento\ImportExport\Model\Export\Config\Converter', + [ + 'moduleManager' => $this->moduleManager + ] + ); } public function testConvert() { - $testDom = $this->_filePath . 'export.xml'; + $testDom = $this->filePath . 'export.xml'; + $dom = new \DOMDocument(); + $dom->load($testDom); + $expectedArray = include $this->filePath . 'export.php'; + $this->moduleManager->expects($this->any())->method('isOutputEnabled')->willReturn(true); + $this->assertEquals($expectedArray, $this->model->convert($dom)); + } + + public function testConvertWithDisabledModules() + { + $testDom = $this->filePath . 'export.xml'; $dom = new \DOMDocument(); $dom->load($testDom); - $expectedArray = include $this->_filePath . 'export.php'; - $this->assertEquals($expectedArray, $this->_model->convert($dom)); + $notExpectedArray = include $this->filePath . 'export.php'; + $this->moduleManager->expects($this->any())->method('isOutputEnabled')->willReturn(false); + $this->assertNotEquals($notExpectedArray, $this->model->convert($dom)); } } diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.php b/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.php index d847c695030c6..a1be63196883a 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.php +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.php @@ -8,25 +8,25 @@ 'product' => [ 'name' => 'product', 'label' => 'Label_One', - 'model' => 'Model_One', + 'model' => 'Model\One', 'types' => [ - 'product_type_one' => ['name' => 'product_type_one', 'model' => 'Product_Model_Type_One'], - 'type_two' => ['name' => 'type_two', 'model' => 'Model_Type_Two'], + 'product_type_one' => ['name' => 'product_type_one', 'model' => 'Product\Model\Type\One'], + 'type_two' => ['name' => 'type_two', 'model' => 'Model\Type\Two'], ], 'entityAttributeFilterType' => 'product', ], 'customer' => [ 'name' => 'customer', 'label' => 'Label_One', - 'model' => 'Model_One', + 'model' => 'Model\One', 'types' => [ - 'type_one' => ['name' => 'type_one', 'model' => 'Model_Type_One'], - 'type_two' => ['name' => 'type_two', 'model' => 'Model_Type_Two'], + 'type_one' => ['name' => 'type_one', 'model' => 'Model\Type\One'], + 'type_two' => ['name' => 'type_two', 'model' => 'Model\Type\Two'], ], 'entityAttributeFilterType' => 'customer', ], ], 'fileFormats' => [ - 'name_three' => ['name' => 'name_three', 'model' => 'Model_Three', 'label' => 'Label_Three'], + 'name_three' => ['name' => 'name_three', 'model' => 'Model\Three', 'label' => 'Label_Three'], ] ]; diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.xml b/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.xml index 8cd0f31a7662e..bf6288e2b31b4 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.xml +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Export/Config/_files/export.xml @@ -6,11 +6,11 @@ */ --> - - - - - - - + + + + + + + diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/ConverterTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/ConverterTest.php index a35552ddec2dc..dc5bc38f019fa 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/ConverterTest.php +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/ConverterTest.php @@ -10,25 +10,48 @@ class ConverterTest extends \PHPUnit_Framework_TestCase /** * @var \Magento\ImportExport\Model\Import\Config\Converter */ - protected $_model; + protected $model; /** * @var string */ - protected $_filePath; + protected $filePath; + + /** + * @var \Magento\Framework\Module\Manager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $moduleManager; public function setUp() { - $this->_filePath = realpath(__DIR__) . '/_files/'; - $this->_model = new \Magento\ImportExport\Model\Import\Config\Converter(); + $this->filePath = realpath(__DIR__) . '/_files/'; + $this->moduleManager = $this->getMock('Magento\Framework\Module\Manager', ['isOutputEnabled'], [], '', false); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManagerHelper->getObject( + '\Magento\ImportExport\Model\Import\Config\Converter', + [ + 'moduleManager' => $this->moduleManager + ] + ); } public function testConvert() { - $testDom = $this->_filePath . 'import.xml'; + $testDom = $this->filePath . 'import.xml'; + $dom = new \DOMDocument(); + $dom->load($testDom); + $expectedArray = include $this->filePath . 'import.php'; + $this->moduleManager->expects($this->any())->method('isOutputEnabled')->willReturn(true); + $this->assertEquals($expectedArray, $this->model->convert($dom)); + } + + public function testConvertWithDisabledModules() + { + $testDom = $this->filePath . 'import.xml'; $dom = new \DOMDocument(); $dom->load($testDom); - $expectedArray = include $this->_filePath . 'import.php'; - $this->assertEquals($expectedArray, $this->_model->convert($dom)); + $notExpectedArray = include $this->filePath . 'import.php'; + $this->moduleManager->expects($this->any())->method('isOutputEnabled')->willReturn(false); + $this->assertNotEquals($notExpectedArray, $this->model->convert($dom)); } } diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.php index 8c2f69aae9875..b663a59807164 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.php +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.php @@ -9,15 +9,15 @@ 'name' => 'product', 'label' => 'Label_One', 'behaviorModel' => 'Model_Basic', - 'model' => 'Model_One', + 'model' => 'Model\One', 'types' => [ 'product_type_one' => [ 'name' => 'product_type_one', - 'model' => 'Product_Type_One', + 'model' => 'Product\Type\One', ], 'type_two' => [ 'name' => 'type_two', - 'model' => 'Product_Type_Two', + 'model' => 'Product\Type\Two', ], ], 'relatedIndexers' => [ @@ -33,15 +33,15 @@ 'name' => 'customer', 'label' => 'Label_One', 'behaviorModel' => 'Model_Basic', - 'model' => 'Model_One', + 'model' => 'Model\One', 'types' => [ 'customer_type_one' => [ 'name' => 'customer_type_one', - 'model' => 'Customer_Type_One', + 'model' => 'Customer\Type\One', ], 'type_two' => [ 'name' => 'type_two', - 'model' => 'Customer_Type_Two', + 'model' => 'Customer\Type\Two', ], ], 'relatedIndexers' => [ diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.xml b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.xml index e289b33b54d12..1aa4e732fda48 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.xml +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/Config/_files/import.xml @@ -6,12 +6,12 @@ */ --> - - - - - - + + + + + + diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php index 9e65d5516c612..c059dffe43128 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php +++ b/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php @@ -322,7 +322,13 @@ public function testGetOperationResultMessages() */ public function testGetAttributeType() { - $this->markTestIncomplete('This test has not been implemented yet.'); + /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */ + $attribute = $this->getMockBuilder('\Magento\Eav\Model\Entity\Attribute\AbstractAttribute') + ->setMethods(['getFrontendInput', 'usesSource']) + ->disableOriginalConstructor()->getMock(); + $attribute->expects($this->any())->method('getFrontendInput')->willReturn('boolean'); + $attribute->expects($this->any())->method('usesSource')->willReturn(true); + $this->assertEquals('boolean', $this->import->getAttributeType($attribute)); } /** diff --git a/app/code/Magento/Msrp/composer.json b/app/code/Magento/Msrp/composer.json index afa0ef50405d1..0f1e1d343d783 100644 --- a/app/code/Magento/Msrp/composer.json +++ b/app/code/Magento/Msrp/composer.json @@ -12,7 +12,8 @@ "magento/framework": "1.0.0-beta" }, "suggest": { - "magento/module-bundle": "1.0.0-beta" + "magento/module-bundle": "1.0.0-beta", + "magento/module-msrp-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json index bb186fb3aeaa7..37d63fb749b2a 100644 --- a/app/code/Magento/OfflineShipping/composer.json +++ b/app/code/Magento/OfflineShipping/composer.json @@ -15,7 +15,8 @@ "magento/framework": "1.0.0-beta" }, "suggest": { - "magento/module-checkout": "1.0.0-beta" + "magento/module-checkout": "1.0.0-beta", + "magento/module-offline-shipping-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/Review/composer.json b/app/code/Magento/Review/composer.json index e5c9d93520156..72317bb39e3ec 100644 --- a/app/code/Magento/Review/composer.json +++ b/app/code/Magento/Review/composer.json @@ -14,7 +14,8 @@ "magento/module-ui": "1.0.0-beta" }, "suggest": { - "magento/module-cookie": "1.0.0-beta" + "magento/module-cookie": "1.0.0-beta", + "magento/module-review-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/Sales/composer.json b/app/code/Magento/Sales/composer.json index 077a1ef5590d8..3912b493e181e 100644 --- a/app/code/Magento/Sales/composer.json +++ b/app/code/Magento/Sales/composer.json @@ -28,6 +28,9 @@ "magento/module-ui": "1.0.0-beta", "magento/module-quote": "1.0.0-beta" }, + "suggest": { + "magento/module-sales-sample-data": "Sample Data version:1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json index 681974c676cdc..fb676265acfa0 100644 --- a/app/code/Magento/SalesRule/composer.json +++ b/app/code/Magento/SalesRule/composer.json @@ -20,6 +20,9 @@ "magento/module-quote": "1.0.0-beta", "magento/framework": "1.0.0-beta" }, + "suggest": { + "magento/module-sales-rule-sample-data": "Sample Data version:1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php b/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php new file mode 100644 index 0000000000000..8b3ca20ca09c9 --- /dev/null +++ b/app/code/Magento/SampleData/Console/Command/SampleDataDeployCommand.php @@ -0,0 +1,104 @@ +filesystem = $filesystem; + $this->sampleDataDependency = $sampleDataDependency; + $this->arrayInputFactory = $arrayInputFactory; + $this->applicationFactory = $applicationFactory; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('sampledata:deploy') + ->setDescription('Deploy sample data modules'); + parent::configure(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $sampleDataPackages = $this->sampleDataDependency->getSampleDataPackages(); + if (!empty($sampleDataPackages)) { + $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); + $commonArgs = ['--working-dir' => $baseDir, '--no-interaction' => 1, '--no-progress' => 1]; + $packages = []; + foreach ($sampleDataPackages as $name => $version) { + $packages[] = "$name:$version"; + } + $commonArgs = array_merge(['packages' => $packages], $commonArgs); + $arguments = array_merge(['command' => 'require'], $commonArgs); + /** @var ArrayInput $commandInput */ + $commandInput = $this->arrayInputFactory->create(['parameters' => $arguments]); + + /** @var Application $application */ + $application = $this->applicationFactory->create(); + $application->setAutoExit(false); + $result = $application->run($commandInput, $output); + if ($result !== 0) { + $output->writeln('' . 'There is an error during sample data deployment.' . ''); + } + } else { + $output->writeln('' . 'There is no sample data for current set of modules.' . ''); + } + } +} diff --git a/app/code/Magento/SampleData/Console/Command/SampleDataRemoveCommand.php b/app/code/Magento/SampleData/Console/Command/SampleDataRemoveCommand.php new file mode 100644 index 0000000000000..d5c2bbfd37ec6 --- /dev/null +++ b/app/code/Magento/SampleData/Console/Command/SampleDataRemoveCommand.php @@ -0,0 +1,99 @@ +filesystem = $filesystem; + $this->sampleDataDependency = $sampleDataDependency; + $this->arrayInputFactory = $arrayInputFactory; + $this->applicationFactory = $applicationFactory; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('sampledata:remove') + ->setDescription('Remove all sample data packages from composer.json'); + parent::configure(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $sampleDataPackages = $this->sampleDataDependency->getSampleDataPackages(); + if (!empty($sampleDataPackages)) { + $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); + $commonArgs = ['--working-dir' => $baseDir, '--no-interaction' => 1, '--no-progress' => 1]; + $packages = array_keys($sampleDataPackages); + $arguments = array_merge(['command' => 'remove', 'packages' => $packages], $commonArgs); + /** @var ArrayInput $commandInput */ + $commandInput = $this->arrayInputFactory->create(['parameters' => $arguments]); + + /** @var Application $application */ + $application = $this->applicationFactory->create(); + $application->setAutoExit(false); + $result = $application->run($commandInput, $output); + if ($result !== 0) { + $output->writeln('' . 'There is an error during remove sample data.' . ''); + } + } else { + $output->writeln('' . 'There is no sample data for current set of modules.' . ''); + } + } +} diff --git a/app/code/Magento/SampleData/Console/Command/SampleDataResetCommand.php b/app/code/Magento/SampleData/Console/Command/SampleDataResetCommand.php new file mode 100644 index 0000000000000..b0ee73fae602d --- /dev/null +++ b/app/code/Magento/SampleData/Console/Command/SampleDataResetCommand.php @@ -0,0 +1,76 @@ +sampleDataDependency = $sampleDataDependency; + $this->moduleResource = $moduleResource; + $this->packageInfo = $packageInfo; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('sampledata:reset') + ->setDescription('Reset all sample data modules for re-installation'); + parent::configure(); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $sampleDataPackages = $this->sampleDataDependency->getSampleDataPackages(); + if (!empty($sampleDataPackages)) { + foreach (array_keys($sampleDataPackages) as $name) { + $moduleName = $this->packageInfo->getModuleName($name); + $this->moduleResource->setDataVersion($moduleName, ''); + } + $output->writeln('' . 'Reset of sample data version completed successfully.' . ''); + } else { + $output->writeln('' . 'There is no sample data for current set of modules.' . ''); + } + } +} diff --git a/app/code/Magento/SampleData/Console/CommandList.php b/app/code/Magento/SampleData/Console/CommandList.php new file mode 100644 index 0000000000000..c6a4df47af8bf --- /dev/null +++ b/app/code/Magento/SampleData/Console/CommandList.php @@ -0,0 +1,58 @@ +objectManager = $objectManager; + } + + /** + * Gets list of command classes + * + * @return string[] + */ + protected function getCommandsClasses() + { + return [ + 'Magento\SampleData\Console\Command\SampleDataDeployCommand', + 'Magento\SampleData\Console\Command\SampleDataRemoveCommand' + ]; + } + + /** + * {@inheritdoc} + */ + public function getCommands() + { + $commands = []; + foreach ($this->getCommandsClasses() as $class) { + if (class_exists($class)) { + $commands[] = $this->objectManager->get($class); + } else { + throw new \Exception('Class ' . $class . ' does not exist'); + } + } + return $commands; + } +} diff --git a/app/code/Magento/SampleData/Model/BlackHole.php b/app/code/Magento/SampleData/Model/BlackHole.php new file mode 100644 index 0000000000000..06f557d318484 --- /dev/null +++ b/app/code/Magento/SampleData/Model/BlackHole.php @@ -0,0 +1,22 @@ +composerInformation = $composerInformation; + $this->filesystem = $filesystem; + $this->packageFactory = $packageFactory; + $this->componentRegistrar = $componentRegistrar; + } + + /** + * Retrieve list of sample data packages from suggests + * + * @return array + */ + public function getSampleDataPackages() + { + $installExtensions = []; + $suggests = $this->composerInformation->getSuggestedPackages(); + $suggests = array_merge($suggests, $this->getSuggestsFromModules()); + foreach ($suggests as $name => $version) { + if (strpos($version, self::SAMPLE_DATA_SUGGEST) === 0) { + $installExtensions[$name] = substr($version, strlen(self::SAMPLE_DATA_SUGGEST)); + } + } + return $installExtensions; + } + + /** + * Retrieve suggested sample data packages from modules composer.json + * + * @return array + */ + protected function getSuggestsFromModules() + { + $suggests = []; + foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) { + $file = $moduleDir . '/composer.json'; + + /** @var Package $package */ + $package = $this->getModuleComposerPackage($file); + $suggest = json_decode(json_encode($package->get('suggest')), true); + if (!empty($suggest)) { + $suggests += $suggest; + } + } + return $suggests; + } + + /** + * Load package + * + * @param string $file + * @return Package + */ + protected function getModuleComposerPackage($file) + { + return $this->packageFactory->create(['json' => json_decode(file_get_contents($file))]); + } +} diff --git a/app/code/Magento/SampleData/README.md b/app/code/Magento/SampleData/README.md new file mode 100644 index 0000000000000..3ab503211a258 --- /dev/null +++ b/app/code/Magento/SampleData/README.md @@ -0,0 +1,83 @@ +# Introduction + +Magento sample data uses the responsive Luma theme to display a sample store, complete with products, categories, promotional price rules, CMS pages, banners, and so on. You can use the sample data to come up to speed quickly and see the power and flexibility of the Magento storefront. + +Installing sample data is optional; you can install it before or after you install the Magento software. + +# Deployment + +Deployment of Sample Data can be performed in three ways: using Magento CLI, composer and from GitHub repository. + +## Using CLI + +SampleData module is included to default scope of Magento CE modules. To deploy other sample data modules (e.g. ConfigurableSampleData, CatalogSampleData e.t.c) Magento CLI command can be used: + +``` +# bin/magento sampledata:deploy +``` + +CLI command collects suggest node from composer.json files of modules which suggest to install sample data: + +``` +"suggest": { + "magento/module-catalog-sample-data": "Sample Data version:1.0.0-beta" +} +``` + +## Using Composer + +Also it's possible to add needed sample data modules manually (via composer require or editing main composer.json file) + +1. Specify packages +``` +{ + "require": { + ... + "magento/module-catalog-sample-data": "{version}", + "magento/module-configurable-sample-data": "{version}", + "magento/module-cms-sample-data": "{version}", + "magento/module-sales-sample-data": "{version}" + .... + } + } +{version} - Go to packages.magento.com and write down suitable versions of magento/sample-data and magento/sample-data-media (typically, you should choose the most recent version). +``` +2. Run composer update from your Magento root directory + +## From GitHub Repository + +1. Clone Sample Data from https://github.com/magento/magento2-sample-data +2. Link Sample Data and Magento Edition using tool /dev/tools/build-sample-data.php +``` +php -f /dev/tools/build-sample-data.php -- --ce-source="path/to/magento/ce/edition" +``` + +# Installing + +Being once deployed the Sample Data is available for installation through the Magento Setup Wizard or using CLI. + +## Web Installation + +Deployed SampleData modules have been selected to be installed by default. To prepare installation Magento with SampleData finish installation as you do it usual. In success page user will be notified about successfully installed SampleData + +## Console Installation + +Use Magento CLI installation command to install Magento as usual. + +# Uninstalling + +There is CLI command which allows to remove all sample data modules from Magento (only for case when sample data was installed via composer): + +``` +# bin/magento sampledata:remove +``` + +# Re-installation + +To prepare sample data for re installation process run: + +``` +# bin/magento sampledata:reset +``` + +Then install or upgrade Magento as usual diff --git a/app/code/Magento/SampleData/Setup/InstallData.php b/app/code/Magento/SampleData/Setup/InstallData.php new file mode 100644 index 0000000000000..734aa424918b3 --- /dev/null +++ b/app/code/Magento/SampleData/Setup/InstallData.php @@ -0,0 +1,36 @@ +state = $state; + } + + /** + * @inheritdoc + */ + public function install(Setup\ModuleDataSetupInterface $setup, Setup\ModuleContextInterface $moduleContext) + { + $this->state->clearState(); + } +} diff --git a/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php new file mode 100644 index 0000000000000..cbc3d330e725b --- /dev/null +++ b/app/code/Magento/SampleData/Test/Unit/Console/Command/SampleDataDeployCommandTest.php @@ -0,0 +1,65 @@ +markTestSkipped('MAGETWO-43636: This test should be fixed by NORD team'); + $directoryRead = $this->getMock('\Magento\Framework\Filesystem\Directory\ReadInterface', [], [], '', false); + $directoryRead->expects($this->atLeastOnce())->method('getAbsolutePath')->willReturn('/path/to/composer.json'); + + $filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false); + $filesystem->expects($this->atLeastOnce())->method('getDirectoryRead')->with(DirectoryList::ROOT) + ->willReturn($directoryRead); + + $sampleDataDependency = $this->getMock('Magento\SampleData\Model\Dependency', [], [], '', false); + $sampleDataDependency->expects($this->atLeastOnce())->method('getSampleDataPackages')->willReturn( + [ + 'magento/module-cms-sample-data' => '1.0.0-beta' + ] + ); + + $arrayInput = $this->getMock('Symfony\Component\Console\Input\ArrayInput', [], [], '', false); + + $arrayInputFactory = $this + ->getMock('Symfony\Component\Console\Input\ArrayInputFactory', ['create'], [], '', false); + $requireArgs = [ + 'command' => 'require', + '--working-dir' => '/path/to/composer.json', + '--no-interaction' => 1, + '--no-progress' => 1, + 'packages' => ['magento/module-cms-sample-data:1.0.0-beta'] + ]; + $arrayInputFactory->expects($this->atLeastOnce()) + ->method('create') + ->with(['parameters' => $requireArgs]) + ->willReturn($arrayInput); + $application = $this->getMock('Composer\Console\Application', [], [], '', false); + $application->expects($this->atLeastOnce())->method('run')->with($arrayInput, $this->anything()) + ->willReturnCallback(function ($input, $output) { + $input->getFirstArgument(); + $output->writeln('./composer.json has been updated'); + }); + + $applicationFactory = $this->getMock('Composer\Console\ApplicationFactory', ['create'], [], '', false); + $applicationFactory->expects($this->atLeastOnce())->method('create')->willReturn($application); + + $commandTester = new CommandTester( + new SampleDataDeployCommand($filesystem, $sampleDataDependency, $arrayInputFactory, $applicationFactory) + ); + $commandTester->execute([]); + + $expectedMsg = './composer.json has been updated' . PHP_EOL; + + $this->assertEquals($expectedMsg, $commandTester->getDisplay()); + } +} diff --git a/app/code/Magento/SampleData/cli_commands.php b/app/code/Magento/SampleData/cli_commands.php new file mode 100644 index 0000000000000..910351b75fac1 --- /dev/null +++ b/app/code/Magento/SampleData/cli_commands.php @@ -0,0 +1,9 @@ + + + + + + + Magento\SampleData\Console\Command\SampleDataDeployCommand + Magento\SampleData\Console\Command\SampleDataResetCommand + Magento\SampleData\Console\Command\SampleDataRemoveCommand + + + + + + Magento\SampleData\Model\BlackHole + + + + + Magento\SampleData\Model\BlackHoleFactory + + + + + blackHoleTransportBuilder + + + + + sampleDataAccountManagement + + + diff --git a/app/code/Magento/SampleData/etc/module.xml b/app/code/Magento/SampleData/etc/module.xml new file mode 100644 index 0000000000000..37798ad6de894 --- /dev/null +++ b/app/code/Magento/SampleData/etc/module.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/code/Magento/SampleData/registration.php b/app/code/Magento/SampleData/registration.php new file mode 100644 index 0000000000000..7dfbb9f61f8a2 --- /dev/null +++ b/app/code/Magento/SampleData/registration.php @@ -0,0 +1,11 @@ + value) $.each(item.options, function () { - $widget.optionsMap[item.id][this.id] = { - price: parseInt($widget.options.jsonConfig.optionPrices[this.products[0]].finalPrice.amount, 10), - products: this.products - }; + if (this.products.length > 0) { + $widget.optionsMap[item.id][this.id] = { + price: parseInt($widget.options.jsonConfig.optionPrices[this.products[0]].finalPrice.amount, 10), + products: this.products + }; + } }); }); diff --git a/app/code/Magento/Tax/composer.json b/app/code/Magento/Tax/composer.json index 7645004662e00..72c9306f68cd2 100644 --- a/app/code/Magento/Tax/composer.json +++ b/app/code/Magento/Tax/composer.json @@ -18,6 +18,9 @@ "magento/module-quote": "1.0.0-beta", "magento/framework": "1.0.0-beta" }, + "suggest": { + "magento/module-tax-sample-data": "Sample Data version:1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/Theme/composer.json b/app/code/Magento/Theme/composer.json index ef001d016fb95..ad1c0e03e882e 100644 --- a/app/code/Magento/Theme/composer.json +++ b/app/code/Magento/Theme/composer.json @@ -15,7 +15,8 @@ "magento/module-require-js": "1.0.0-beta" }, "suggest": { - "magento/module-translation": "1.0.0-beta" + "magento/module-translation": "1.0.0-beta", + "magento/module-theme-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/app/code/Magento/Widget/composer.json b/app/code/Magento/Widget/composer.json index e828ca94217d8..0a34d51959468 100644 --- a/app/code/Magento/Widget/composer.json +++ b/app/code/Magento/Widget/composer.json @@ -12,6 +12,9 @@ "magento/framework": "1.0.0-beta", "magento/module-variable": "1.0.0-beta" }, + "suggest": { + "magento/module-widget-sample-data": "Sample Data version:1.0.0-beta" + }, "type": "magento2-module", "version": "1.0.0-beta", "license": [ diff --git a/app/code/Magento/Wishlist/composer.json b/app/code/Magento/Wishlist/composer.json index 0531ad4cc0b0b..1fa74f94a8571 100644 --- a/app/code/Magento/Wishlist/composer.json +++ b/app/code/Magento/Wishlist/composer.json @@ -20,7 +20,8 @@ "magento/module-configurable-product": "1.0.0-beta", "magento/module-downloadable": "1.0.0-beta", "magento/module-bundle": "1.0.0-beta", - "magento/module-cookie": "1.0.0-beta" + "magento/module-cookie": "1.0.0-beta", + "magento/module-wishlist-sample-data": "Sample Data version:1.0.0-beta" }, "type": "magento2-module", "version": "1.0.0-beta", diff --git a/composer.json b/composer.json index b9bfa65c39a8c..eba9d9b53c2f7 100644 --- a/composer.json +++ b/composer.json @@ -149,6 +149,7 @@ "magento/module-sales": "self.version", "magento/module-sales-rule": "self.version", "magento/module-sales-sequence": "self.version", + "magento/module-sample-data": "self.version", "magento/module-search": "self.version", "magento/module-send-friend": "self.version", "magento/module-shipping": "self.version", @@ -223,7 +224,10 @@ "psr-0": { "": "app/code/" }, - "files": ["app/etc/NonComposerComponentRegistration.php"] + "files": [ + "app/etc/NonComposerComponentRegistration.php", + "app/code/Magento/SampleData/cli_commands.php" + ] }, "autoload-dev": { "psr-4": { diff --git a/composer.lock b/composer.lock index cfa0e8c41d943..6fd412b7ba5bc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "25a5ae0bdd6b3ea879ab1140483c493e", - "content-hash": "05d5894f85b00df1148fd6ca99e33b82", + "hash": "1de4f3f96c81c1ff19a057f4c6121927", "packages": [ { "name": "braintree/braintree_php", @@ -2845,16 +2844,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "2.2.3", + "version": "2.2.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ef1ca6835468857944d5c3b48fa503d5554cff2f" + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef1ca6835468857944d5c3b48fa503d5554cff2f", - "reference": "ef1ca6835468857944d5c3b48fa503d5554cff2f", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", "shasum": "" }, "require": { @@ -2903,7 +2902,7 @@ "testing", "xunit" ], - "time": "2015-09-14 06:51:16" + "time": "2015-10-06 15:47:00" }, { "name": "phpunit/php-file-iterator", diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php b/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php index 590a553274d7d..542d25af339ac 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php @@ -110,6 +110,27 @@ public function testGetRequiredExtensions($composerDir) } } + /** + * @param $composerDir string Directory under _files that contains composer files + * + * @dataProvider getRequiredPhpVersionDataProvider + */ + public function testGetSuggestedPackages($composerDir) + { + $this->setupDirectory($composerDir); + $composerInfo = $this->objectManager->create( + 'Magento\Framework\Composer\ComposerInformation', + [ + 'applicationFactory' => new MagentoComposerApplicationFactory( + $this->composerJsonFinder, + $this->directoryList + ) + ] + ); + $actualSuggestedExtensions = $composerInfo->getSuggestedPackages(); + $this->assertArrayHasKey('psr/log', $actualSuggestedExtensions); + } + /** * @param $composerDir string Directory under _files that contains composer files * diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php index 815ce953c3176..530d99c68dcdf 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php @@ -194,7 +194,7 @@ private function assertAutoloadRegistrar(\StdClass $json, $dir) $error = 'There must be an "autoload->files" node in composer.json of each Magento component.'; $this->assertObjectHasAttribute('autoload', $json, $error); $this->assertObjectHasAttribute('files', $json->autoload, $error); - $this->assertEquals([ "registration.php" ], $json->autoload->files, $error); + $this->assertTrue(in_array("registration.php", $json->autoload->files), $error); $this->assertFileExists("$dir/registration.php"); } diff --git a/lib/internal/Magento/Framework/App/Utility/Files.php b/lib/internal/Magento/Framework/App/Utility/Files.php index f5255ea78fe90..e19dd388fc6d3 100644 --- a/lib/internal/Magento/Framework/App/Utility/Files.php +++ b/lib/internal/Magento/Framework/App/Utility/Files.php @@ -273,6 +273,7 @@ private function getAppCodeFiles($flags) } else { foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) { $excludePaths[] = str_replace('\\', '/', '#' . $moduleDir . '/registration.php#'); + $excludePaths[] = str_replace('\\', '/', '#' . $moduleDir . '/cli_commands.php#'); } } return $this->getFilesSubset( diff --git a/lib/internal/Magento/Framework/Composer/ComposerInformation.php b/lib/internal/Magento/Framework/Composer/ComposerInformation.php index f03865e53024b..0f9c9d489b2a2 100755 --- a/lib/internal/Magento/Framework/Composer/ComposerInformation.php +++ b/lib/internal/Magento/Framework/Composer/ComposerInformation.php @@ -159,6 +159,24 @@ public function getRequiredExtensions() return array_unique($requiredExtensions); } + /** + * Retrieve list of suggested extensions + * + * Collect suggests from composer.lock file and modules composer.json files + * + * @return array + */ + public function getSuggestedPackages() + { + $suggests = []; + /** @var \Composer\Package\CompletePackage $package */ + foreach ($this->locker->getLockedRepository()->getPackages() as $package) { + $suggests += $package->getSuggests(); + } + + return array_unique($suggests); + } + /** * Collect required packages from root composer.lock file * diff --git a/lib/internal/Magento/Framework/Console/Cli.php b/lib/internal/Magento/Framework/Console/Cli.php index 72ca214b1fbcf..786a658b7e9ac 100644 --- a/lib/internal/Magento/Framework/Console/Cli.php +++ b/lib/internal/Magento/Framework/Console/Cli.php @@ -62,11 +62,34 @@ protected function getApplicationCommands() $modulesCommands = $commandList->getCommands(); } + $vendorCommands = $this->getVendorCommands($objectManager); + $commandsList = array_merge( $setupCommands, - $modulesCommands + $modulesCommands, + $vendorCommands ); return $commandsList; } + + /** + * Gets vendor commands + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @return array + */ + protected function getVendorCommands($objectManager) + { + $commands = []; + foreach (CommandLocator::getCommands() as $commandListClass) { + if (class_exists($commandListClass)) { + $commands = array_merge( + $commands, + $objectManager->create($commandListClass)->getCommands() + ); + } + } + return $commands; + } } diff --git a/lib/internal/Magento/Framework/Console/CommandList.php b/lib/internal/Magento/Framework/Console/CommandList.php index 99519a396d16b..b754a637f4bb8 100644 --- a/lib/internal/Magento/Framework/Console/CommandList.php +++ b/lib/internal/Magento/Framework/Console/CommandList.php @@ -9,7 +9,7 @@ /** * Class CommandList has a list of commands, which can be extended via DI configuration. */ -class CommandList +class CommandList implements CommandListInterface { /** * @var string[] @@ -27,9 +27,7 @@ public function __construct(array $commands = []) } /** - * Gets list of command instances - * - * @return \Symfony\Component\Console\Command\Command[] + * {@inheritdoc} */ public function getCommands() { diff --git a/lib/internal/Magento/Framework/Console/CommandListInterface.php b/lib/internal/Magento/Framework/Console/CommandListInterface.php new file mode 100644 index 0000000000000..b15780716381a --- /dev/null +++ b/lib/internal/Magento/Framework/Console/CommandListInterface.php @@ -0,0 +1,19 @@ +_result = $this->_moveFile($this->_file['tmp_name'], $destinationFile); if ($this->_result) { - chmod($destinationFile, DriverInterface::WRITEABLE_DIRECTORY_MODE); + $this->chmod($destinationFile); if ($this->_enableFilesDispersion) { $fileName = str_replace('\\', '/', self::_addDirSeparator($this->_dispretionPath)) . $fileName; } @@ -239,6 +239,15 @@ public function save($destinationFolder, $newFileName = null) return $this->_result; } + /** + * @param string $file + * @return void + */ + protected function chmod($file) + { + chmod($file, DriverInterface::WRITEABLE_DIRECTORY_MODE); + } + /** * Move files from TMP folder into destination folder * diff --git a/lib/internal/Magento/Framework/Setup/SampleData/Context.php b/lib/internal/Magento/Framework/Setup/SampleData/Context.php new file mode 100644 index 0000000000000..2624bfb20bea0 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/SampleData/Context.php @@ -0,0 +1,50 @@ +fixtureManager = $fixtureManager; + $this->csvReader = $csvReader; + } + + /** + * @return FixtureManager + */ + public function getFixtureManager() + { + return $this->fixtureManager; + } + + /** + * @return Csv + */ + public function getCsvReader() + { + return $this->csvReader; + } +} diff --git a/lib/internal/Magento/Framework/Setup/SampleData/Executor.php b/lib/internal/Magento/Framework/Setup/SampleData/Executor.php new file mode 100644 index 0000000000000..2a71963fb6614 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/SampleData/Executor.php @@ -0,0 +1,39 @@ +logger = $logger; + $this->state = $state; + } + + /** + * Execute SampleData module installation. + * Catch exception if it appeared and continue installation + * + * @param InstallerInterface $installer + * @return void + */ + public function exec(InstallerInterface $installer) + { + try { + $installer->install(); + $this->state->setInstalled(); + } catch (\Exception $e) { + $this->state->setError(); + $this->logger->error('Sample Data error: ' . $e->getMessage()); + } + } +} diff --git a/lib/internal/Magento/Framework/Setup/SampleData/FixtureManager.php b/lib/internal/Magento/Framework/Setup/SampleData/FixtureManager.php new file mode 100644 index 0000000000000..5746d4029961d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/SampleData/FixtureManager.php @@ -0,0 +1,80 @@ +componentRegistrar = $componentRegistrar; + $this->_string = $string; + } + + /** + * @param string $fileId + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getFixture($fileId) + { + list($moduleName, $filePath) = \Magento\Framework\View\Asset\Repository::extractModule( + $this->normalizePath($fileId) + ); + return $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName) . '/' . $filePath; + } + + /** + * Remove excessive "." and ".." parts from a path + * + * For example foo/bar/../file.ext -> foo/file.ext + * + * @param string $path + * @return string + */ + public static function normalizePath($path) + { + $parts = explode('/', $path); + $result = []; + + foreach ($parts as $part) { + if ('..' === $part) { + if (!count($result) || ($result[count($result) - 1] == '..')) { + $result[] = $part; + } else { + array_pop($result); + } + } elseif ('.' !== $part) { + $result[] = $part; + } + } + return implode('/', $result); + } +} diff --git a/lib/internal/Magento/Framework/Setup/SampleData/InstallerInterface.php b/lib/internal/Magento/Framework/Setup/SampleData/InstallerInterface.php new file mode 100644 index 0000000000000..bb12e9e5719c1 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/SampleData/InstallerInterface.php @@ -0,0 +1,19 @@ +filesystem = $filesystem; + } + + /** + * @inheritdoc + */ + public function hasError() + { + $isError = false; + $stream = $this->openStream('r'); + if (!$stream) { + return $isError; + } elseif (strpos(trim($stream->read(400)), self::ERROR) !== false) { + $isError = true; + } + $this->closeStream($stream); + return $isError; + } + + /** + * @inheritdoc + */ + public function setError() + { + if (!$this->hasError()) { + $this->writeStream(self::ERROR); + } + } + + /** + * @inheritdoc + */ + public function isInstalled() + { + $isInstalled = false; + /**@var $stream \Magento\Framework\Filesystem\File\WriteInterface */ + $stream = $this->openStream('r'); + if (!$stream) { + return $isInstalled; + } else { + $state = trim($stream->read(400)); + if (strpos($state, self::ERROR) !== false || strpos($state, self::INSTALLED) !== false) { + $isInstalled = true; + } + } + $this->closeStream($stream); + return $isInstalled; + } + + /** + * @inheritdoc + */ + public function setInstalled() + { + if (!$this->isInstalled()) { + $this->writeStream(self::INSTALLED); + } + } + + /** + * @inheritdoc + */ + public function clearState() + { + if ($this->openStream('w')) { + $this->writeStream(''); + } + } + + /** + * @return \Magento\Framework\Filesystem\File\WriteInterface + */ + protected function getStream() + { + if (!$stream = $this->openStream('w')) { + $stream = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR)->openFile($this->fileName); + } + return $stream; + } + + /** + * @param string $mode + * @return bool|\Magento\Framework\Filesystem\File\WriteInterface + */ + protected function openStream($mode = 'w') + { + $fileName = $this->fileName; + $stream = false; + $directoryWrite = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR); + if ($directoryWrite->isExist($fileName)) { + $stream = $directoryWrite->openFile($fileName, $mode); + } + return $stream; + + } + + /** + * @param string $data + * @throws \Exception + * @return void + */ + protected function writeStream($data) + { + $stream = $this->getStream(); + if ($stream === false) { + throw new \Exception( + 'Please, ensure that file ' . $this->fileName + . ' inside var directory exists and is writable' + ); + } + $stream->write($data); + $this->closeStream($stream); + } + + /** + * Closing file stream + * + * @param \Magento\Framework\Filesystem\File\WriteInterface $stream + * @return void + */ + protected function closeStream($stream) + { + if ($stream) { + $stream->close(); + } + } +} diff --git a/lib/internal/Magento/Framework/Setup/SampleData/StateInterface.php b/lib/internal/Magento/Framework/Setup/SampleData/StateInterface.php new file mode 100644 index 0000000000000..89f453025c31f --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/SampleData/StateInterface.php @@ -0,0 +1,53 @@ +filesystem = $this->getMockBuilder('Magento\Framework\Filesystem') + ->setMethods(['getDirectoryWrite']) + ->disableOriginalConstructor() + ->getMock(); + $this->writeInterface = $this->getMockForAbstractClass( + 'Magento\Framework\Filesystem\Directory\WriteInterface', + [], + '', + false, + true, + true, + ['write', 'close'] + ); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->state = $objectManager->getObject( + 'Magento\Framework\Setup\SampleData\State', + ['filesystem' => $this->filesystem] + ); + } + + public function testClearState() + { + $this->filesystem->expects($this->any())->method('getDirectoryWrite')->willReturn($this->writeInterface); + $this->writeInterface->expects($this->any())->method('openFile')->willReturnSelf(); + + $this->state->clearState(); + } + + /** + * @covers setError() + */ + public function testHasError() + { + $this->filesystem->expects($this->any())->method('getDirectoryWrite')->willReturn($this->writeInterface); + $this->writeInterface->expects($this->any())->method('openFile')->willReturnSelf(); + $this->writeInterface->expects($this->any())->method('write')->willReturnSelf(); + $this->writeInterface->expects($this->any())->method('close'); + $this->writeInterface->expects($this->any())->method('isExist')->willReturn(true); + $this->writeInterface->expects($this->any())->method('read') + ->willReturn(\Magento\Framework\Setup\SampleData\State::ERROR); + $this->state->setError(); + $this->assertTrue($this->state->hasError()); + } + + /** + * Clear state file + */ + protected function tearDown() + { + $this->filesystem->expects($this->any())->method('getDirectoryWrite')->willReturn($this->writeInterface); + $this->writeInterface->expects($this->any())->method('openFile')->willReturnSelf($this->absolutePath); + + $this->state->clearState(); + } +} diff --git a/setup/src/Magento/Setup/Controller/CustomizeYourStore.php b/setup/src/Magento/Setup/Controller/CustomizeYourStore.php index fe24ddcd5e586..cd85d5da81a57 100644 --- a/setup/src/Magento/Setup/Controller/CustomizeYourStore.php +++ b/setup/src/Magento/Setup/Controller/CustomizeYourStore.php @@ -50,10 +50,10 @@ public function indexAction() { $sampleDataDeployed = $this->moduleList->has('Magento_SampleData'); if ($sampleDataDeployed) { - /** @var \Magento\SampleData\Model\SampleData $sampleData */ - $sampleData = $this->objectManagerProvider->get()->get('Magento\SampleData\Model\SampleData'); - $isSampleDataInstalled = $sampleData->isInstalledSuccessfully(); - $isSampleDataErrorInstallation = $sampleData->isInstallationError(); + /** @var \Magento\Framework\Setup\SampleData\State $sampleData */ + $sampleData = $this->objectManagerProvider->get()->get('Magento\Framework\Setup\SampleData\State'); + $isSampleDataInstalled = $sampleData->isInstalled(); + $isSampleDataErrorInstallation = $sampleData->hasError(); } else { $isSampleDataInstalled = false; $isSampleDataErrorInstallation = false; @@ -63,7 +63,6 @@ public function indexAction() 'timezone' => $this->list->getTimezoneList(), 'currency' => $this->list->getCurrencyList(), 'language' => $this->list->getLocaleList(), - 'isSampledataEnabled' => $sampleDataDeployed, 'isSampleDataInstalled' => $isSampleDataInstalled, 'isSampleDataErrorInstallation' => $isSampleDataErrorInstallation ]); diff --git a/setup/src/Magento/Setup/Controller/Install.php b/setup/src/Magento/Setup/Controller/Install.php index 1677c45f8bbc3..fe6f1f363bb7d 100644 --- a/setup/src/Magento/Setup/Controller/Install.php +++ b/setup/src/Magento/Setup/Controller/Install.php @@ -19,6 +19,7 @@ use Zend\View\Model\JsonModel; use Zend\View\Model\ViewModel; use Magento\Setup\Console\Command\InstallCommand; +use Magento\SampleData; /** * Install controller @@ -42,21 +43,29 @@ class Install extends AbstractActionController */ private $progressFactory; + /** + * @var \Magento\Framework\Setup\SampleData\State + */ + protected $sampleDataState; + /** * Default Constructor * * @param WebLogger $logger * @param InstallerFactory $installerFactory * @param ProgressFactory $progressFactory + * @param \Magento\Framework\Setup\SampleData\State $sampleDataState */ public function __construct( WebLogger $logger, InstallerFactory $installerFactory, - ProgressFactory $progressFactory + ProgressFactory $progressFactory, + \Magento\Framework\Setup\SampleData\State $sampleDataState ) { $this->log = $logger; $this->installer = $installerFactory->create($logger); $this->progressFactory = $progressFactory; + $this->sampleDataState = $sampleDataState; } /** @@ -91,13 +100,13 @@ public function startAction() $this->installer->getInstallInfo()[SetupConfigOptionsList::KEY_ENCRYPTION_KEY] ); $json->setVariable('success', true); + if ($this->sampleDataState->hasError()) { + $json->setVariable('isSampleDataError', true); + } $json->setVariable('messages', $this->installer->getInstallInfo()[Installer::INFO_MESSAGE]); } catch (\Exception $e) { $this->log->logError($e); $json->setVariable('success', false); - if ($e instanceof \Magento\Setup\SampleDataException) { - $json->setVariable('isSampleDataError', true); - } } return $json; } @@ -117,11 +126,11 @@ public function progressAction() $percent = sprintf('%d', $progress->getRatio() * 100); $success = true; $contents = $this->log->get(); - } catch (\Exception $e) { - $contents = [(string)$e]; - if ($e instanceof \Magento\Setup\SampleDataException) { + if ($this->sampleDataState->hasError()) { $json->setVariable('isSampleDataError', true); } + } catch (\Exception $e) { + $contents = [(string)$e]; } return $json->setVariables(['progress' => $percent, 'success' => $success, 'console' => $contents]); } diff --git a/setup/src/Magento/Setup/Controller/Success.php b/setup/src/Magento/Setup/Controller/Success.php index 5bb2dd9f6e056..f10dbcd49290b 100644 --- a/setup/src/Magento/Setup/Controller/Success.php +++ b/setup/src/Magento/Setup/Controller/Success.php @@ -38,9 +38,9 @@ public function __construct(ModuleList $moduleList, ObjectManagerProvider $objec public function indexAction() { if ($this->moduleList->has('Magento_SampleData')) { - /** @var \Magento\SampleData\Model\SampleData $sampleData */ - $sampleData = $this->objectManagerProvider->get()->get('Magento\SampleData\Model\SampleData'); - $isSampleDataErrorInstallation = $sampleData->isInstallationError(); + /** @var \Magento\Framework\Setup\SampleData\State $sampleData */ + $sampleData = $this->objectManagerProvider->get()->get('Magento\Framework\Setup\SampleData\State'); + $isSampleDataErrorInstallation = $sampleData->hasError(); } else { $isSampleDataErrorInstallation = false; } diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php index 0afe71e591b6e..4a28e4ffcc3d1 100644 --- a/setup/src/Magento/Setup/Model/Installer.php +++ b/setup/src/Magento/Setup/Model/Installer.php @@ -37,6 +37,7 @@ use Magento\Setup\Console\Command\InstallCommand; use Magento\Setup\Validator\DbValidator; use \Magento\Backend\Setup\ConfigOptionsList as BackendConfigOptionsList; +use Magento\SampleData; /** * Class Installer contains the logic to install Magento application. @@ -205,6 +206,11 @@ class Installer */ private $dataSetupFactory; + /** + * @var \Magento\Framework\Setup\SampleData\State + */ + protected $sampleDataState; + /** * Component Registrar * @@ -233,6 +239,7 @@ class Installer * @param DbValidator $dbValidator * @param SetupFactory $setupFactory * @param DataSetupFactory $dataSetupFactory + * @param \Magento\Framework\Setup\SampleData\State $sampleDataState * @param ComponentRegistrar $componentRegistrar * * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -256,6 +263,7 @@ public function __construct( DbValidator $dbValidator, SetupFactory $setupFactory, DataSetupFactory $dataSetupFactory, + \Magento\Framework\Setup\SampleData\State $sampleDataState, ComponentRegistrar $componentRegistrar ) { $this->filePermissions = $filePermissions; @@ -277,6 +285,7 @@ public function __construct( $this->dbValidator = $dbValidator; $this->setupFactory = $setupFactory; $this->dataSetupFactory = $dataSetupFactory; + $this->sampleDataState = $sampleDataState; $this->componentRegistrar = $componentRegistrar; } @@ -297,6 +306,7 @@ public function install($request) } $script[] = ['Installing database schema:', 'installSchema', []]; $script[] = ['Installing user configuration...', 'installUserConfig', [$request]]; + $script[] = ['Enabling caches:', 'enableCaches', []]; $script[] = ['Installing data...', 'installDataFixtures', []]; if (!empty($request[InstallCommand::INPUT_KEY_SALES_ORDER_INCREMENT_PREFIX])) { $script[] = [ @@ -306,12 +316,7 @@ public function install($request) ]; } $script[] = ['Installing admin user...', 'installAdminUser', [$request]]; - $script[] = ['Enabling caches:', 'enableCaches', []]; - if (!empty($request[InstallCommand::INPUT_KEY_USE_SAMPLE_DATA]) - && $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, 'Magento_SampleData') !== null - ) { - $script[] = ['Installing sample data:', 'installSampleData', [$request]]; - } + $script[] = ['Caches clearing:', 'cleanCaches', []]; $script[] = ['Disabling Maintenance Mode:', 'setMaintenanceMode', [0]]; $script[] = ['Post installation file permissions check...', 'checkApplicationFilePermissions', []]; @@ -336,6 +341,9 @@ public function install($request) if ($this->progress->getCurrent() != $this->progress->getTotal()) { throw new \LogicException('Installation progress did not finish properly.'); } + if ($this->sampleDataState->hasError()) { + $this->log->log('Sample Data is installed with errors. See log file for details'); + } } /** @@ -929,7 +937,7 @@ public function updateModulesSequence() { $this->assertDeploymentConfigExists(); - $this->clearCache(); + $this->cleanCaches(); $this->log->log('File system cleanup:'); $messages = $this->cleanupFiles->clearCodeGeneratedClasses(); @@ -959,7 +967,7 @@ public function uninstall() $this->log->log('Starting Magento uninstallation:'); $this->cleanupDb(); - $this->clearCache(); + $this->cleanCaches(); $this->log->log('File system cleanup:'); $messages = $this->cleanupFiles->clearAllFiles(); @@ -972,18 +980,6 @@ public function uninstall() $this->log->logSuccess('Magento uninstallation complete.'); } - /** - * Clears cache - * - * @return void - */ - private function clearCache() - { - $cache = $this->objectManagerProvider->get()->create('Magento\Framework\App\Cache'); - $cache->clean(); - $this->log->log('Cache cleared successfully'); - } - /** * Enables caches after installing application * @@ -1003,6 +999,22 @@ private function enableCaches() $this->log->log(print_r($cacheManager->getStatus(), true)); } + /** + * Clean caches after installing application + * + * @return void + * + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) Called by install() via callback. + */ + private function cleanCaches() + { + /** @var \Magento\Framework\App\Cache\Manager $cacheManager */ + $cacheManager = $this->objectManagerProvider->get()->get('Magento\Framework\App\Cache\Manager'); + $types = $cacheManager->getAvailableTypes(); + $cacheManager->clean($types); + $this->log->log('Cache cleared successfully'); + } + /** * Enables or disables maintenance mode for Magento application * @@ -1130,30 +1142,6 @@ private function assertDbAccessible() } } - /** - * Run installation process for Sample Data - * - * @param array $request - * @return void - * @throws \Magento\Setup\SampleDataException - * - * @SuppressWarnings(PHPMD.UnusedPrivateMethod) Called by install() via callback. - */ - private function installSampleData($request) - { - try { - $userName = isset($request[AdminAccount::KEY_USER]) ? $request[AdminAccount::KEY_USER] : ''; - $this->objectManagerProvider->reset(); - $sampleData = $this->objectManagerProvider->get()->get('Magento\SampleData\Model\SampleData'); - $sampleData->install($this->objectManagerProvider->get(), $this->log, $userName); - } catch (\Exception $e) { - throw new \Magento\Setup\SampleDataException( - "Error during sample data installation: {$e->getMessage()}", - $e->getCode() - ); - } - } - /** * Get handler for schema or data install/upgrade/backup/uninstall etc. * diff --git a/setup/src/Magento/Setup/Model/InstallerFactory.php b/setup/src/Magento/Setup/Model/InstallerFactory.php index 0266a9c5261ef..297cbd02fd706 100644 --- a/setup/src/Magento/Setup/Model/InstallerFactory.php +++ b/setup/src/Magento/Setup/Model/InstallerFactory.php @@ -72,6 +72,7 @@ public function create(LoggerInterface $log) $this->serviceLocator->get('Magento\Setup\Validator\DbValidator'), $this->serviceLocator->get('Magento\Setup\Module\SetupFactory'), $this->serviceLocator->get('Magento\Setup\Module\DataSetupFactory'), + $this->serviceLocator->get('Magento\Framework\Setup\SampleData\State'), new \Magento\Framework\Component\ComponentRegistrar() ); } diff --git a/setup/src/Magento/Setup/SampleDataException.php b/setup/src/Magento/Setup/SampleDataException.php deleted file mode 100644 index 05337f2ab72a8..0000000000000 --- a/setup/src/Magento/Setup/SampleDataException.php +++ /dev/null @@ -1,11 +0,0 @@ -getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false); $this->objectManager = $this->getMock('Magento\Framework\App\ObjectManager', [], [], '', false); $objectManagerProvider->expects($this->any())->method('get')->willReturn($this->objectManager); - $this->sampleData = $this->getMock( - 'Magento\SampleData\Model\SampleData', - ['isInstalledSuccessfully', 'isInstallationError'], + $this->sampleDataState = $this->getMock( + 'Magento\Framework\Setup\SampleData\State', + [], [], '', false @@ -54,17 +54,18 @@ public function setup() /** * @param array $expected + * @param $withSampleData * * @dataProvider indexActionDataProvider */ - public function testIndexAction($expected) + public function testIndexAction($expected, $withSampleData) { - if ($expected['isSampledataEnabled']) { + if ($withSampleData) { $this->moduleList->expects($this->once())->method('has')->willReturn(true); - $this->objectManager->expects($this->once())->method('get')->willReturn($this->sampleData); - $this->sampleData->expects($this->once())->method('isInstalledSuccessfully') + $this->objectManager->expects($this->once())->method('get')->willReturn($this->sampleDataState); + $this->sampleDataState->expects($this->once())->method('isInstalled') ->willReturn($expected['isSampleDataInstalled']); - $this->sampleData->expects($this->once())->method('isInstallationError') + $this->sampleDataState->expects($this->once())->method('hasError') ->willReturn($expected['isSampleDataErrorInstallation']); } else { $this->moduleList->expects($this->once())->method('has')->willReturn(false); @@ -95,23 +96,19 @@ public function indexActionDataProvider() $currency = ['currency' => ['USD'=>'US Dollar', 'EUR' => 'Euro']]; $language = ['language' => ['en_US'=>'English (USA)', 'en_UK' => 'English (UK)']]; $sampleData = [ - 'isSampledataEnabled' => false, 'isSampleDataInstalled' => false, 'isSampleDataErrorInstallation' => false ]; - $sampleDataTrue = array_merge($sampleData, ['isSampledataEnabled' => true]); - $sampleDataFalse = array_merge($sampleData, ['isSampledataEnabled' => false]); return [ - 'with_all_data' => [array_merge($timezones, $currency, $language, $sampleDataTrue)], - 'no_currency_data' => [array_merge($timezones, ['currency' => null], $language, $sampleDataTrue)], - 'no_timezone_data' => [array_merge(['timezone' => null], $currency, $language, $sampleDataTrue)], - 'no_language_data' => [array_merge($timezones, $currency, ['language' => null], $sampleDataTrue)], - 'empty_currency_data' => [array_merge($timezones, ['currency' => []], $language, $sampleDataTrue)], - 'empty_timezone_data' => [array_merge(['timezone' => []], $currency, $language, $sampleDataTrue)], - 'empty_language_data' => [array_merge($timezones, $currency, ['language' => []], $sampleDataTrue)], - 'false_sample_data' => [array_merge($timezones, $currency, $language, $sampleDataFalse)], - 'no_sample_data' => [array_merge($timezones, $currency, $language, $sampleData)], + 'with_all_data' => [array_merge($timezones, $currency, $language, $sampleData), true], + 'no_currency_data' => [array_merge($timezones, ['currency' => null], $language, $sampleData), true], + 'no_timezone_data' => [array_merge(['timezone' => null], $currency, $language, $sampleData), true], + 'no_language_data' => [array_merge($timezones, $currency, ['language' => null], $sampleData), true], + 'empty_currency_data' => [array_merge($timezones, ['currency' => []], $language, $sampleData), true], + 'empty_timezone_data' => [array_merge(['timezone' => []], $currency, $language, $sampleData), true], + 'empty_language_data' => [array_merge($timezones, $currency, ['language' => []], $sampleData), true], + 'no_sample_data' => [array_merge($timezones, $currency, $language, $sampleData), false], ]; } diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/InstallTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/InstallTest.php index d5ff4a9f96128..53ea5f5bd2246 100644 --- a/setup/src/Magento/Setup/Test/Unit/Controller/InstallTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Controller/InstallTest.php @@ -30,15 +30,26 @@ class InstallTest extends \PHPUnit_Framework_TestCase */ private $controller; + /** + * @var \Magento\Framework\Setup\SampleData\State|\PHPUnit_Framework_MockObject_MockObject + */ + private $sampleDataState; + public function setUp() { $this->webLogger = $this->getMock('\Magento\Setup\Model\WebLogger', [], [], '', false); $installerFactory = $this->getMock('\Magento\Setup\Model\InstallerFactory', [], [], '', false); $this->installer = $this->getMock('\Magento\Setup\Model\Installer', [], [], '', false); $this->progressFactory = $this->getMock('\Magento\Setup\Model\Installer\ProgressFactory', [], [], '', false); + $this->sampleDataState = $this->getMock('\Magento\Framework\Setup\SampleData\State', [], [], '', false); $installerFactory->expects($this->once())->method('create')->with($this->webLogger) ->willReturn($this->installer); - $this->controller = new Install($this->webLogger, $installerFactory, $this->progressFactory); + $this->controller = new Install( + $this->webLogger, + $installerFactory, + $this->progressFactory, + $this->sampleDataState + ); } public function testIndexAction() @@ -66,31 +77,33 @@ public function testStartActionException() { $this->webLogger->expects($this->once())->method('clear'); $this->installer->expects($this->once())->method('install') - ->willThrowException($this->getMock('\Magento\Setup\SampleDataException')); + ->willThrowException($this->getMock('\Exception')); $jsonModel = $this->controller->startAction(); - $this->assertTrue($jsonModel->getVariable('isSampleDataError')); + $this->assertNull($jsonModel->getVariable('isSampleDataError')); } public function testStartActionWithSampleDataError() { $this->webLogger->expects($this->once())->method('clear'); - $this->webLogger->expects($this->once())->method('logError'); - $this->installer->method('install')->will($this->throwException(new \LogicException)); + $this->webLogger->expects($this->never())->method('logError'); + $this->installer->method('install'); + $this->sampleDataState->expects($this->once())->method('hasError')->willReturn(true); $jsonModel = $this->controller->startAction(); $this->assertInstanceOf('\Zend\View\Model\JsonModel', $jsonModel); $variables = $jsonModel->getVariables(); $this->assertArrayHasKey('success', $variables); - $this->assertFalse($variables['success']); + $this->assertTrue($variables['success']); + $this->assertTrue($jsonModel->getVariable('isSampleDataError')); } public function testProgressAction() { - $someNumber = 42; + $numValue = 42; $consoleMessages = ['key1' => 'log message 1', 'key2' => 'log message 2']; $progress = $this->getMock('\Magento\Setup\Model\Installer\Progress', [], [], '', false); $this->progressFactory->expects($this->once())->method('createFromLog')->with($this->webLogger) ->willReturn($progress); - $progress->expects($this->once())->method('getRatio')->willReturn($someNumber); + $progress->expects($this->once())->method('getRatio')->willReturn($numValue); $this->webLogger->expects($this->once())->method('get')->willReturn($consoleMessages); $jsonModel = $this->controller->progressAction(); $this->assertInstanceOf('\Zend\View\Model\JsonModel', $jsonModel); @@ -100,7 +113,7 @@ public function testProgressAction() $this->assertArrayHasKey('console', $variables); $this->assertSame($consoleMessages, $variables['console']); $this->assertTrue($variables['success']); - $this->assertSame(sprintf('%d', $someNumber * 100), $variables['progress']); + $this->assertSame(sprintf('%d', $numValue * 100), $variables['progress']); } public function testProgressActionWithError() @@ -120,15 +133,19 @@ public function testProgressActionWithError() public function testProgressActionWithSampleDataError() { - $this->progressFactory->expects($this->once())->method('createFromLog') - ->willThrowException($this->getMock('\Magento\Setup\SampleDataException')); + $numValue = 42; + $progress = $this->getMock('\Magento\Setup\Model\Installer\Progress', [], [], '', false); + $progress->expects($this->once())->method('getRatio')->willReturn($numValue); + $this->progressFactory->expects($this->once())->method('createFromLog')->willReturn($progress); + $this->sampleDataState->expects($this->once())->method('hasError')->willReturn(true); $jsonModel = $this->controller->progressAction(); $this->assertInstanceOf('\Zend\View\Model\JsonModel', $jsonModel); $variables = $jsonModel->getVariables(); $this->assertArrayHasKey('success', $variables); $this->assertArrayHasKey('console', $variables); - $this->assertFalse($variables['success']); + $this->assertTrue($variables['success']); $this->assertTrue($jsonModel->getVariable('isSampleDataError')); + $this->assertSame(sprintf('%d', $numValue * 100), $variables['progress']); } public function testDispatch() diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php index e55d4430ee7cf..6efff5d1ca88e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Controller/SuccessTest.php @@ -17,11 +17,11 @@ public function testIndexAction() $objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false); $objectManager = $this->getMock('Magento\Framework\App\ObjectManager', [], [], '', false); $objectManagerProvider->expects($this->once())->method('get')->willReturn($objectManager); - $sampleData = $this->getMock('Magento\Setup\Model\SampleData', ['isInstallationError'], [], '', false); - $objectManager->expects($this->once())->method('get')->willReturn($sampleData); + $sampleDataState = $this->getMock('Magento\Framework\Setup\SampleData\State', ['hasError'], [], '', false); + $objectManager->expects($this->once())->method('get')->willReturn($sampleDataState); /** @var $controller Success */ $controller = new Success($moduleList, $objectManagerProvider); - $sampleData->expects($this->once())->method('isInstallationError'); + $sampleDataState->expects($this->once())->method('hasError'); $viewModel = $controller->indexAction(); $this->assertInstanceOf('Zend\View\Model\ViewModel', $viewModel); $this->assertTrue($viewModel->terminate()); diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php index 30d4ba681439f..c87bda0dfab2e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php @@ -85,6 +85,10 @@ public function testCreate() 'Magento\Setup\Module\DataSetupFactory', $this->getMock('Magento\Setup\Module\DataSetupFactory', [], [], '', false), ], + [ + 'Magento\Framework\Setup\SampleData\State', + $this->getMock('Magento\Framework\Setup\SampleData\State', [], [], '', false), + ], ]; $serviceLocatorMock = $this->getMockForAbstractClass('Zend\ServiceManager\ServiceLocatorInterface', ['get']); $serviceLocatorMock diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php index 2b752d96dc285..42b8f5ee33541 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php @@ -121,6 +121,11 @@ class InstallerTest extends \PHPUnit_Framework_TestCase */ private $dataSetupFactory; + /** + * @var \Magento\Framework\Setup\SampleData\State|\PHPUnit_Framework_MockObject_MockObject + */ + private $sampleDataState; + /** * @var \Magento\Framework\Component\ComponentRegistrar|\PHPUnit_Framework_MockObject_MockObject */ @@ -172,6 +177,7 @@ protected function setUp() $this->dbValidator = $this->getMock('Magento\Setup\Validator\DbValidator', [], [], '', false); $this->setupFactory = $this->getMock('Magento\Setup\Module\SetupFactory', [], [], '', false); $this->dataSetupFactory = $this->getMock('Magento\Setup\Module\DataSetupFactory', [], [], '', false); + $this->sampleDataState = $this->getMock('Magento\Framework\Setup\SampleData\State', [], [], '', false); $this->componentRegistrar = $this->getMock('Magento\Framework\Component\ComponentRegistrar', [], [], '', false); $this->object = $this->createObject(); } @@ -213,6 +219,7 @@ private function createObject($connectionFactory = false, $objectManagerProvider $this->dbValidator, $this->setupFactory, $this->dataSetupFactory, + $this->sampleDataState, $this->componentRegistrar ); } @@ -242,8 +249,9 @@ public function testInstall() $resource->expects($this->any())->method('getConnection')->will($this->returnValue($connection)); $dataSetup = $this->getMock('Magento\Setup\Module\DataSetup', [], [], '', false); $cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false); - $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->any())->method('getAvailableTypes')->willReturn(['foo', 'bar']); $cacheManager->expects($this->once())->method('setEnabled')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->any())->method('clean'); $appState = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject( 'Magento\Framework\App\State' ); @@ -259,10 +267,12 @@ public function testInstall() ->method('get') ->will($this->returnValueMap([ ['Magento\Framework\App\State', $appState], + ['Magento\Framework\App\Cache\Manager', $cacheManager] ])); $this->adminFactory->expects($this->once())->method('create')->willReturn( $this->getMock('Magento\Setup\Model\AdminAccount', [], [], '', false) ); + $this->sampleDataState->expects($this->once())->method('hasError')->willReturn(true); $this->logger->expects($this->at(0))->method('log')->with('Starting Magento installation:'); $this->logger->expects($this->at(1))->method('log')->with('File permissions check...'); @@ -277,16 +287,18 @@ public function testInstall() $this->logger->expects($this->at(14))->method('log')->with("Module 'Foo_One':"); $this->logger->expects($this->at(16))->method('log')->with("Module 'Bar_Two':"); $this->logger->expects($this->at(19))->method('log')->with('Installing user configuration...'); - $this->logger->expects($this->at(21))->method('log')->with('Installing data...'); - $this->logger->expects($this->at(22))->method('log')->with('Data install/update:'); - $this->logger->expects($this->at(23))->method('log')->with("Module 'Foo_One':"); - $this->logger->expects($this->at(25))->method('log')->with("Module 'Bar_Two':"); - $this->logger->expects($this->at(28))->method('log')->with('Installing admin user...'); - $this->logger->expects($this->at(30))->method('log')->with('Enabling caches:'); - $this->logger->expects($this->at(31))->method('log')->with('Current status:'); - $this->logger->expects($this->at(34))->method('log')->with('Disabling Maintenance Mode:'); - $this->logger->expects($this->at(36))->method('log')->with('Post installation file permissions check...'); - $this->logger->expects($this->at(38))->method('logSuccess')->with('Magento installation complete.'); + $this->logger->expects($this->at(21))->method('log')->with('Enabling caches:'); + $this->logger->expects($this->at(25))->method('log')->with('Installing data...'); + $this->logger->expects($this->at(26))->method('log')->with('Data install/update:'); + $this->logger->expects($this->at(27))->method('log')->with("Module 'Foo_One':"); + $this->logger->expects($this->at(29))->method('log')->with("Module 'Bar_Two':"); + $this->logger->expects($this->at(32))->method('log')->with('Installing admin user...'); + $this->logger->expects($this->at(34))->method('log')->with('Caches clearing:'); + $this->logger->expects($this->at(37))->method('log')->with('Disabling Maintenance Mode:'); + $this->logger->expects($this->at(39))->method('log')->with('Post installation file permissions check...'); + $this->logger->expects($this->at(41))->method('logSuccess')->with('Magento installation complete.'); + $this->logger->expects($this->at(43))->method('log') + ->with('Sample Data is installed with errors. See log file for details'); $this->object->install($request); } @@ -339,14 +351,14 @@ public function testUpdateModulesSequence() ) ); - $cache = $this->getMock('Magento\Framework\App\Cache', [], [], '', false); - $cache->expects($this->once())->method('clean'); - $this->objectManager->expects($this->once()) - ->method('create') + $cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false); + $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->once())->method('clean'); + $this->objectManager->expects($this->any()) + ->method('get') ->will($this->returnValueMap([ - ['Magento\Framework\App\Cache', [], $cache], + ['Magento\Framework\App\Cache\Manager', $cacheManager] ])); - $this->moduleLoader->expects($this->once())->method('load')->willReturn($allModules); $expectedModules = [ @@ -400,13 +412,13 @@ public function testUninstall() ->expects($this->at(1)) ->method('log') ->with('No database connection defined - skipping database cleanup'); - $cache = $this->getMock('Magento\Framework\App\Cache', [], [], '', false); - $cache->expects($this->once())->method('clean'); - $this->objectManager->expects($this->once()) - ->method('create') - ->will($this->returnValueMap([ - ['Magento\Framework\App\Cache', [], $cache], - ])); + $cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false); + $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']); + $cacheManager->expects($this->once())->method('clean'); + $this->objectManager->expects($this->any()) + ->method('get') + ->with('Magento\Framework\App\Cache\Manager') + ->willReturn($cacheManager); $this->logger->expects($this->at(2))->method('log')->with('Cache cleared successfully'); $this->logger->expects($this->at(3))->method('log')->with('File system cleanup:'); $this->logger diff --git a/setup/view/magento/setup/customize-your-store.phtml b/setup/view/magento/setup/customize-your-store.phtml index e392296753f3f..c5d7f17049558 100644 --- a/setup/view/magento/setup/customize-your-store.phtml +++ b/setup/view/magento/setup/customize-your-store.phtml @@ -25,48 +25,34 @@ Customize Your Store + isSampleDataInstalled || $this->isSampleDataErrorInstallation): ?>
-

- Select “Use Sample Data" to create a sample store with sample products, customers, and payment settings. Our Guide to Using Sample Data can help you get started. -

- isSampledataEnabled ? '' : 'disabled' ?> - > - - - isSampleDataInstalled || $this->isSampleDataErrorInstallation): ?> -
-

- isSampleDataInstalled): ?> - You have already installed sample data. If you want to re-install it, your database has to be cleaned up - - isSampleDataErrorInstallation): ?> - Your sample data is broken. If you want to re-install it, your database has to be cleaned up - -

- - -
- +
+

+ isSampleDataInstalled): ?> + You have already installed sample data. If you want to re-install it, your database has to be cleaned up + + isSampleDataErrorInstallation): ?> + Your sample data is broken. If you want to re-install it, your database has to be cleaned up + +

+ + +
+