magento / magento2

Prior to making any Submission(s), you must sign an Adobe Contributor License Agreement, available here at: https://opensource.adobe.com/cla.html. All Submissions you make to Adobe Inc. and its affiliates, assigns and subsidiaries (collectively “Adobe”) are subject to the terms of the Adobe Contributor License Agreement.
http://www.magento.com
Open Software License 3.0
11.5k stars 9.31k forks source link

Custom customer attribute not saves #1393

Closed sashas777 closed 9 years ago

sashas777 commented 9 years ago

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.

Vinai commented 9 years ago

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.

vpelipenko commented 9 years ago

@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?

sashas777 commented 9 years ago

@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

vpelipenko commented 9 years ago

Internal ticket: MAGETWO-39121

vpelipenko commented 9 years ago

@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.

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();
        }
    }
}
sashas777 commented 9 years ago

Thanks. It works

phanikumar111 commented 8 years ago

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);

Mohammed8960 commented 8 years ago

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

webkulabhi commented 8 years ago
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();
    }
}
Mohammed8960 commented 8 years ago

this worked with me

carloshernan007 commented 7 years ago

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

sashas777 commented 7 years ago

@carloshernan007 Please try this one: http://www.extensions.sashas.org/blog/magento-2-1-3-how-to-make-customer-attribute-update.html

carloshernan007 commented 7 years ago

@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 \Magento\Framework\Reflection\MethodsMap\DataObjectHelper 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

carloshernan007 commented 7 years ago

@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.

sashas777 commented 7 years ago

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

Thanks

carloshernan007 commented 7 years ago

Ok, thanks for your help

danielruedaa commented 7 years ago

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.

sashas777 commented 7 years ago

@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.

danielruedaa commented 7 years ago

thanks for your help

darkogoles1 commented 6 years ago

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

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

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.

jafar247commerce commented 5 years ago

@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

akssaiyad commented 4 years ago

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();
        }
    }
}
ShlokPurani commented 4 years ago

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;
    }
}
\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;
    }
}
RakeshJesadiya commented 4 years ago

you can check the articles to fix this issue, https://www.rakeshjesadiya.com/issue-customer-attribute-not-saving-value-in-admin-panel-magento-2/

moshe770 commented 4 years ago

Thanks @RakeshJesadiya , you saved my dayS!