Magento2 Custom Customer Attribute – How to Save Data

customcustomermagento2

I cannot save data for custom customer attributes in Magento2 admin.

I am creating custom Customer Attributes in a {customModule}/Setup/UpgradeData.php script. To execute it, I remove the entry for that module from the DB table setup_module (or update the module.xml version) and run bin/magento setup:upgrade from the command line. I have tried clearing the generation and other caches, re-indexing, etc.

This creates the custom attributes and displays them in admin>customer>edit, but it does not allow any data to be saved for that attribute. The same is true for custom attributes which were created by the migration tool. Standard attributes such as name or birthdate are editable. I have compared the data in tables eav_attribute, eav_form_element, customer_form_attribute and any others I can find but to no avail.

Can anyone see what is going wrong?

Here is the script:

<?php

namespace {Vendor}\{Module}\Setup;


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


class UpgradeData implements UpgradeDataInterface
{

private $customerSetupFactory;
private $attributeSetFactory;

public function __construct(
    \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory,
    AttributeSetFactory $attributeSetFactory
    )
{
    $this->customerSetupFactory = $customerSetupFactory;
    $this->attributeSetFactory = $attributeSetFactory;


}


public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{   
    $attributeCode = "test";
    $installer = $setup;
    $installer->startSetup();

    $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);

    $customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
    $attributeSetId = $customerEntity->getDefaultAttributeSetId();
    $attributeSet = $this->attributeSetFactory->create();
    $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);



    $customerSetup->removeAttribute(\Magento\Customer\Model\Customer::ENTITY, $attributeCode);

    $customerSetup->addAttribute(\Magento\Customer\Model\Customer::ENTITY, $attributeCode,  array(
        "type"     => "varchar",
        "backend"  => "",
        "label"    => $attributeCode.'label',
        "input"    => "text",
        "source"   => "",
        "visible"  => true,
        "required" => false,
        "default" => "",
        "frontend" => "",
        "unique"     => false,
        "note"       => "",
        "system"  => false,

    ));

 //Alternate to setting these id's to 1, I tried this:
 //$customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
 //$attributeSetId = $customerEntity->getDefaultAttributeSetId();
 //$attributeSet = $this->attributeSetFactory->create();
 //$attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);
 // 'attribute_set_id' => $attributeSetId,
 // 'attribute_group_id' => $attributeGroupId


    $my_attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, $attributeCode)
    ->setData([
        'attribute_set_id' => 1,
        'attribute_group_id' => 1,
        'used_in_forms' => ['adminhtml_customer'],
        'used_in_forms' => ['checkout_register'],
    'used_in_forms' => ['customer_account_create'],
    'used_in_forms' => ['customer_account_edit'],
    'used_in_forms' => ['adminhtml_checkout'],
    ]);

    $my_attribute->save();
    $installer->endSetup();

    }

}

Still working on this…
I am checking what is saved in the DB with this query:

SELECT ea.attribute_id, ea.attribute_code, eea.`attribute_set_id`,  eea.`attribute_group_id`, efe.type_id, cea.is_system, ceaw.website_id,  cfa.form_code FROM eav_attribute as ea
inner join eav_entity_attribute as eea ON ea.attribute_id = eea.`attribute_id`
left join eav_form_element as efe ON ea.attribute_id = efe.`attribute_id`
left join customer_eav_attribute as cea ON ea.attribute_id = cea.attribute_id
left join customer_eav_attribute_website as ceaw ON ea.attribute_id =   ceaw.`attribute_id`
left join customer_form_attribute as cfa ON ea.attribute_id = cfa.attribute_id
WHERE ea.attribute_code IN ('testb', 'dob', 'lastname')
AND ea.entity_type_id=1     

(Both 'dob' and 'lastname' are attributes which do save). The only thing I see is that my test attribute is not affiliated with a website in customer_eav_attribute_website, but neither is 'dob'.

Best Answer

You have to keep below code inside your UpgradeData.php file,

<?php
/**
 * Copyright © 2015 Clounce. All rights reserved.
 * See LICENSE.txt for license details.
 */

namespace {Vendor}\{Module}\Setup;

use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Customer\Model\Customer;

class UpgradeData implements UpgradeDataInterface
{
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * Installs data for a module
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);

        $attributes = [
            'test'=> [
                "type"     => "varchar",
                "label"    => "Your custom label",
                "input"    => "text",                
                'sort_order' => 100,
                "required" => false,
                'position' => 100,
                'system' => false,                
                //'validate_rules' => 'a:2:{s:15:"max_text_length";i:255;s:15:"min_text_length";i:1;}',
            ],
        ];

        foreach ($attributes as $code => $options) {
            $eavSetup->addAttribute(
                Customer::ENTITY,
                $code,
                $options
            );
        }

        $this->installCustomerForms($eavSetup);
    }

    /**
     * Add customer attributes to customer forms
     */
    public function installCustomerForms(EavSetup $eavSetup)
    {
        $customer = (int)$eavSetup->getEntityTypeId(\Magento\Customer\Model\Customer::ENTITY);
        /**
         * @var ModuleDataSetupInterface $setup
         */
        $setup = $eavSetup->getSetup();

        $attributeIds = [];
        $select = $setup->getConnection()->select()->from(
            ['ea' => $setup->getTable('eav_attribute')],
            ['entity_type_id', 'attribute_code', 'attribute_id']
        )->where(
            'ea.entity_type_id IN(?)',
            [$customer]
        );
        foreach ($eavSetup->getSetup()->getConnection()->fetchAll($select) as $row) {
            $attributeIds[$row['entity_type_id']][$row['attribute_code']] = $row['attribute_id'];
        }

        $data = [];

        $attributes = [
            'test'=> [
                "type"     => "varchar",
                "label"    => "Your custom label",
                "input"    => "text",                
                'sort_order' => 100,
                "required" => false,
                'position' => 100,
                'system' => false,                
                //'validate_rules' => 'a:2:{s:15:"max_text_length";i:255;s:15:"min_text_length";i:1;}',
            ],
        ];

        foreach ($attributes as $attributeCode => $attribute) {
            $attributeId = $attributeIds[$customer][$attributeCode];
            $attribute['system'] = isset($attribute['system']) ? $attribute['system'] : true;
            $attribute['visible'] = isset($attribute['visible']) ? $attribute['visible'] : true;
            if ($attribute['system'] != true || $attribute['visible'] != false) {
                $usedInForms = ['customer_account_create','adminhtml_customer','checkout_register','customer_account_edit','adminhtml_checkout'];

                foreach ($usedInForms as $formCode) {
                    $data[] = ['form_code' => $formCode, 'attribute_id' => $attributeId];
                }
            }
        }

        if ($data) {
            $setup->getConnection()->insertOnDuplicate($setup->getTable('customer_form_attribute'), $data);
        }
    }
}

Remove var folder from root and run command,

php bin/magento setup:upgrade

and

php bin/magento indexer:reindex

Check again. Its working.