Problem in creating Drop down product attribute in Magento2
-
13-04-2021 - |
Question
I have created a Data patch file to create the product drop down attribute with options. used the following code in it.
<?php
declare(strict_types=1);
namespace Custom\Module\Setup\Patch\Data;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
class AddTestAttribute implements DataPatchInterface
{
private $moduleDataSetup;
private $eavSetupFactory;
public $_storeManager;
private $logger;
protected $_dir;
const TYPE_BOOLEAN = "boolean";
const TYPE_TEXT = "text";
const TYPE_SELECT = "select";
protected $_attributeFactory;
protected $_eavAttribute;
public function __construct(
ModuleDataSetupInterface $moduleDataSetup,
EavSetupFactory $eavSetupFactory,
\Psr\Log\LoggerInterface $logger,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\Filesystem\DirectoryList $dir,
\Magento\Catalog\Model\ResourceModel\Eav\Attribute $attributeFactory,
\Magento\Eav\Model\Entity\Attribute $eavAttribute
) {
$this->moduleDataSetup = $moduleDataSetup;
$this->eavSetupFactory = $eavSetupFactory;
$this->_storeManager = $storeManager;
$this->logger = $logger;
$this->_dir = $dir;
$this->_attributeFactory = $attributeFactory;
$this->_eavAttribute = $eavAttribute;
}
/**
* {@inheritdoc}
*/
public function apply()
{
/** @var EavSetup $eavSetup */
$eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);
$fileName = 'attributes_data.csv';
$pubPath = $this->_dir->getPath('pub');
$attributeFile = $pubPath.'/'.$fileName;
$arrResult = array();
if(($handle = fopen($attributeFile, 'r')) !== FALSE) {
$row = 1;
while(($data = fgetcsv($handle, 1000000, ',')) !== FALSE) {
$col_count = count($data);
$arrResult[] = $data;
$row++;
}
fclose($handle);
}
$i = 0;
foreach ($arrResult as $line) {
if($i > 0){
$attributeCode = $line[0];
$attributeName = $line[1];
$inputType = strtolower($line[2]);
$options = $line[3];
switch ($inputType) {
case ($inputType == self::TYPE_BOOLEAN && isset($attributeCode)):
$this->createBooleanAttribute($eavSetup,$attributeCode,$attributeName,$inputType);
break;
case ($inputType == self::TYPE_SELECT && isset($attributeCode)):
$this->createSelectAttribute($eavSetup,$attributeCode,$attributeName,$inputType);
if(isset($options) && $options != '' ){
$optionName = explode (",", $options);
if(count($optionName) > 0){
$this->createAttributeOptions($eavSetup,$attributeCode,$optionName);
}
}
case ($inputType == self::TYPE_TEXT && isset($attributeCode)):
$this->createTextAttribute($eavSetup,$attributeCode,$attributeName,$inputType);
break;
default:
$this->createTextAttribute($eavSetup,$attributeCode,$attributeName,$inputType);
}
}
$i++;
}
}
/**
* {@inheritdoc}
*/
public static function getDependencies()
{
return [];
}
/**
* {@inheritdoc}
*/
public function getAliases()
{
return [];
}
public function createSelectAttribute($eavSetup,$attributeCode,$attributeName,$inputType){ //,$options
$this->logger->info('-select Attribute---');
$type = 'int';
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
$attributeCode,
[
'type' => $type,
'group' => 'General',
'backend' => 'int',
'frontend' => '',
'label' => $attributeName,
'input' => $inputType,
'class' => '',
'source' => 'Magento\Eav\Model\Entity\Attribute\Source\Table',
'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
'visible' => true,
'required' => false,
'user_defined' => true,
'searchable' => false,
'filterable' => true,
"filterable_in_search" => 1,
'comparable' => false,
'visible_on_front' => true,
'used_in_product_listing' => true,
'unique' => false ,
'system' => 1
]
);
}
public function createTextAttribute($eavSetup,$attributeCode,$attributeName,$inputType){
$type = 'text';
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
$attributeCode,
[
'type' => $type,
'group' => 'Product Details',
'attribute_set' => 'Default',
'label' => $attributeName,
'backend' => '',
'input' => $inputType,
'wysiwyg_enabled' => false,
'source' => '',
'required' => false,
'sort_order' => 3,
'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
'used_in_product_listing' => true,
'visible_on_front' => true
]
);
}
public function createAttributeOptions($eavSetup,$attributeCode,$optionName){
$entityType = 'catalog_product';
$attributeInfo = $this->_eavAttribute->loadByCode($entityType, $attributeCode);
$attributeId = $attributeInfo->getAttributeId();
//$attribute_arr = ['aaa','bbb','ccc','ddd'];
$attribute_arr = $optionName;
$option = array();
$option['attribute_id'] = $attributeId;
foreach($attribute_arr as $key => $value){
$option['value'][$value][0]=$value;
foreach($this->_storeManager as $store){
$option['value'][$value][$store->getId()] = $value;
}
}
if ($option) {
$eavSetup->addAttributeOption($option);
}
}
}
In the above script, I have created a csv file inside pub directory, then reading data from the file and creating the attributes based on the file data.
File content will be like this.
In database its created like below.
The problem here is the "drop down" attribute is created well, but the "source_model" is created empty in database also the backend_type created as "text" instead of "int".
Due to this we are unable to see the drop down attribute in layered navigation. Can anyone advise me here please how can i create the drop down attribute with option by reading from the csv file. Thanks!!
No correct solution
OTHER TIPS
Try like this
$eavSetup->addAttribute(
'catalog_product',
'attribute_code',
[
'group' => 'General',
'type' => 'int',
'label' => 'My Attribute',
'input' => 'select',
'required' => false,
'visible' => true,
'default' => '',
'user_defined' => true,
'searchable' => true,
'filterable' => true,
'comparable' => false,
'visible_on_front' => true,
'used_in_product_listing' => true,
'unique' => false,
'option' => ['values' => ['Option 1', 'Option 2', 'Option 3']]
]
);
Try to replace with this below code :
$eavSetup->addAttribute(
\Magento\Catalog\Model\Product::ENTITY,
$attributeCode,
[
'group' => 'general',
'type' => 'int',
'backend' => '',
'frontend' => '',
'label' => 'My Custom Attribute',
'input' => 'select',
'note' => 'My Custom Attribute',
'class' => '',
'source' => \MyModule\MyDropdownAttribute\Model\Config\Source\Options::class,
'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
'visible' => true,
'required' => false,
'user_defined' => true,
'default' => '0',
'searchable' => false,
'filterable' => false,
'comparable' => false,
'visible_on_front' => true,
'used_in_product_listing' => true,
'unique' => false,
'option' => [
'values' => [],
]
]
);
Option File :
app/code/MyModule/MyDropdownAttribute/Model/Config/Source/Options.php
<?php
namespace MyModule\MyDropdownAttribute\Model\Config\Source;
use Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory;
use Magento\Framework\DB\Ddl\Table;
class Options extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
{
/**
* Get all options
*
* @return array
*/
public function getAllOptions()
{
$this->_options = [
['label'=>'', 'value'=>''],
['label'=>'Small', 'value'=>'1'],
['label'=>'Medium', 'value'=>'2'],
['label'=>'Large', 'value'=>'3']
];
return $this->_options;
}
/**
* Get a text for option value
*
* @param string|integer $value
* @return string|bool
*/
public function getOptionText($value)
{
foreach ($this->getAllOptions() as $option) {
if ($option['value'] == $value) {
return $option['label'];
}
}
return false;
}
}
You need to set your dropdown options files in source attribute. Please replace with this code and check it.
Use Below code it will create attribute and import options using csv file
<?php
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
if (version_compare($context->getVersion(), '1.0.10') < 0) {
$entityTypeId = $this->eavSetup->getEntityTypeId(Product::ENTITY);
$options = $this->getCountryOptionsFromCsv('manufacturer-countries-list.csv');
$this->addNewAttributeWithOptions($entityTypeId, 'custom_attributes_5.csv', $options);
}
$setup->endSetup();
}
private function addNewAttributeWithOptions($entityTypeId, $fileName, $options)
{
$ffcCatalogFixture = 'NameSpace_Catalog::fixtures/'.$fileName;
$importFile = $this->fixtureManager->getFixture($ffcCatalogFixture);
if (!$this->filesystem->isExists($importFile)) {
return;
}
$columns = $this->csv->getData($importFile);
foreach ($columns as $column) {
//$this->eavSetup->removeAttribute($entityTypeId, $column[self::ATTRIBUTE_CODE]);
$attributeObj = $this->eavconfig->getAttribute(self::ENTITY_TYPE, self::ATTRIBUTE_CODE);
$attributeId = $attributeObj->getAttributeId();
if (!$attributeId) {
if ($column[self::USE_IN_FILTER] == "Yes") {
$useInfilter = "true";
} else {
$useInfilter = "false";
}
$usedInProductListing = ($column[self::USED_IN_PRODUCT_LISTING] == "Yes") ? true : false;
$this->eavSetup->addAttribute(
Product::ENTITY,
$column[self::ATTRIBUTE_CODE],
[
'global' => ScopedAttributeInterface::SCOPE_STORE,
'attribute_code' => $column[self::ATTRIBUTE_CODE],
'label' => $column[self::ATTRIBUTE_LABEL],
'attribute_model' => '',
'backend' => $column[self::ATTRIBUTE_BACKEND],
'source' => $column[self::ATTRIBUTE_SOURCE],
'frontend' => '',
'frontend_class' => $column[self::FRONTEND_CLASS],
'type' => $column[self::ATTRIBUTE_TYPE],
'input' => $column[self::ATTRIBUTE_INPUT],
'visible' => true,
'required' => false,
'user_defined' => true,
'searchable' => false,
'filterable' => $useInfilter,
'comparable' => false,
'visible_on_front' => false,
'used_in_product_listing' => $usedInProductListing,
'unique' => false,
'option' => [
'values' => $options,
],
]
);
// Save the attributes in attribute sets and groups.
$attributeSets = explode(',', $column[self::ATTRIBUTE_SET]);
foreach ($attributeSets as $attributeSet) {
$this->eavSetup->addAttributeToSet(
$entityTypeId,
$attributeSet,
$column[self::ATTRIBUTE_GROUP],
$column[self::ATTRIBUTE_CODE]
);
}
}
}
}