1

Seriously why is this such an exercise in frustration?

I've added my custom customer attribute using the EAV model, the PROPER way. I'm able to save this attribute when I save a customer.

I've added MyModule\view\adminhtml\ui_component\customer_listing.xml with the following code

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="customer_columns" class="Magento\Customer\Ui\Component\Listing\Columns">
        <column name="constit_id">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="editor" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Constit ID</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

Problem is, I don't think I'm getting data for the constit_id column. I've looked at how the customer core module generates this data, and of course, none of any non-core attributes are included when ->getData() is called.

3
  • 1
    Did you get any solution? I am also stuck in same problem. Commented Jul 26, 2016 at 9:26
  • Yes. I'll share my answer. Its sorta complicated.
    – CarComp
    Commented Jul 26, 2016 at 12:02
  • I have added it but export csv not working, any solution for this, please help
    – Naveenbos
    Commented Nov 29, 2018 at 12:37

3 Answers 3

1

There is no need to create /companyname/modulename/view/adminhtml/ui_component/customer_listing.xml.

Instead, you need to create etc/indexer.xml with the following contents. In this example, I'm adding a mobile attribute and its type is text (database column type)

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Indexer/etc/indexer.xsd">
    <indexer id="customer_grid">
        <fieldset name="customer">
            <field name="mobile" xsi:type="filterable" dataType="text" />
        </fieldset>
    </indexer>
</config>

While creating your attribute via InstallData.php, 'is_used_in_grid' => 1, should be set.

After all these code setups, you have to run bin/magento setup:upgrade and then bin/magento indexer:reindex

0

I was also stuck in the same problem but I have found a solution for it. First thing, create a simple module and make an attribute using

namespace Deepak\Customer2\Setup;

use Magento\Framework\Module\Setup\Migration;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

class InstallData implements InstallDataInterface {

    /**
     * Customer setup factory
     *
     * @var \Magento\Customer\Setup\CustomerSetupFactory
     */
    private $customerSetupFactory;

    /**
     * Init
     *
     * @param \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory
     */
    public function __construct(\Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory) {
        $this->customerSetupFactory = $customerSetupFactory;
    }

    /**
     * Installs DB schema for a module
     *
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context
     * @return void
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) {
        $installer = $setup;
        $installer->startSetup();
        $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);
        $entityTypeId = $customerSetup->getEntityTypeId(\Magento\Customer\Model\Customer::ENTITY);

        $customerSetup->addAttribute(\Magento\Customer\Model\Customer::ENTITY, "is_employee", array(
            "type" => "int",
            "backend" => "",
            "label" => "Employee",
            "input" => "boolean",
            "visible" => true,
            "required" => false,
            "default" => "",
            "frontend" => "",
            "unique" => true,
            "note" => "",
        ));

        $employee = $customerSetup->getAttribute(\Magento\Customer\Model\Customer::ENTITY, "is_employee");

        $employee = $customerSetup->getEavConfig()->getAttribute(\Magento\Customer\Model\Customer::ENTITY, 'is_employee');
        $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";
        $employee->setData("used_in_forms", $used_in_forms)
                ->setData("is_used_for_customer_segment", true)
                ->setData("is_system", 0)
                ->setData("is_user_defined", 1)
                ->setData("is_visible", 1)
                ->setData("sort_order", 100);
        $employee->save();

        $installer->endSetup();
    }

}


this file(app/code/[Vendor]/[Module]/Setup/InstallData.php). It will create an input field in the backend form and add an attribute in DB. You can also save its values in DB. but there is no column in the customer grid. so you need to create a UI component file like

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="customer_columns" class="Magento\Customer\Ui\Component\Listing\Columns">
        <column name="is_employee">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="editor" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Employee</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </item>
            </argument>
        </column>
    </columns>
</listing> 

in app/code/[Vendor]/[Module]/view/adminhtml/ui_component/customer_listing.xml.

But the problem is still not solved, now column created in customer grid but data is not showing in it so I modified my InstallData.php by adding these lines.

 ->setData("is_used_in_grid", 1)
 ->setData("is_visible_in_grid", 1)
 ->setData("is_filterable_in_grid", 1)
 ->setData("is_searchable_in_grid", 1)

If you already created your module then you can write it into UpgradeData.php.

-1

So, this is going to be a really convoluted answer. There are a LOT of pieces in play, and it really helps to know whats going on. I am just going to post the code to get a customer attribute into the customer grid.

Also, I want to STRESS that I cobbled this code together from a helper file and an InstallData.php file, taken from a rather expansive module. Theres a 99% chance it won't just work if you copy and paste. Rather, try to understand how it works.

There are a few important things to do:

  • Be sure to extend the customer_listing.xml to inject your column into the grid.
  • Make sure the attribute is set up properly: is_searchable_in_grid, etc
  • DON'T FORGET THE MAGIC SAUCE (see commented code)
  • Use a good toolset like PhpStorm + xdebug to see whats really going on.

Files to set up:

/companyname/modulename/view/adminhtml/ui_component/customer_listing.xml

<?xml version="1.0" encoding="UTF-8"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <columns name="customer_columns" class="Magento\Customer\Ui\Component\Listing\Columns">
        <column name="constit_id">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="editor" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Constit ID</item>
                    <item name="sortOrder" xsi:type="number">10</item>
                </item>
            </argument>
        </column>
    </columns>
</listing>

To create the attribute properly, you must create it using the following methods in your InstallData.php script.

use Magento\Customer\Model\Customer;

const FORM_CUSTOMER_ADMIN = array(
        'adminhtml_customer',
        'customer_account_create',
        'customer_account_edit',
    );

const INPUT_TEXT = array (
        'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
        'input' => 'text'
    );

    const CONSTIT_ID = 'constit_id';

    protected $_userDefinedAttributeCodes = [];
    protected $eavSetupFactory;
    protected $attribute_info;
    protected $customerSetupFactory;
    protected $eavConfigFactory;
    protected $indexerRegistry;

    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Eav\Setup\EavSetupFactory $eavSetupFactory,
        \Magento\Customer\Setup\CustomerSetupFactory $customerSetupFactory,
        \Magento\Eav\Model\ConfigFactory $eavConfigFactory,
        \Magento\Eav\Model\AttributeRepository $attributeRepository,
        \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
    ) {
        $this->eavConfigFactory = $eavConfigFactory;
        $this->eavSetupFactory = $eavSetupFactory;
        $this->customerSetupFactory = $customerSetupFactory;
        parent::__construct($context);
    }

    public function configCustomerAttribute($setup, $attr_name, $pretty_name, $entity_name) {
        $attr_setup = $this->customerSetupFactory->create(['setup' => $setup]);

        $attributeExists = count($attr_setup->getAttribute($entity_name, $attr_name)) > 0;

        if (empty($attributeExists)) {
            $attr_setup->addAttribute(
                $entity_name,
                $attr_name,
                array_merge($this->attribute_info, array('label' => $pretty_name))
            );
        }

        // Pull newly created attribute
        $attribute = $this->eavConfigFactory->create()->getAttribute($entity_name, $attr_name);

        // Get current used in forms vars (if they exist)
        $used_in_forms_diff = array_diff($this->attribute_info['used_in_forms'], $attribute->getUsedInForms());

        // add the attribute to the customer_form table
        if (count($used_in_forms_diff) > 0) {
            $data = [];
            foreach ($used_in_forms_diff as $formCode) {
                $data[] = ['form_code' => $formCode, 'attribute_id' => $attribute->getId()];
            }

            $eavSetup = $this->eavSetupFactory->create();

            $eavSetup->getSetup()->getConnection()
                ->insertMultiple($eavSetup->getSetup()->getTable('customer_form_attribute'), $data);
        }

    }

    public function setAttributeInfo($where, $inputType, $required = false, $defaultValue = 0, $frontVisible = true, $useGrid = false) {
            $this->attribute_info = array_merge(self::FORM_DEFAULTS, $inputType);
            $this->attribute_info['required'] = $required;
            $this->attribute_info['used_in_forms'] = $where;
            $this->attribute_info['default'] = $defaultValue;
            $this->attribute_info['visible_on_front'] = $frontVisible;
            if ($useGrid){
                $this->attribute_info['is_used_in_grid'] = 1;
                $this->attribute_info['is_visible_in_grid'] = 1;
                $this->attribute_info['is_filterable_in_grid'] = 1;
                $this->attribute_info['is_searchable_in_grid'] = 1;
            }
        }

public function install(
            \Magento\Framework\Setup\ModuleDataSetupInterface $setup,
            \Magento\Framework\Setup\ModuleContextInterface $context)
        {

            $setup->startSetup();

    $form_set = $this::FORM_CUSTOMER_ADMIN;
    $this->setAttributeInfo($form_set, $this::INPUT_TEXT, false, '', false, true);
    $this->configCustomerAttribute($setup, self::CONSTIT_ID , 'Constit ID', 'customer');

// MAGIC SAUCE - You HAVE to manually add the dang column to the customer_grid_flat table or your value won't show up.

$definition = ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT];
                $definition['comment'] = 'STTI Constituent ID';
                $setup->getConnection()->addColumn('customer_grid_flat', self::CONSTIT_ID, $definition);

$indexer = $this->indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID);
            $indexer->reindexAll();

            $setup->endSetup();
4
  • Hi, I am getting same issue. Could you please write full code here. As some of things I dont find in code like self::FORM_DEFAULTS where is it defined. Class that you may have extended because you have used , parent::__construct($context); . Please let me know full code so it could help! Thanks
    – Rushvi
    Commented Aug 31, 2016 at 5:54
  • i am also getting same error Commented Feb 14, 2018 at 11:38
  • I am also getting the same error anyone solved this? please share your code
    – Naveenbos
    Commented Nov 29, 2018 at 12:36
  • Finding where self is defined is a simple matter of class inheritance. Look up the parent chain until you find a definition. Also, I did share the code, I said it was really difficult to do this, and its one of the 'tricks' Magento employs to get you to pay for the EE version. EE contains this functionality, and many of you probably know this and have been tasked with converting to community. There are modules out there.
    – CarComp
    Commented Nov 29, 2018 at 15:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.