My goal is to join another (custom) table to the collection of the customer list ui component in adminhtml and by that add a condition which customers are shown.

What is the best (or any way) to do that?

I ve tried preferences for the DataProvider Magento\Customer\Ui\Component\DataProvider as well as the Grid Collection Magento\Customer\Model\ResourceModel\Grid\Collection. But they didnt work, because from what i ve seen, those classes are instantiated with new XYZ via Object Manager.

I tried changing the used collection via .xml in di.xml

<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
            <argument name="collections" xsi:type="array">
                <item name="customer_listing_data_source" xsi:type="string">MYCUSTOM\MODULE\..\Customer\Grid\Collection</item>

I ran out of ideas to accomplish my goal.


I have tried a solution which might be work for you.

At this case, I am doing below step to add a custom table with customer grid

Step1: Change the Data source class from UI Collection factory:

Instead of Changes data source class of customer_listing_data_source from di.xml(<item name="customer_listing_data_source" xsi:type="string">MYCUSTOM\MODULE\..\Customer\Grid\Collection</item>)

I have using plugin around method over class Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory

Have changed GetReport() method output using own grid collection class.

di.xml code

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
        <plugin disabled="false" 
                        sortOrder="10" type="StackExchange\Magento\Plugin\UiComponent\DataProvider\CollectionFactoryPlugin"/>

And Plugin Class:

namespace StackExchange\Magento\Plugin\UiComponent\DataProvider;
 * Magento\Customer\Model\ResourceModel\Grid\Collection
use Magento\Framework\Data\Collection;
use Magento\Framework\ObjectManagerInterface;

class CollectionFactoryPlugin {

     * @var Collection[]
    protected $collections;

     * @var ObjectManagerInterface
    protected $objectManager;

     * @param ObjectManagerInterface $objectManagerInterface
     * @param array $collections
    public function __construct(
        ObjectManagerInterface $objectManagerInterface,
        array $collections = []
    ) {
        $this->collections = $collections;
        $this->objectManager = $objectManagerInterface;
    public function aroundGetReport(
        \Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory $subject,
        \Closure $proceed,
     if($requestName !== 'customer_listing_data_source') 
         return $proceed($requestName);

        $collection = $this->objectManager->create(\StackExchange\Magento\Model\ResourceModel\Grid\Customer\Collection::CLASS);
        if (!$collection instanceof Collection) {
            throw new \Exception(sprintf('%s is not of Collection type.', $requestName));
        return $collection;

Steps2: Create grid Collection which is a replica of original Class

Create a grid collection class StackExchange\Magento\Model\ResourceModel\Grid\Customer which is replica of original grid class Magento\Customer\Model\ResourceModel\Grid\Collection

And that new Class on _initSelect() add the custom table with Magento Collection class.

And after that, i have to map the field of the custom fields to $_map variable, So that error does not occur during filter.

 protected $_map = ['fields' => 
        ['entity_id' => 'main_table.entity_id'],
        'total_qty' => 'testorder.total_qty' // Custom table field

New grid Class


namespace StackExchange\Magento\Model\ResourceModel\Grid\Customer;

use Magento\Customer\Ui\Component\DataProvider\Document;
use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy;
use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory;
use Magento\Framework\Event\ManagerInterface as EventManager;
use Psr\Log\LoggerInterface as Logger;

class Collection extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult
     * @inheritdoc
    protected $document = Document::class;

     * @inheritdoc
    protected $_map = ['fields' => 
        ['entity_id' => 'main_table.entity_id'],
        'total_qty' => 'testorder.total_qty'

     * Initialize dependencies.
     * @param EntityFactory $entityFactory
     * @param Logger $logger
     * @param FetchStrategy $fetchStrategy
     * @param EventManager $eventManager
     * @param string $mainTable
     * @param string $resourceModel
    public function __construct(
        EntityFactory $entityFactory,
        Logger $logger,
        FetchStrategy $fetchStrategy,
        EventManager $eventManager,
        $mainTable = 'customer_grid_flat',
        $resourceModel = \Magento\Customer\Model\ResourceModel\Customer::class
    ) {
        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel);
    protected function _initSelect() {

                ['salesorder' => $this->getTable('testorder')], 
                'salesorder.customer_id = main_table.entity_id',
        return $this;
    protected function _initInitialFieldsToSelect() {


Next step: add the custom field to customer_listing.xml

the last step add your field to app/code/vendor/Module/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">
        <column name="total_qty">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="filter" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Total</item>
  • Thank you. I thought about this too. I think there should be a better way to do something like this by default. But apparently there isnt. So im going this way. – Ben Feb 19 at 12:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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