How to Add Customer Attribute in Magento 2

customer-attributeeavmagento2magento2-dev-betasetup-script

Note: The question was referring to and the code for setup scripts is not the same anymore in Magento 2.x.

I'm playing with Magento 2 and I'm stuck in adding attribute for customer entity. I got attribute properly installed using data installer, but I can't get it displayed in forms.

My data-install-2.0.0.php setup script looks as follows:

/* @var $this \Magento\Customer\Model\Resource\Setup */
$installer = $this;

$installer->startSetup();

// Add nickname attribute
$installer->addAttribute(
    'customer',
    'nickname',
    [
        'type' => 'varchar',
        'label' => 'Nickname',
        'input' => 'text',
        'required' => true,
        'sort_order' => 75,
        'visible' => true,
        'system' => true,
        'unique' => true,
        'position' => 75,
    ]
);


$nicknameAttribute = $installer->getEavConfig()->getAttribute('customer', 'nickname');
$nicknameAttribute->setData(
    'used_in_forms',
    ['customer_account_create', 'customer_account_edit', 'checkout_register', 'adminhtml_customer']
);
$nicknameAttribute->save();

$installer->endSetup();

This part works fine, after running setup/index.php update my attribute is visible in database tables (eav_attribute, customer_eav_attribute, customer_form_attribute). However it's not visible in forms.

I added following in etc/fieldset.xml in my custom module:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Object/etc/fieldset.xsd">
    <scope id="global">
        <fieldset id="customer_account">
            <field name="nickname">
                <aspect name="create" />
                <aspect name="update" />
                <aspect name="name" />
            </field>
        </fieldset>
    </scope>
</config>

It looks it does nothing.

Then I added following in data_source/customer.xml:

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="../../../../../../app/code/Magento/Ui/etc/data_source.xsd">
    <dataSource
            name="account" label="Account Information"
            dataSet="Magento\Customer\Model\Resource\Customer\Collection">
        <fields entityType="customer">
            <field name="nickname" source="eav" dataType="text"/>
        </fields>
    </dataSource>
</config>

This actually does something, it breaks backend customer form with exception:

More than one node matching the query: /config/dataSource[@name='account']/fields/field

I guess adding to these two xml files from core module in custom module should be done in some other way.

At the end I did one more thing just for testing. I removed etc/fieldset.xml and data_source/customer.xml from my module and added that content in Magento_Customer core module. This resulted in having my field displayed in backend (hooray!), but saving still doesn't work and throws error message:

"Nickname" is a required value.

So my questions are:

  1. What is a valid way to alter etc/fieldset.xml and data_source/customer.xml in custom module?

  2. What else should be done to have custom attribute being saved?

  3. How can I do this for frontend registration form? Adding field in form/register.phtml doesn't do the magic.

Best Answer

Note: This answer was referring to and the code for setup scripts is not the same anymore in Magento 2.x.

Finally I can provide answer to my question. Adding customer attribute and having it displayed in backend form doesn't require to change anything in XML files. It could be achieved by doing following in install/upgrade script:

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

    $customerSetup->addAttribute(
        \Magento\Customer\Model\Customer::ENTITY,
        'nickname',
        [
            'label'            => 'Nickname',
            'required'         => 0,
            'system'           => 0,
            'position'         => 100
        ]
    );

    $customerSetup->getEavConfig()->getAttribute('customer', 'nickname')
        ->setData('used_in_forms', ['adminhtml_customer'])
        ->save();

system property set to 0 is crucial, in other case attribute value won't be saved.

It works well on current develop branch.