Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can we add customer attribute? #1238

Closed
HirokazuNishi opened this issue May 6, 2015 · 22 comments

Comments

Projects
None yet
@HirokazuNishi
Copy link
Contributor

commented May 6, 2015

In some cases, merchants hope to add some custom attributes for customer entity.
I already added custom attributes via setup scripts and create data_source xml files. But I defined this xml below, Magento reported error "More than one node matching the query".
How should I do?

    <dataSource
            name="account" label="Account Information"
            dataSet="Magento\Customer\Model\Resource\Customer\Collection">
        <fields entityType="customer">
            <field name="firstnamekana" source="eav" dataType="text">
                <constraints>
                    <validate name="required-entry"/>
                </constraints>
            </field>
            <field name="lastnamekana" source="eav" dataType="text">
                <constraints>
                    <validate name="required-entry"/>
                </constraints>
            </field>
        </fields>
    </dataSource>

@vpelipenko vpelipenko added CS labels May 6, 2015

@vpelipenko

This comment has been minimized.

Copy link
Contributor

commented May 6, 2015

@HirokazuNishi, ability to add custom customer attributes is implemented as feature only in Enterprise edition, unfortunately Community edition doesn't support it.

@HirokazuNishi

This comment has been minimized.

Copy link
Contributor Author

commented May 6, 2015

You mean is...

  1. M2 EE can manage customer attributes as default feature.
  2. M2 CE can't.

I'd like to know,

  1. Is it possible to add customer attributes on M2.
  2. How to add customer attributes as Extension code?

If this issue is out of place, where should I post it?

@wojtekn

This comment has been minimized.

Copy link
Contributor

commented May 6, 2015

@vpelipenko I guess you mean backend UI which allows to manage customer attributes. It works the way you describe in Magento 1 CE/EE, however it's possible to install customer attribute in Magento 1 CE programatically.

As far as I see @HirokazuNishi tries to add attribute programatically.

I tried to do this at some point on dev beta and added question on MageStack:

http://magento.stackexchange.com/questions/50039/how-can-i-add-customer-attribute-in-magento-2

I haven't got any answers there and finally I gave up with that. I haven't tried that with latest M2 versions yet.

@vpelipenko are you saying you don't want to support adding customer attributes in Magento 2 CE programatically?

@choukalos

This comment has been minimized.

Copy link

commented May 6, 2015

Per @vpelipenko that's an enterprise feature for customer module

There's probably a way to add that functionality etc to Magento 2 CE but you'd be re-inventing the wheel. Plus in Enterprise the merchant gets a GUI to do it themselves.

Another way to add extra data to a customer entity ( or any other service layered entity for all versions of M2 ) the way to do that would be with an extensible object. Basically you create a new service and associated it via XML config with the customer load & save methods; define a PHP handler for those methods and then you're good to go.

@choukalos choukalos added the TECH label May 6, 2015

@HirokazuNishi

This comment has been minimized.

Copy link
Contributor Author

commented May 6, 2015

@wojtekn Thanks, I saw your question on MageStack and I also gave up.

@choukalos OK, where is useful documents about service contract?

@Vinai

This comment has been minimized.

Copy link
Contributor

commented May 7, 2015

Just a few thoughts:
Most of the time I do not want merchants to be able to modify attibutes in the backend (products or customers). Instead, adding an attribute programatically is much better, because that way the change is bound to a module which requires the attribute.
Also, it is synchronized between all instances (dev, integration, staging, live) because it is created and modified by setup scripts.
Because of this, access to the EE GUI to modify customer attributes was disabled for the merchants in most instances I've worked on. The only people that where allowed to use it where developers, who chose to not use it in favor of setup scripts.
Since this is such a common scenario I assume tutorials on how to create customer attributes in Magento 2 programatically will start to appear soon in the eco-system.

@Vinai

This comment has been minimized.

Copy link
Contributor

commented May 24, 2015

@HirokazuNishi Adding custom customer attributes works fine.
Here an example upgrade script:

namespace Example\CustomerAttribute\Setup;

use Magento\Customer\Model\Customer;
use Magento\Customer\Setup\CustomerSetup;
use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;

class UpgradeData implements UpgradeDataInterface
{

    /**
     * @var CustomerSetupFactory
     */
    private $customerSetupFactory;

    public function __construct(CustomerSetupFactory $customerSetupFactory)
    {
        $this->customerSetupFactory = $customerSetupFactory;
    }

    /**
     * Upgrades data for a module
     *
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     * @return void
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $dbVersion = $context->getVersion();

        if (version_compare($dbVersion, '0.1.3', '<')) {
            /** @var CustomerSetup $customerSetup */
            $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
            $customerSetup->addAttribute(
                Customer::ENTITY,
                'example',
                [
                    'label' => 'Example Attribute',
                    'required' => 0,
                    'system' => 0, // <-- important, otherwise values aren't saved.
                                   // @see Magento\Customer\Model\Metadata\CustomerMetadata::getCustomAttributesMetadata()
                    'position' => 100
                ]
            );
            $customerSetup->getEavConfig()->getAttribute('customer', 'example')
                ->setData('used_in_forms', ['adminhtml_customer'])
                ->save();
        }
    }
}

No XML is needed actually.

@vpelipenko

This comment has been minimized.

Copy link
Contributor

commented Jun 3, 2015

@HirokazuNishi, can we consider this issue resolved?

@choukalos

This comment has been minimized.

Copy link

commented Jun 3, 2015

For service contract info check out the Imagine 2015 Magento 2 Deep Dive presentations. I believe this one has some relevant information [link|http://magento.com/videos/imagine/imagine-commerce-2015-magento-2-deep-dive-session-i#.VW9Yg2B1R10]

@HirokazuNishi

This comment has been minimized.

Copy link
Contributor Author

commented Jun 10, 2015

Thank you! I successfully added and displayed custom customer attributes!

@hitendraebiz

This comment has been minimized.

Copy link

commented Jan 4, 2016

Hi @Vinai, I problem for customer attribute save from backend but not saved script .Customer model load by id and set attribute value but attribute not saved in database and replace with blank value.Can you please provide me if you have any solutions for it ?

@Vikram0811

This comment has been minimized.

Copy link

commented Feb 26, 2016

`<?php
/**

  • Copyright © 2015 Magento. All rights reserved.
  • See COPYING.txt for license details.
    */

namespace Namespace\Modulename\Setup;

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

/**

  • @codeCoverageIgnore
    /
    class UpgradeData implements UpgradeDataInterface
    {
    private $eavSetupFactory;
    /
    *

    • @param CustomerSetupFactory $customerSetupFactory
    • @param IndexerRegistry $indexerRegistry
    • @param \Magento\Eav\Model\Config $eavConfig
      */
      public function __construct(EavSetupFactory $eavSetupFactory)
      {
      $this->eavSetupFactory = $eavSetupFactory;
      }

    /**

    • {@inheritdoc}

    • @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      /
      public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
      {
      $setup->startSetup();
      /
      * @var CustomerSetup $customerSetup */
      $customerSetup = $this->eavSetupFactory->create(['setup' => $setup]);

      $customerSetup->addAttribute(
      Customer::ENTITY,
      'customer_product_points',
      [
      'type' => 'int',
      'label' => 'Customer Product Points',
      'input' => 'text',
      'required' => false,
      'visible' => false,
      'system' => false,
      ]
      );

      // add attribute to form
      /** @var $attribute */
      $attribute = $customerSetup->getEavConfig()->getAttribute('customer', 'customer_product_points');
      $attribute->setData('used_in_forms', ['adminhtml_customer']);
      $attribute->save();
      $setup->endSetup();
      }
      }`

When I upgrade, it throws below exception

Fatal error: Call to undefined method Magento\Eav\Setup\EavSetup::getEavConfig()

What I have missed here ?

@daniel-ifrim

This comment has been minimized.

Copy link

commented Mar 15, 2016

@hitendraebiz
I got stuck in same issue. Found the solution using setCustomAttribute from interface
https://github.com/magento/magento2/blob/develop/lib/internal/Magento/Framework/Api/CustomAttributesDataInterface.php#L36

/** @var \Magento\Customer\Model\Customer $customer */
/** @var \Magento\Customer\Model\Data\Customer $customerData */
$customerData = $customer->getDataModel();
$customerData->setCustomAttribute('my_attr_code', $val);
$customer->updateData($customerData);
$customer->save();
@asavchenko

This comment has been minimized.

Copy link

commented Mar 21, 2016

@daniel-ifrim, @hitendraebiz I think i figured it you need to set default attribute_set_id on customer object before calling save. In other case vendor/magento/module-eav/Model/Entity/AbstractEntity.php line 1268 check fails and called save doesn't save custom attributes as $newObject->getAttributeSetId() returns null. CustomerRepository sets magic "1" (vendor/magento/module-customer/Model/ResourceModel/CustomerRepository.php line 173) that's why it works.

@LucScu

This comment has been minimized.

Copy link

commented Oct 11, 2016

@daniel-ifrim thx for your hint!
@asavchenko please post code to fix like daniel-ifrim

@asavchenko

This comment has been minimized.

Copy link

commented Oct 11, 2016

@LucScu this is what I used to get my custom attribute saved (I've not updated this approach since March, probably there were some changes in Magento core, but it still works, so I think it's safe to share this old code).

 $defaultAttributeSetId = 1; // it's not always true, especially if you migrated to m2 from m1 check database, table  eav_attribute_set
 $customer->setData('my_attribute_code', $val);
 $customerData = $customer->getDataModel();
 $customerData->setCustomAttribute('my_attribute_code', $val);
 if (!$customer->getData('attribute_set_id')) {
     $customer->setData('attribute_set_id', $defaultAttributeSetId);
 }
 $customer->save();
@LucScu

This comment has been minimized.

Copy link

commented Oct 14, 2016

@asavchenko thx for your code, i just fix it with @daniel-ifrim code

@danielruedaa

This comment has been minimized.

Copy link

commented Feb 8, 2017

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.

@david-kominek

This comment has been minimized.

Copy link

commented Mar 16, 2017

@danielruedaa If you are still having this issue, try checking the customer_form_attributes table in your database to ensure that you have a row linking "adminhtml_customer" to your attribute. You may need to get the "attribute_id" field from the eav_attributes table. After that, make sure to clear your cache, as Magento caches form attribute data.

I'm not sure why, but I've found that Magento doesn't always create the proper form_attribute rows, even if you specify the "used_in_form" data when setting up the attribute. Could be a bug, or may be related to the attribute already existing from a previous php magento setup:upgrade. I haven't figured that one out yet.

@zeeshan2523806

This comment has been minimized.

Copy link

commented May 10, 2018

@asavchenko solution works perfect for me. Before saving any value inside your custom functionality to Products/Customer/Customer Address make sure you choose the attribute_set too otherwise your values will not gonna be saved.

@Patelcc

This comment has been minimized.

Copy link

commented Sep 12, 2018

@Vinai your code is working fine but while export customer getting error

Fatal error: Uncaught TypeError: Argument 2 passed to Magento\Framework\View\Element\UiComponentFactory::argumentsResolver() must be of the type array, null given, called in /var/www/html/tgbl222/vendor/magento/framework/View/Element/UiComponentFactory.php on line 220 and defined in /var/www/html/tgbl222/vendor/magento/framework/View/Element/UiComponentFactory.php:172 Stack trace: #0 /var/www/html/tgbl222/vendor/magento/framework/View/Element/UiComponentFactory.php(220): Magento\Framework\View\Element\UiComponentFactory->argumentsResolver('approve_account', NULL) #1 /var/www/html/tgbl222/vendor/magento/module-ui/Component/Listing/Columns/Column.php(77): Magento\Framework\View\Element\UiComponentFactory->create('approve_account', 'int', Array) #2 /var/www/html/tgbl222/vendor/magento/module-ui/Component/MassAction/Filter.php(184): Magento\Ui\Component\Listing\Columns\Column->prepare() #3 /var/www/html/tgbl222/generated/code/Magento/Ui/Component/MassAction/Filter/Interceptor.php(63): Magento\Ui\Component\MassAction\Filter->p in /var/www/html/tgbl222/vendor/magento/framework/View/Element/UiComponentFactory.php on line 172

@zeeshan2523806

This comment has been minimized.

Copy link

commented Sep 27, 2018

@Patelcc you need to clear var/generated folder and regenerate the classes again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.