Magento 2 Customer Attributes

Complete code was updated on 15 June 2016 to an issue with an undefined method

Every business captures different information about their business. Magento gives businesses the ability to define which customer information is to be gathered and stored in Magento. The customer information customisation is done through customer attributes.

The last few versions of Magento 1.X gave the flexibility to create customer attributes in Magento backend. However as at Magento 2 0.74.0-beta9 the backend functionality has not yet been implemented, so customer attributes need to be created programmatically.

Scripting the customer attributes

The steps outlined below assume that we are working on an extension called Clounce_Customer. For details of how to create the extension base refer to the article, A very basic Magento 2 module.

To create new customer attributes programmatically:

1. Create the “Setup” folder under the module code

Module Setup Folder Structure

2. Create the file “UpgradeData.php” under the “Setup” folder.

Note: While in Magento 1.X each version upgrade had its own file stating the version change, in Magento 2 there are only 4 main files. The "InstallData.php" and "UpgradeData.php" for data related scripts; and "InstallSchema.php" and "UpdateSchema.php" for database table creation and modifications. As all updates need to be handled through one file it is important to keep in mind that each run of the UpgradeData.php will execute all the commands in the file. Therefore all database updates need to consider data overriding and multiple re-runs.

  1. In the UpgradeData.php file create a class called UpgradeData that implements the UpgradeDataInterface.
    class UpgradeData implements UpgradeDataInterface
    {
    }
  2. In Magento the Customer entity is an EAV model, therefore we will need an EAV setup model. To obtain the EAV setup model we have to override the constructor method to pass it an object of type EavSetupFactory.
    /**
     * Init
     *
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }
  3. The next step is to implement the method defined by the UpgradeDataInterface.
    /**
     * Installs data for a module
     *
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     * @return void
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
    }
  4. Currently we have a standard upgrade class that does nothing and an EavSetupFactory that cannot run updates. The first step is to obtain an instance from the EavSetupFactory which will execute our attribute creation commands.
    /** @var EavSetup $eavSetup */
    $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
  5. Next we need to define the customer attributes to be created or updated. In this article we will defined the attributes as an associative array with the key being the attribute code and the value being an array of attribute options.
    $attributes = [
        'custom_1' => [
            'type' => 'int',
            'label' => 'A Yes/No Option',
            'input' => 'select',
            'source' => 'Magento\Eav\Model\Entity\Attribute\Source\Boolean',
            'required' => true, /* The field is required */
            'default' => '0', /* Defaults to the No value */
            'sort_order' => 100,
            'system' => false, /* A custom attribute */
            'position' => 100,
            'adminhtml_only' => 1, /* Do not show on frontend */
        ],
        'custom_2' => [
            'type' => 'varchar',
            'label' => 'Some custom text',
            'input' => 'text',
            'sort_order' => 101,
            'validate_rules' => 'a:2:{s:15:"max_text_length";i:255;s:15:"min_text_length";i:1;}',
            'position' => 101,
            'system' => false,
         /* 'adminhtml_only' => 0, --- If the attribute is visible in frontend and backend this line is not required. */
        ],
    ];
  6. Now that the attributes array is defined, the attributes need to be created in Magento. In this article we create the attributes by looping over the array and call addAttribute() on each attribute defined.
    foreach ($attributes as $code => $options) {
        $eavSetup->addAttribute(
            \Magento\Customer\Model\Customer::ENTITY,
            $code,
            $options
        );
    }
  7. As a final step for setting up customer attributes we need to set the forms in which the attributes will be used. Looking at the CustomerSetup.php that is provided by Magento 2, one will notice that the class contains a generic method to assign the attributes to the form based on their visibility. As the CustomerSetup class was not extended in this example, we can copy the method to our script and call it at the end of the upgrade method.
  8. Finally we need to run the upgrade script in Magento. To do this from the server command line run the command
    php bin/magento upgrade
  9. The full code for this article’s UpgradeData.php file is:

    <?php
    /**
     * Copyright © 2015 Clounce. All rights reserved.
     * See LICENSE.txt for license details.
     */
     
    namespace Clounce\Customer\Setup;
     
    use Magento\Customer\Model\Customer;
    use Magento\Eav\Setup\EavSetup;
    use Magento\Eav\Setup\EavSetupFactory;
    use Magento\Framework\Setup\UpgradeDataInterface;
    use Magento\Framework\Setup\ModuleContextInterface;
    use Magento\Framework\Setup\ModuleDataSetupInterface;
     
    class UpgradeData implements UpgradeDataInterface
    {
        /**
         * Init
         *
         * @param EavSetupFactory $eavSetupFactory
         */
        public function __construct(EavSetupFactory $eavSetupFactory)
        {
            $this->eavSetupFactory = $eavSetupFactory;
        }
     
        /**
         * A central function to return the attributes that need to be created
         *
         * Updated on 15 June 2016, following Anamika comment
         **/
        private function getNewAttributes()
        {
            return [
                'custom_1' => [
                    'type' => 'int',
                    'label' => 'A Yes/No Option',
                    'input' => 'select',
                    'source' => 'Magento\Eav\Model\Entity\Attribute\Source\Boolean',
                    'required' => true, /* The field is required */
                    'default' => '0', /* Defaults to the No value */
                    'sort_order' => 100,
                    'system' => false, /* A custom attribute */
                    'position' => 100,
                    'adminhtml_only' => 1, /* Do not show on frontend */
                ],
                'custom_2' => [
                    'type' => 'varchar',
                    'label' => 'Some custom text',
                    'input' => 'text',
                    'sort_order' => 101,
                    'validate_rules' => 'a:2:{s:15:"max_text_length";i:255;s:15:"min_text_length";i:1;}',
                    'position' => 101,
                    'system' => false,
                    /* 'adminhtml_only' => 0, --- If the attribute is visible in frontend and backend this line is not required. */
                ],
            ];
        }
        /**
         * Installs data for a module
         *
         * @param ModuleDataSetupInterface $setup
         * @param ModuleContextInterface $context
         * @return void
         */
        public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
        {
            /** @var EavSetup $eavSetup */
            $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
     
            $attributes = $this->getNewAttributes();
     
            foreach ($attributes as $code => $options) {
                $eavSetup->addAttribute(
                    Customer::ENTITY,
                    $code,
                    $options
                );
            }
     
            $this->installCustomerForms($eavSetup);
        }
     
        /**
         * Add customer attributes to customer forms
         *
         * @param EavSetup $eavSetup
         *
         * @return void
         * @SuppressWarnings(PHPMD.CyclomaticComplexity)
         * @SuppressWarnings(PHPMD.NPathComplexity)
         */
        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 = $this->getNewAttributes();
            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', 'customer_account_edit', 'checkout_register'];
                    if (!empty($attribute['adminhtml_only'])) {
                        $usedInForms = ['adminhtml_customer'];
                    } else {
                        $usedInForms[] = 'adminhtml_customer';
                    }
                    if (!empty($attribute['admin_checkout'])) {
                        $usedInForms[] = 'adminhtml_checkout';
                    }
                    foreach ($usedInForms as $formCode) {
                        $data[] = ['form_code' => $formCode, 'attribute_id' => $attributeId];
                    }
                }
            }
     
            if ($data) {
                $setup->getConnection()
                    ->insertOnDuplicate($setup->getTable('customer_form_attribute'), $data);
            }
        }
    }

    Running the script multiple times

    Once the upgrade script has been executed any further calls to the upgrade command will not perform any changes. There are a few ways to have the script re-executed.

    Method 1: Upgrading the module version

    Any easy way to re-run the script is to increment the version number in module.xml. The attribute setup_version in the module XML element is used by Magento to know if the module has changed. By incrementing the build number in the setup_version attribute and calling the upgrade command, the UpgradeData script will get executed again.
    Note: Magento 2 will not run install and upgrade scripts automatically like in Magento 1.X but they must be triggered through the command line.

    Method 2: Reduce the module version from the database

    Another way to rerun the upgrade script without changing the module version in the code is to change the version in Magento database. The table setup_module contains a list of modules installed and their current setup and data version. Locate the module entry and change the data_version value for the module to a value lower than the current version in the code. When the upgrade command is executed Magento will notice the version in the database is lower than the one published in the code and will re-run the upgrade scripts.

    Method 3: Removing the module resource from the database

    For upgrade scripts it is easy to play around with version numbers. However install scripts run only when the module is being initialised the first time. Therefore changing the module version will not rerun the install script. To rerun an install script, it is important to delete the extension reference from the database.

    Full code with frontend available on Github.

    Be Sociable, Share!
  • Anamika

    I added the above code to add custom attributes but I am getting this error

    a:4:{i:0;s:21:”Class does not exist”;i:1;s:10771:”#0 D:xampphtdocsMagento204vendormagentoframeworkCodeReaderClassReader.php(19): ReflectionClass->__construct(”)

    And one more thing after installation when I run setup:upgrade command, I am getting the below error ..

    PHP Fatal error: Call to undefined method SnapcustomerCustomerSetupSetupUpgradeData::getNewAttributes() in D:xampphtdocsMagento204appcodeSnapcustomerCustomerSetupSetupUpgradeData.php on line 232
    Fatal error: Call to undefined method SnapcustomerCustomerSetupSetupUpgradeData::getNewAttributes() in D:xampphtdocsMagento204appcodeSnapcustomerCustomerSetupSetupUpgradeData.php on line 232
    Can you please help….
    Thanks in Advance

    • The issue with the undefined method getNewAttributes() is due to the function being missing in the script. The associated array in the upgrade() function had to be moved to a method called getNewAttributes() so it is shared between the functions. Check the updated code.

      As for the error Class does not exist it is difficult to determine why the issue is occurring without having to look into the code. A few things that you might check are:
      1. Ensure that the physical class path starting from after the app/code and the class namespace match both in the part names and case. From what I can see you are using Windows, so you might have a character case issue along the path.
      2. Check the di.xml and ensure that the class names are correct.
      3. Check that you have created the register.php file at the root folder for the extension. At the time of writing the article it was not required but it is now required for the module to be found in Magento.

      If you can share more information about the Class issue, it might be helpful to determine what could be the issue. If you have solved it already, can you please indicate what was the cause.

      Thanks

      • Anamika

        Thanks for the reply…

        Please tell me where can I get the updated code.

        Here is the complete error description for “class does not exist”

        a:4:{i:0;s:21:”Class does not exist”;i:1;s:10771:”#0 D:xampphtdocsMagento204vendormagentoframeworkCodeReaderClassReader.php(19): ReflectionClass->__construct(”)
        #1 D:xampphtdocsMagento204vendormagentoframeworkObjectManagerDefinitionRuntime.php(44): MagentoFrameworkCodeReaderClassReader->getConstructor(”)
        #2 D:xampphtdocsMagento204vendormagentoframeworkObjectManagerFactoryDynamicDeveloper.php(71): MagentoFrameworkObjectManagerDefinitionRuntime->getParameters(”)
        #3 D:xampphtdocsMagento204vendormagentoframeworkObjectManagerObjectManager.php(57): MagentoFrameworkObjectManagerFactoryDynamicDeveloper->create(”, Array)
        #4 D:xampphtdocsMagento204vendormagentoframeworkValidatorUniversalFactory.php(36): MagentoFrameworkObjectManagerObjectManager->create(NULL, Array)
        #5 D:xampphtdocsMagento204vendormagentomodule-eavModelEntityAttributeAbstractAttribute.php(537): MagentoFrameworkValidatorUniversalFactory->create(NULL)
        #6 D:xampphtdocsMagento204vendormagentomodule-customerModelAttributeMetadataConverter.php(66): MagentoEavModelEntityAttributeAbstractAttribute->getSource()
        #7 D:xampphtdocsMagento204vendormagentomodule-customerModelMetadataCustomerMetadata.php(77): MagentoCustomerModelAttributeMetadataConverter->createMetadataAttribute(Object(MagentoCustomerModelAttribute))
        #8 D:xampphtdocsMagento204vendormagentomodule-customerModelMetadataCustomerMetadata.php(109): MagentoCustomerModelMetadataCustomerMetadata->getAttributeMetadata(‘Billing Method’)
        #9 D:xampphtdocsMagento204vendormagentomodule-customerModelMetadataCachedMetadata.php(94): MagentoCustomerModelMetadataCustomerMetadata->getAllAttributesMetadata()
        #10 D:xampphtdocsMagento204vendormagentomodule-customerUiComponentListingAttributeRepository.php(66): MagentoCustomerModelMetadataCachedMetadata->getAllAttributesMetadata()
        #11 D:xampphtdocsMagento204vendormagentomodule-customerUiComponentListingColumns.php(96): MagentoCustomerUiComponentListingAttributeRepository->getList()
        #12 D:xampphtdocsMagento204vendormagentoframeworkViewLayoutGeneratorUiComponent.php(148): MagentoCustomerUiComponentListingColumns->prepare()
        #13 D:xampphtdocsMagento204vendormagentoframeworkViewLayoutGeneratorUiComponent.php(145): MagentoFrameworkViewLayoutGeneratorUiComponent->prepareComponent(Object(MagentoCustomerUiComponentListingColumns))
        #14 D:xampphtdocsMagento204vendormagentoframeworkViewLayoutGeneratorUiComponent.php(126): MagentoFrameworkViewLayoutGeneratorUiComponent->prepareComponent(Object(MagentoUiComponentListing))
        #15 D:xampphtdocsMagento204vendormagentoframeworkViewLayoutGeneratorUiComponent.php(93): MagentoFrameworkViewLayoutGeneratorUiComponent->generateComponent(Object(MagentoFrameworkViewLayoutDataStructure), ‘customer_listin…’, Array, Object(MagentoFrameworkViewLayoutInterceptor))
        #16 D:xampphtdocsMagento204vendormagentoframeworkViewLayoutGeneratorPool.php(86): MagentoFrameworkViewLayoutGeneratorUiComponent->process(Object(MagentoFrameworkViewLayoutReaderContext), Object(MagentoFrameworkViewLayoutGeneratorContext))
        #17 D:xampphtdocsMagento204vendormagentoframeworkViewLayout.php(327): MagentoFrameworkViewLayoutGeneratorPool->process(Object(MagentoFrameworkViewLayoutReaderContext), Object(MagentoFrameworkViewLayoutGeneratorContext))
        #18 D:xampphtdocsMagento204vargenerationMagentoFrameworkViewLayoutInterceptor.php(89): MagentoFrameworkViewLayout->generateElements()
        #19 D:xampphtdocsMagento204vendormagentoframeworkViewLayoutBuilder.php(129): MagentoFrameworkViewLayoutInterceptor->generateElements()
        #20 D:xampphtdocsMagento204vendormagentoframeworkViewPageBuilder.php(55): MagentoFrameworkViewLayoutBuilder->generateLayoutBlocks()
        #21 D:xampphtdocsMagento204vendormagentoframeworkViewLayoutBuilder.php(65): MagentoFrameworkViewPageBuilder->generateLayoutBlocks()
        #22 D:xampphtdocsMagento204vendormagentoframeworkViewLayout.php(244): MagentoFrameworkViewLayoutBuilder->build()
        #23 D:xampphtdocsMagento204vendormagentoframeworkViewLayout.php(859): MagentoFrameworkViewLayout->build()
        #24 D:xampphtdocsMagento204vargenerationMagentoFrameworkViewLayoutInterceptor.php(414): MagentoFrameworkViewLayout->getBlock(‘menu’)
        #25 D:xampphtdocsMagento204vendormagentomodule-backendModelViewResultPage.php(59): MagentoFrameworkViewLayoutInterceptor->getBlock(‘menu’)
        #26 D:xampphtdocsMagento204vargenerationMagentoBackendModelViewResultPageInterceptor.php(24): MagentoBackendModelViewResultPage->setActiveMenu(‘Magento_Custome…’)
        #27 D:xampphtdocsMagento204vendormagentomodule-customerControllerAdminhtmlIndexIndex.php(26): MagentoBackendModelViewResultPageInterceptor->setActiveMenu(‘Magento_Custome…’)
        #28 D:xampphtdocsMagento204vargenerationMagentoCustomerControllerAdminhtmlIndexIndexInterceptor.php(24): MagentoCustomerControllerAdminhtmlIndexIndex->execute()
        #29 D:xampphtdocsMagento204vendormagentoframeworkAppActionAction.php(102): MagentoCustomerControllerAdminhtmlIndexIndexInterceptor->execute()
        #30 D:xampphtdocsMagento204vendormagentomodule-backendAppAbstractAction.php(226): MagentoFrameworkAppActionAction->dispatch(Object(MagentoFrameworkAppRequestHttp))
        #31 [internal function]: MagentoBackendAppAbstractAction->dispatch(Object(MagentoFrameworkAppRequestHttp))
        #32 D:xampphtdocsMagento204vendormagentoframeworkInterceptionInterceptor.php(74): call_user_func_array(Array, Array)
        #33 D:xampphtdocsMagento204vendormagentoframeworkInterceptionChainChain.php(70): MagentoCustomerControllerAdminhtmlIndexIndexInterceptor->___callParent(‘dispatch’, Array)
        #34 D:xampphtdocsMagento204vendormagentoframeworkInterceptionChainChain.php(63): MagentoFrameworkInterceptionChainChain->invokeNext(‘Magento\Custome…’, ‘dispatch’, Object(MagentoCustomerControllerAdminhtmlIndexIndexInterceptor), Array, ‘adminAuthentica…’)
        #35 D:xampphtdocsMagento204vendormagentomodule-backendAppActionPluginAuthentication.php(143): MagentoFrameworkInterceptionChainChain->MagentoFrameworkInterceptionChain{closure}(Object(MagentoFrameworkAppRequestHttp))
        #36 [internal function]: MagentoBackendAppActionPluginAuthentication->aroundDispatch(Object(MagentoCustomerControllerAdminhtmlIndexIndexInterceptor), Object(Closure), Object(MagentoFrameworkAppRequestHttp))
        #37 D:xampphtdocsMagento204vendormagentoframeworkInterceptionChainChain.php(68): call_user_func_array(Array, Array)
        #38 D:xampphtdocsMagento204vendormagentoframeworkInterceptionChainChain.php(63): MagentoFrameworkInterceptionChainChain->invokeNext(‘Magento\Custome…’, ‘dispatch’, Object(MagentoCustomerControllerAdminhtmlIndexIndexInterceptor), Array, ‘designLoader’)
        #39 D:xampphtdocsMagento204vendormagentoframeworkAppActionPluginDesign.php(39): MagentoFrameworkInterceptionChainChain->MagentoFrameworkInterceptionChain{closure}(Object(MagentoFrameworkAppRequestHttp))
        #40 [internal function]: MagentoFrameworkAppActionPluginDesign->aroundDispatch(Object(MagentoCustomerControllerAdminhtmlIndexIndexInterceptor), Object(Closure), Object(MagentoFrameworkAppRequestHttp))
        #41 D:xampphtdocsMagento204vendormagentoframeworkInterceptionChainChain.php(68): call_user_func_array(Array, Array)
        #42 D:xampphtdocsMagento204vendormagentoframeworkInterceptionInterceptor.php(136): MagentoFrameworkInterceptionChainChain->invokeNext(‘Magento\Custome…’, ‘dispatch’, Object(MagentoCustomerControllerAdminhtmlIndexIndexInterceptor), Array, ‘adminMassaction…’)
        #43 D:xampphtdocsMagento204vendormagentomodule-backendAppActionPluginMassactionKey.php(33): MagentoCustomerControllerAdminhtmlIndexIndexInterceptor->MagentoFrameworkInterception{closure}(Object(MagentoFrameworkAppRequestHttp))
        #44 [internal function]: MagentoBackendAppActionPluginMassactionKey->aroundDispatch(Object(MagentoCustomerControllerAdminhtmlIndexIndexInterceptor), Object(Closure), Object(MagentoFrameworkAppRequestHttp))
        #45 D:xampphtdocsMagento204vendormagentoframeworkInterceptionInterceptor.php(141): call_user_func_array(Array, Array)
        #46 D:xampphtdocsMagento204vargenerationMagentoCustomerControllerAdminhtmlIndexIndexInterceptor.php(39): MagentoCustomerControllerAdminhtmlIndexIndexInterceptor->___callPlugins(‘dispatch’, Array, Array)
        #47 D:xampphtdocsMagento204vendormagentoframeworkAppFrontController.php(55): MagentoCustomerControllerAdminhtmlIndexIndexInterceptor->dispatch(Object(MagentoFrameworkAppRequestHttp))
        #48 [internal function]: MagentoFrameworkAppFrontController->dispatch(Object(MagentoFrameworkAppRequestHttp))
        #49 D:xampphtdocsMagento204vendormagentoframeworkInterceptionInterceptor.php(74): call_user_func_array(Array, Array)
        #50 D:xampphtdocsMagento204vendormagentoframeworkInterceptionChainChain.php(70): MagentoFrameworkAppFrontControllerInterceptor->___callParent(‘dispatch’, Array)
        #51 D:xampphtdocsMagento204vendormagentoframeworkInterceptionInterceptor.php(136): MagentoFrameworkInterceptionChainChain->invokeNext(‘Magento\Framewo…’, ‘dispatch’, Object(MagentoFrameworkAppFrontControllerInterceptor), Array, ‘install’)
        #52 D:xampphtdocsMagento204vendormagentoframeworkModulePluginDbStatusValidator.php(69): MagentoFrameworkAppFrontControllerInterceptor->MagentoFrameworkInterception{closure}(Object(MagentoFrameworkAppRequestHttp))
        #53 [internal function]: MagentoFrameworkModulePluginDbStatusValidator->aroundDispatch(Object(MagentoFrameworkAppFrontControllerInterceptor), Object(Closure), Object(MagentoFrameworkAppRequestHttp))
        #54 D:xampphtdocsMagento204vendormagentoframeworkInterceptionInterceptor.php(141): call_user_func_array(Array, Array)
        #55 D:xampphtdocsMagento204vargenerationMagentoFrameworkAppFrontControllerInterceptor.php(26): MagentoFrameworkAppFrontControllerInterceptor->___callPlugins(‘dispatch’, Array, Array)
        #56 D:xampphtdocsMagento204vendormagentoframeworkAppHttp.php(115): MagentoFrameworkAppFrontControllerInterceptor->dispatch(Object(MagentoFrameworkAppRequestHttp))
        #57 D:xampphtdocsMagento204vendormagentoframeworkAppBootstrap.php(258): MagentoFrameworkAppHttp->launch()
        #58 D:xampphtdocsMagento204index.php(39): MagentoFrameworkAppBootstrap->run(Object(MagentoFrameworkAppHttp))
        #59 {main}”;s:3:”url”;s:108:”/Magento204/admin/customer/index/index/key/c1e2bcac554d7d95f4865c4dbca7ec7d2aaacb035c280863e381bda022577975/”;s:11:”script_name”;s:21:”/Magento204/index.php”;}
        Thanks once again

        • From the error, on line #6 it indicates that you have the source field set on one of the attributes which is referencing a class that is not present. This is most likely a naming issue or if you are using one of the Magento available sources, make sure that the class is available since they might have changed it in later releases.

          Alternatively you have an attribute that has the input field to ‘select’ or one of the options with a list. If you fetch the line indicated in MagentoCustomerModelAttributeMetadataConverter line 66, The line before and the line in the error state:

          if ($attribute->usesSource()) {
          foreach ($attribute->getSource()->getAllOptions() as $option) {

          This means that the attribute requires a source to be specified in order to read the available options. My understanding from the error is that error is that you either have set the attribute input field incorrectly or if you really need to have option values for the attribute you have to define a class in the source field.

          If you do have the source field and it is a Magento provided class, try to add a backslash () in from of the class name, like MagentoEavModelEntityAttributeSourceBoolean. This initial backslash is required since now the Magento files are in the vendor folder.

          However I think it is more likely that you have missed the source field since the error on line #5 is MagentoFrameworkValidatorUniversalFactory->create(NULL).

          Hope this helps you out. If it doesn’t you, you can share the files over some file transfer software, like wetransfer or google drive. Unfortunately I don’t have a file server available where you can place the code.

          • Anamika

            Thank you So much….
            I added custom source files for custom select fields. Now it is working fine.
            But after creating customer . The values for custom fields are not displaying in the grid. May be they are not saving in the database. Should i specifically add custom fields to customer_entity and customer_grid_flat tables using Installschema.php . Please clarify.
            Thanks in Advance

          • You shouldn’t need to add the custom attributes to any other tables. Looking at the Customer Upgrade scripts of Magento they have added the following fields to the attributes. I haven’t tried this out to verify it but worth trying it out.

            $entityAttributes = [
            ‘customer’ => [
            ” => [
            ‘is_used_in_grid’ => true,
            ‘is_visible_in_grid’ => true,
            ‘is_filterable_in_grid’ => true,
            ‘is_searchable_in_grid’ => false,
            ],
            ],
            ];
            $this->upgradeAttributes($entityAttributes, $customerSetup);

            Replace the part with the name you used earlier, like custom_1.
            Also to check if the values are being stored for the custom select attributes you should check the customer_entity_int table for any values of the new attributes. You can obtain the attribute_id from the eav_attribute table.

            Let me know how it goes.

          • Anamika

            HI..
            Thanks. I have already added all those parameters in the upgradeData.php . All the attributes are inserted into the database but the values are not inserting and i am getting blank in customer admin grid for those custom attribute values.

            I have checked in all the customer related tables in database but it is not inserting into it.

            Anyways I will try it again. Let me know if any other things need to be done.
            Thank you

          • Anamika

            HI,

            Thanks.

            I have already added all those parameters in the upgradeData.php. All the attributes are inserted into the database but the values were not inserting.

            The issue got fixed now, the Problem was with the parameter ‘backend_type : static” which i changed to Varchar and then the custom fields data got inserted into customer_entity_varchar and customer_grid_flat tables.
            I have added those custom fields to customer account create form also . Now I need to edit those custom fields in customer_account_edit form also. Please tell me the procedure to add custom fields in customer_account_edit section (frontend)

            Thanks in Advance.

          • Hi,

            The frontend edit form is all hardcoded. They have never changed it to load the fields dynamically. You will need to create your own template and replace the Magento provided one. This can be done through the layout xml in your module.

            Regards

          • Anamika

            HI
            Thanks for the information. Can you please tell me some more information to add custom fields in customer edit section.
            Thanks in Advance

          • Hi Anamika,

            I have placed the code on github, https://github.com/kdemanuele/Magento2-Adding-Customer-Attribute, for the backend and frontend. The code is based on the code in this article. Hope it helps you out.

            Regards

          • Anamika

            HI,

            Thank you so much for your help. Actually I did the same thing for customer edit. But I edited files of magento-customer module where I was able to get the custom values but after modification it was not saving into database. Anyways now i know where I have done mistakes. Once again Thanks for everything.

  • Abhishek Gupta

    Hello ,I have done all above but value which I insert in custom attribute do not save in database
    Please , can anybody help me?