Magento2: Custom customer attribute not saves

Created on 19 Jun 2015  路  25Comments  路  Source: magento/magento2

Hi,
I have made custom text attribute for customer (admin customer edit form) using installation script.
The attribute shows fine, but its not possible to save any value - seems that value not insets into customer_entity_varchar table.

Format is not valid Ready for Work needs update bug report

Most helpful comment

@sashas777, we've investigated internal ticket and here is response:

Attribute is not possible to save any value, because the attribute data not stored in 'eav_entity_attribute' table.

To avoid this you must specify additional parameters for the attribute.

  • attribute_set_id
  • attribute_group_id

The 'system' parameter must be specified as 0 (the new attribute is not really system attribute).

The working code here (update VERSION to real module version value):

namespace Magento\Customer\Setup;

use Magento\Customer\Model\Customer;
use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

class UpgradeData implements UpgradeDataInterface
{
    /**
     * @var CustomerSetupFactory
     */
    protected $customerSetupFactory;

    /**
     * @var AttributeSetFactory
     */
    private $attributeSetFactory;

    /**
     * @param CustomerSetupFactory $customerSetupFactory
     * @param AttributeSetFactory $attributeSetFactory
     */
    public function __construct(
        CustomerSetupFactory $customerSetupFactory,
        AttributeSetFactory $attributeSetFactory
    ) {
        $this->customerSetupFactory = $customerSetupFactory;
        $this->attributeSetFactory = $attributeSetFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        if (version_compare($context->getVersion(), 'VERSION') < 0) {
            /** @var CustomerSetup $customerSetup */
            $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);

            $customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
            $attributeSetId = $customerEntity->getDefaultAttributeSetId();

            /** @var $attributeSet AttributeSet */
            $attributeSet = $this->attributeSetFactory->create();
            $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);

            $customerSetup->addAttribute(Customer::ENTITY, 'customer_code', [
                'type' => 'varchar',
                'label' => 'Customer Code',
                'input' => 'text',
                'required' => false,
                'visible' => true,
                'user_defined' => true,
                'sort_order' => 90,
                'position' => 90,
                'system' => 0,
            ]);

            $attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'customer_code')
                ->addData([
                    'attribute_set_id' => $attributeSetId,
                    'attribute_group_id' => $attributeGroupId,
                    'used_in_forms' => ['adminhtml_customer'],
                ]);

            $attribute->save();
        }
    }
}

All 25 comments

Have you assigned it to the form? In #1238 there is a module setup example I've used to create a working custom customer attribute.

@sashas777, did you look at example from https://github.com/magento/magento2/issues/1238#issuecomment-105034397? Did you define 'used_in_forms' for this attribute?

@vpelipenko @Vinai
Hi,

Yes it is set 'used_in_forms' and it visible at the admin customer edit form. But when i enter information in the field it doesnt save it and put into customer_entity_varchar table. If i manually add record into table the values shows at the admin customer edit page.
Here is setup function from InstallData.php file:


    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        /** @var CustomerSetup $customerSetup */
        $customerSetup = $this->ExtensionSetupFactory->create(['setup' => $setup]);
        $attributeParams=array(
            'type' => 'varchar',
            'label' => 'Customer Code',
            'input' => 'text',
            'required' => false,
            'visible' => true,
            'user_defined' => true,
            'sort_order' => 90,     
            'position' => 90,
        );
        $customerSetup->addAttribute('customer', 'customer_code', $attributeParams);
        $customerCodeAttribute = $customerSetup->getEavConfig()->getAttribute('customer', 'customer_code');
        $customerCodeAttribute->setData(
            'used_in_forms',
            ['adminhtml_customer']
        );
        $customerCodeAttribute->save();

    }

Thanks

Internal ticket: MAGETWO-39121

@sashas777, we've investigated internal ticket and here is response:

Attribute is not possible to save any value, because the attribute data not stored in 'eav_entity_attribute' table.

To avoid this you must specify additional parameters for the attribute.

  • attribute_set_id
  • attribute_group_id

The 'system' parameter must be specified as 0 (the new attribute is not really system attribute).

The working code here (update VERSION to real module version value):

namespace Magento\Customer\Setup;

use Magento\Customer\Model\Customer;
use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

class UpgradeData implements UpgradeDataInterface
{
    /**
     * @var CustomerSetupFactory
     */
    protected $customerSetupFactory;

    /**
     * @var AttributeSetFactory
     */
    private $attributeSetFactory;

    /**
     * @param CustomerSetupFactory $customerSetupFactory
     * @param AttributeSetFactory $attributeSetFactory
     */
    public function __construct(
        CustomerSetupFactory $customerSetupFactory,
        AttributeSetFactory $attributeSetFactory
    ) {
        $this->customerSetupFactory = $customerSetupFactory;
        $this->attributeSetFactory = $attributeSetFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        if (version_compare($context->getVersion(), 'VERSION') < 0) {
            /** @var CustomerSetup $customerSetup */
            $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);

            $customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
            $attributeSetId = $customerEntity->getDefaultAttributeSetId();

            /** @var $attributeSet AttributeSet */
            $attributeSet = $this->attributeSetFactory->create();
            $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);

            $customerSetup->addAttribute(Customer::ENTITY, 'customer_code', [
                'type' => 'varchar',
                'label' => 'Customer Code',
                'input' => 'text',
                'required' => false,
                'visible' => true,
                'user_defined' => true,
                'sort_order' => 90,
                'position' => 90,
                'system' => 0,
            ]);

            $attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'customer_code')
                ->addData([
                    'attribute_set_id' => $attributeSetId,
                    'attribute_group_id' => $attributeGroupId,
                    'used_in_forms' => ['adminhtml_customer'],
                ]);

            $attribute->save();
        }
    }
}

Thanks. It works

I added this attribute in customer registration form. please let me know how to save this attribute form frontend.

I created attribute like this
webiste_url
I am trying to save this in
$customer->setWebsiteUrl(webiste_url);

also i tried to save it form front-end but notworking

I tried to save from backend but not working.
custom attribute created and display in customer form properly 
<?php

namespace CustomModule\CustomCustomerModule\Setup;

use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Customer\Model\Customer;
use Magento\Eav\Model\Entity\Attribute\Set as AttributeSet;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;


/**
 * @codeCoverageIgnore
 */
class InstallData implements InstallDataInterface
{
    /**
     * @var CustomerSetupFactory
     */
    protected $customerSetupFactory;

    /**
     * @var AttributeSetFactory
     */
    private $attributeSetFactory;

    /**
     * @param CustomerSetupFactory $customerSetupFactory
     * @param AttributeSetFactory $attributeSetFactory
     */
    public function __construct(
        CustomerSetupFactory $customerSetupFactory,
        AttributeSetFactory $attributeSetFactory
    ) {
        $this->customerSetupFactory = $customerSetupFactory;
        $this->attributeSetFactory = $attributeSetFactory;
    }

    /**
     * {@inheritdoc}
     *
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(
        ModuleDataSetupInterface $setup, 
        ModuleContextInterface $context
    ) {
        /** @var CustomerSetup $customerSetup */
        $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);

        $customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
        $attributeSetId = $customerEntity->getDefaultAttributeSetId();

        /** @var $attributeSet AttributeSet */
        $attributeSet = $this->attributeSetFactory->create();
        $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);

        /** @var CustomerSetup $customerSetup */
        $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);

        $setup->startSetup();

        $attributesInfo = [
            'custom_ship_time_min' => [
                'type' => 'varchar',
                'label' => 'Shipping Time Min',
                'input' => 'text',
                'class' => '',
                'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
                'visible' => true,
                'required' => false,
                'user_defined' => true,
                'filterable' => false,
                'comparable' => false,
                'unique' => false,
                'position' => 119
            ],
            'custom_ship_free' => [
                'type' => 'int',
                'label' => 'Shipping Free',
                'input' => 'boolean',
                'class' => '',
                'backend' => 'Magento\Customer\Model\Attribute\Backend\Data\Boolean',
                'global' => ScopedAttributeInterface::SCOPE_GLOBAL,
                'visible' => true,
                'required' => false,
                'user_defined' => true,
                'filterable' => false,
                'comparable' => false,
                'unique' => false,
                'position' => 121
            ]
        ];

        foreach ($attributesInfo as $attributeCode => $attributeParams) {
            $customerSetup->addAttribute(Customer::ENTITY, $attributeCode, $attributeParams);
            $attribute = $customerSetup->getEavConfig()
                                        ->getAttribute(Customer::ENTITY, $attributeCode)
                                        ->addData(
                                            [
                                                'attribute_set_id' => $attributeSetId,
                                                'attribute_group_id' => $attributeGroupId,
                                                'used_in_forms'=> ['adminhtml_customer']
                                            ]
                                        );
            $attribute->save();
        }
        $setup->endSetup();
    }
}


this worked with me

I tried to save it from backend but not working,
Magento only save the files of table customer_entity

@sashas777 In my form I see the new attributes of customer, but is impossible save the information of this attributes.

I checked the controller save the module customer in the line 215 the controller save the customer information with helper MagentoFrameworkReflectionMethodsMapDataObjectHelper in the line 98 the function _satDataValue the condition "$data Object instanceof CustomAttributesDataInterface" never is true I think that's reason of my problem.

`

protected function _setDataValues($dataObject, array $data, $interfaceName)
{
    $dataObjectMethods = get_class_methods(get_class($dataObject));
    foreach ($data as $key => $value) {
        /* First, verify is there any setter for the key on the Service Data Object */
        $camelCaseKey = \Magento\Framework\Api\SimpleDataObjectConverter::snakeCaseToUpperCamelCase($key);
        $possibleMethods = [
            'set' . $camelCaseKey,
            'setIs' . $camelCaseKey,
        ];
        if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES
            && ($dataObject instanceof ExtensibleDataInterface)
            && is_array($data[$key])
            && !empty($data[$key])
        ) {
            foreach ($data[$key] as $customAttribute) {
                $dataObject->setCustomAttribute(
                    $customAttribute[AttributeInterface::ATTRIBUTE_CODE],
                    $customAttribute[AttributeInterface::VALUE]
                );
            }
        } elseif ($methodNames = array_intersect($possibleMethods, $dataObjectMethods)) {
            $methodName = array_values($methodNames)[0];
            if (!is_array($value)) {
                if ($methodName === 'setExtensionAttributes' && $value === null) {
                    // Cannot pass a null value to a method with a typed parameter
                } else {
                    $dataObject->$methodName($value);
                }
            } else {
                $getterMethodName = 'get' . $camelCaseKey;
                $this->setComplexValue($dataObject, $getterMethodName, $methodName, $value, $interfaceName);
            }
        } elseif ($dataObject instanceof CustomAttributesDataInterface) {
            $dataObject->setCustomAttribute($key, $value);
        }
    }


    return $this;
}`

The files

vendor/magento/framework/Api/DataObjectHelper.php:98
vendor/magento/module-customer/Controller/Adminhtml/Index/Save.php:215

Maybe is necessary modified the class

@sashas777 In some point the controller saves the information of my customer attributes or write the data in the customer model, but never the save in my database I did check the table customer_entity_varchar all time is empty.
In the class AbstractExtensibleObject of file vendor/magento/framework/Api/AbstractExtensibleObject.php list all attributes included my custom attributes in the method setCustomAttribute.

@carloshernan007
You were correct. Thanks I did update to the article and checked - it works.

Thanks

Ok, thanks for your help

I followed the tutorial http://www.extensions.sashas.org/blog/magento-2-1-3-how-to-make-customer-attribute-update.html added the attributes that I needed, they are shown in the form, but when I save the changes they are not persited to the database.
When I register the information directly in the database, it is shown in the form, but when I save the changes, my custom information gets deleted.

@danielruedaa It should work. Have you tried to flush cache and switch to developer mode? Maybe you have the issue because of cache. The current code in the article works.

thanks for your help

For all of those that came here still searching for an answer:

When creating the customer attribute, please take care about following things:

  • Attribute is added to the attribute set, group
  • Attribute is assigned to customer forms
  • And the last one the most important as somehow, people just skip over it and wondering why the customer attribute does not want to save from the backend: Please make sure to set "is_system" flag in "customer_eav_attribute" table to 0, otherwise the attribute will not be saved.

It can be done by setting the attribute option to "system" => 0 in attribute parameters inside the install/upgrade script.

More about that particular issue can be found here.

@darkogoles1,
Tried as your comment, That didn't solve my issue, here is my stack link https://magento.stackexchange.com/questions/260079/multiselect-attribute-not-saving-in-magento-2-3-0

Customer Registration Custom attribute value create in admin and save

1. Text Field

2. Drop Down Field

3. Date Field

Using UpgradeSchema.php

<?php

namespace {CompanyName}\{ModuleName}\Setup;

use Magento\Customer\Model\Customer;
use Magento\Customer\Setup\CustomerSetup;
/* irrelevant */
#use Magento\Framework\Setup\UpgradeSchemaInterface;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
/* irrelevant */
#use Magento\Framework\Setup\SchemaSetupInterface;
/* add this */
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

class UpgradeData implements  UpgradeDataInterface
{
    private $customerSetupFactory;

    public function __construct(\Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory)
    {
        $this->customerSetupFactory = $customerSetupFactory;
    }
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        if (version_compare($context->getVersion(), '1.0.1', '<')) 
        {
            // For Text field
            $customerSetup->addAttribute(
                    \Magento\Customer\Model\Customer::ENTITY,
                    'attribute_title',                    
                    [
                        'type' => 'text',
                        'input' => 'text',
                        'label' => 'Attribute Title',
                        'required' => false,
                        'visible' => true,
                        'user_defined' => false,
                        'sort_order' => 1000,
                        'position' => 1000,
                        'system' => 0,
                    ]
                );
            $attribute_title = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'attribute_title')
                ->addData(
                    ['used_in_forms' => ['adminhtml_customer']
                ]);

            $attribute_title->save();

            //Add field Drop Down for Yes/No
            $customerSetup->addAttribute(
                    \Magento\Customer\Model\Customer::ENTITY,
                    'is_attribute',                    
                    [
                        'type' => 'int',
                        'input' => 'select',
                        'label' => 'Is Attribute',
                        'frontend' => '',
                        'default' => '1',
                        'class' => '',
                        'source' => 'Magento\Eav\Model\Entity\Attribute\Source\Boolean',
                        'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend',
                        'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
                        'required' => false,
                        'visible' => true,
                        'user_defined' => false,
                        'sort_order' => 1000,
                        'position' => 1000,
                        'system' => 0,
                    ]
                );
            $is_attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'is_attribute')
                ->addData(
                    ['used_in_forms' => ['adminhtml_customer']
                ]);

            $is_attribute->save();

            // For Date And Time field
            $customerSetup->addAttribute(
                \Magento\Customer\Model\Customer::ENTITY,
                'custom_date',                    
                [
                    'label' => 'Custom Date',
                    'type' => 'datetime',
                    'input' => 'date',
                    'frontend' => 'Magento\Eav\Model\Entity\Attribute\Frontend\Datetime',
                    'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\Datetime',
                    'validate_rules' => '{"input_validation":"date"}',
                    'user_defined' => false,
                    'required' => false,
                    'visible' => true,
                    'searchable' => false,
                    'filterable' => false,
                    'comparable' => false,
                    'visible_on_front' => false,
                    'sort_order' => 1000,
                    'position' => 1000,
                    'system' => 0,
                ]
            );
            $custom_date = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, 'custom_date')
                ->addData(
                    ['used_in_forms' => ['adminhtml_customer']
                ]);
                // more used_in_forms ['adminhtml_checkout','adminhtml_customer','adminhtml_customer_address','customer_account_edit','customer_address_edit','customer_register_address']
            $commenced_business->save();
        }
    }
}

Basically I have been trying to add custom attribute in customer admin using upgrade data and customer setup. But here I can see in my db that my new custom attribute have been added successfully in eav_attribute,customer_eav_attribute,eav_entity_attribute,customer_grid_flat,customer_form_attribute also I am able to see that attribute in customer/admin/edit form in account information tab where I wanted to add. Also it is showing up in customer_grid filter with dropdown values also in customer_grid_table as new column. I am not getting any errors or warnings. Also my upgrade script is working properly its just not updating my custom attribute in eav_attribute_option and eav_attribute_option_value while rest of everything is working fine. I did cache clean, flush, upgrade and compile. I would really like to understand this concept and solve this issue any kind of suggestion would be great for me to continue learning. reindexing the whole magento 2 didn't work either. may I please get any guidance on this issue thanks

public function createSelectAttributeDataNewSignupReview($label = 'replace this value', $sortOrder = 1)
    {
        return [
            'type' => 'int',
            'store_label' => $label,
            'frontend_label' => $label,
            'input' => 'select',
            'sort_order' => $sortOrder,
            'required' => false,
            'user_defined' => true,
            'default' => null,
            'system' => false,
            'backend_type' => 'int',
            'attribute_model' => 'Magento\Customer\Model\Attribute',
            'visible' => true,
            'visible_on_front' => true,
            'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL
        ];
    }

public function getCustomAttributesData()
    {
        $sortOrder = 1;
$newsignupreview = $this->createSelectAttributeDataNewSignupReview('New Signup Review', $sortOrder++);
        $newsignupreview['source'] = \Vendor\Customer\Model\Customer\Attribute\Source\NewSignupReview::class;
        $newsignupreview['is_used_in_grid'] = true;
        $newsignupreview['is_visible_in_grid'] = true;
        $newsignupreview['is_filterable_in_grid'] = true;
        $newsignupreview['is_searchable_in_grid'] = true;

        return [
 CustomerInterface::NEW_SIGNUP_REVIEW => $newsignupreview
        ];
}

public function addCustomAttributes()
    {
        $customAttributesData = $this->getCustomAttributesData();

        $defaultUsedInForms = [
            'adminhtml_customer',
            'adminhtml_checkout',
            'customer_account_create',
            'customer_account_edit',
            'checkout_register'
        ];

        foreach ($customAttributesData as $attributeCode => $customAttributesDatum) {
            $attributeId = $this->getAttributeId(Customer::ENTITY, $attributeCode);

            if (empty($attributeId)) {
                $this->addAttribute(Customer::ENTITY, $attributeCode, $customAttributesDatum);
            }

            $this->updateAttribute(Customer::ENTITY, $attributeCode, $customAttributesDatum);

            $this->addAttributeToSet(
                CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER,
                CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER,
                null,
                $attributeCode);

            $attribute = $this->eavConfig->getAttribute(Customer::ENTITY, $attributeCode);

            $usedInForms = null;
            if ($attributeCode == CustomerInterface::REQUESTED_PASSWORD_RESET) {
                $usedInForms = [
                    'adminhtml_customer'
                ];
            }

            $attribute->setData('used_in_forms', $usedInForms ? $usedInForms : $defaultUsedInForms);
            $this->attributeResource->save($attribute);
        }
    }
\app\code\Company\Customer\Model\Customer\Attribute\Source\NewSignupReview.php
<?php
namespace Company\Customer\Model\Customer\Attribute\Source;


use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource;
use Company\Customer\Model\NewSignupReviewProvider;


class NewSignupReview extends AbstractSource
{
    protected $newsignupreviewProvider;

    protected $newsignupreviews;

    public function __construct(NewSignupReviewProvider $newsignupreviewProvider)
    {
        $this->newsignupreviewProvider = $newsignupreviewProvider;
        $this->newsignupreviews = $newsignupreviewProvider->getList();
    }

    public function getAllOptions()
    {
        if (!empty($this->_options)) {
            return $this->_options;
        }

        $this->_options = [];
        foreach ($this->newsignupreviews as $id => $label) {
            $this->_options[] = [
                'label' => __($label),
                'value' => $id
            ];
        }
        return $this->_options;
    }
}



md5-3112e366f6a16c5282b791c47dfd046d



\app\code\Company\Customer\Model\NewSignupReviewProvider.php
<?php

namespace Company\Customer\Model;


class NewSignupReviewProvider
{
    public function getList($indexById = true)
    {
        $data = [
            '' => 'Please select',
            705 => 'Rejected',
            706 => 'Unrejected'
        ];

        if ($indexById) {
            return $data;
        }

        $options = [];
        foreach ($data as $id => $value) {
            $options[] = [
                'id' => $id,
                'value' => $value
            ];
        }
        return $options;
    }
}

Thanks @RakeshJesadiya , you saved my dayS!

Was this page helpful?
0 / 5 - 0 ratings