Magento2 Admin Grid – How to Enable Full Text Search

magento2magento2-dev-beta

I created admin grid using UI component when I try to search from full test search or keyword search I am not getting correct search data
can any one help me on this
rest all thing are working filters is working fine, sort is working only common search is not working
app\code\Sugarcode\Test\view\adminhtml\ui_component\test_lists_listing.xml

<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../Ui/etc/ui_configuration.xsd">
    <argument name="data" xsi:type="array">
        <item name="js_config" xsi:type="array">
            <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing_data_source</item>
            <item name="deps" xsi:type="string">test_lists_listing.test_lists_listing_data_source</item>
        </item>
        <item name="spinner" xsi:type="string">test_lists_columns</item>
        <item name="buttons" xsi:type="array">
            <item name="add" xsi:type="array">
                <item name="name" xsi:type="string">add</item>
                <item name="label" xsi:type="string" translate="true">Add New Info</item>
                <item name="class" xsi:type="string">primary</item>
                <item name="url" xsi:type="string">*/*/new</item>
            </item>
        </item>
    </argument>
    <dataSource name="test_lists_listing_data_source">
        <argument name="dataProvider" xsi:type="configurableObject">
            <argument name="class" xsi:type="string">ListsGridDataProvider</argument>
            <argument name="name" xsi:type="string">test_lists_listing_data_source</argument>
            <argument name="primaryFieldName" xsi:type="string">id</argument>
            <argument name="requestFieldName" xsi:type="string">id</argument>
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="update_url" xsi:type="url" path="mui/index/render"/>
                </item>
            </argument>
        </argument>
        <argument name="data" xsi:type="array">
            <item name="js_config" xsi:type="array">
                <item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
            </item>
        </argument>
    </dataSource>
    <container name="listing_top">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="template" xsi:type="string">ui/grid/toolbar</item>
            </item>
        </argument>
        <bookmark name="bookmarks">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/controls/bookmarks/bookmarks</item>
                    <item name="displayArea" xsi:type="string">dataGridActions</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="saveUrl" xsi:type="url" path="mui/bookmark/save"/>
                        <item name="deleteUrl" xsi:type="url" path="mui/bookmark/delete"/>
                        <item name="namespace" xsi:type="string">test_lists_listing</item>
                    </item>
                </item>
            </argument>
        </bookmark>
        <container name="columns_controls">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="columnsData" xsi:type="array">
                        <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.test_lists_columns</item>
                    </item>
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/controls/columns</item>
                    <item name="displayArea" xsi:type="string">dataGridActions</item>
                </item>
            </argument>
        </container>
        <filterSearch name="fulltext">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/search/search</item>
                    <item name="displayArea" xsi:type="string">dataGridFilters</item>
                    <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing_data_source</item>
                    <item name="chipsProvider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.listing_filters_chips</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.bookmarks</item>
                        <item name="namespace" xsi:type="string">current.search</item>
                    </item>
                </item>
            </argument>
        </filterSearch>
        <filters name="listing_filters">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="displayArea" xsi:type="string">dataGridFilters</item>
                    <item name="dataScope" xsi:type="string">filters</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.bookmarks</item>
                        <item name="namespace" xsi:type="string">current.filters</item>
                    </item>
                    <item name="childDefaults" xsi:type="array">
                        <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.listing_filters</item>
                        <item name="imports" xsi:type="array">
                            <item name="visible" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item>
                        </item>
                    </item>
                </item>
            </argument>
            <filterRange name="id">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="dataScope" xsi:type="string">id</item>
                        <item name="label" xsi:type="string" translate="true">ID</item>
                        <item name="childDefaults" xsi:type="array">
                            <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.listing_filters</item>
                        </item>
                    </item>
                </argument>
                <filterInput name="from">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">from</item>
                            <item name="label" xsi:type="string" translate="true">from</item>
                            <item name="placeholder" xsi:type="string" translate="true">From</item>
                        </item>
                    </argument>
                </filterInput>
                <filterInput name="to">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">to</item>
                            <item name="label" xsi:type="string" translate="true">to</item>
                            <item name="placeholder" xsi:type="string" translate="true">To</item>
                        </item>
                    </argument>
                </filterInput>
            </filterRange>
            <filterInput name="title">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="dataScope" xsi:type="string">title</item>
                        <item name="label" xsi:type="string" translate="true">Title</item>
                    </item>
                </argument>
            </filterInput>
            <filterRange name="created_at"  class="Magento\Ui\Component\Filters\Type\DateRange">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="dataScope" xsi:type="string">created_at</item>
                        <item name="label" xsi:type="string" translate="true">Created</item>
                        <item name="childDefaults" xsi:type="array">
                            <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.listing_filters</item>
                        </item>
                    </item>
                </argument>
                <filterDate name="from">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">from</item>
                            <item name="label" xsi:type="string" translate="true">From</item>
                            <item name="placeholder" xsi:type="string" translate="true">From</item>
                            <item name="dateFormat" xsi:type="string" translate="true">MM/dd/YYYY</item>
                        </item>
                    </argument>
                </filterDate>
                <filterDate name="to">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="dataScope" xsi:type="string">to</item>
                            <item name="label" xsi:type="string" translate="true">To</item>
                            <item name="placeholder" xsi:type="string" translate="true">To</item>
                            <item name="dateFormat" xsi:type="string" translate="true">MM/dd/YYYY</item>
                        </item>
                    </argument>
                </filterDate>
            </filterRange>  
            
            <filterSelect name="status">
                <argument name="optionsProvider" xsi:type="configurableObject">
                    <argument name="class" xsi:type="string">Sugarcode\Test\Model\Status</argument>
                </argument>
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="dataScope" xsi:type="string">status</item>
                        <item name="caption" xsi:type="string" translate="true">Select...</item>
                        <item name="label" xsi:type="string" translate="true">Status</item>
                    </item>
                </argument>
            </filterSelect>
            
        </filters>
        <massaction name="listing_massaction">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="selectProvider" xsi:type="string">test_lists_listing.test_lists_listing.test_lists_columns.ids</item>
                    <item name="displayArea" xsi:type="string">bottom</item>
                    <item name="actions" xsi:type="array">
                        <item name="delete" xsi:type="array">
                            <item name="type" xsi:type="string">delete</item>
                            <item name="label" xsi:type="string" translate="true">Delete</item>
                            <item name="url" xsi:type="string">test/lists/massDelete</item>
                            <item name="confirm" xsi:type="array">
                                <item name="title" xsi:type="string" translate="true">Delete items</item>
                                <item name="message" xsi:type="string" translate="true">Are you sure you wan't to delete selected items?</item>
                            </item>
                        </item>
                        <item name="disable" xsi:type="array">
                            <item name="type" xsi:type="string">disable</item>
                            <item name="label" xsi:type="string" translate="true">Disable</item>
                            <item name="url" xsi:type="string">test/lists/massDisable</item>
                        </item>
                        <item name="enable" xsi:type="array">
                            <item name="type" xsi:type="string">enable</item>
                            <item name="label" xsi:type="string" translate="true">Enable</item>
                            <item name="url" xsi:type="string">test/lists/massEnable</item>
                        </item>                    </item>
                    <item name="indexField" xsi:type="string">id</item>
                </item>
            </argument>
        </massaction>
        <paging name="listing_paging">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.bookmarks</item>
                        <item name="namespace" xsi:type="string">current.paging</item>
                    </item>
                    <item name="selectProvider" xsi:type="string">test_lists_listing.test_lists_listing.test_lists_columns.ids</item>
                    <item name="displayArea" xsi:type="string">bottom</item>
                    <item name="options" xsi:type="array">
                        <item name="20" xsi:type="array">
                            <item name="value" xsi:type="number">20</item>
                            <item name="label" xsi:type="string" translate="true">20</item>
                        </item>
                        <item name="30" xsi:type="array">
                            <item name="value" xsi:type="number">30</item>
                            <item name="label" xsi:type="string" translate="true">30</item>
                        </item>
                        <item name="50" xsi:type="array">
                            <item name="value" xsi:type="number">50</item>
                            <item name="label" xsi:type="string" translate="true">50</item>
                        </item>
                        <item name="100" xsi:type="array">
                            <item name="value" xsi:type="number">100</item>
                            <item name="label" xsi:type="string" translate="true">100</item>
                        </item>
                        <item name="200" xsi:type="array">
                            <item name="value" xsi:type="number">200</item>
                            <item name="label" xsi:type="string" translate="true">200</item>
                        </item>
                    </item>
                </item>
            </argument>
        </paging>
    </container>
    <columns name="test_lists_columns">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="storageConfig" xsi:type="array">
                    <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.bookmarks</item>
                    <item name="namespace" xsi:type="string">current</item>
                </item>
                <item name="childDefaults" xsi:type="array">
                    <item name="fieldAction" xsi:type="array">
                        <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.test_lists_columns.actions</item>
                        <item name="target" xsi:type="string">applyAction</item>
                        <item name="params" xsi:type="array">
                            <item name="0" xsi:type="string">edit</item>
                            <item name="1" xsi:type="string">${ $.$data.rowIndex }</item>
                        </item>
                    </item>
                    <item name="controlVisibility" xsi:type="boolean">true</item>
                    <item name="storageConfig" xsi:type="array">
                        <item name="provider" xsi:type="string">test_lists_listing.test_lists_listing.listing_top.bookmarks</item>
                        <item name="root" xsi:type="string">columns.${ $.index }</item>
                        <item name="namespace" xsi:type="string">current.${ $.storageConfig.root }</item>
                    </item>
                </item>
            </item>
        </argument>
        <column name="ids" class="Magento\Ui\Component\MassAction\Columns\Column">
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/multiselect</item>
                </item>
                <item name="config" xsi:type="array">
                    <item name="indexField" xsi:type="string">id</item>
                    <item name="controlVisibility" xsi:type="boolean">false</item>
                </item>
            </argument>
        </column>
        <column name="id">
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/column</item>
                </item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="sorting" xsi:type="string">asc</item>
                    <item name="align" xsi:type="string">left</item>
                    <item name="label" xsi:type="string" translate="true">ID</item>
                    <item name="sortOrder" xsi:type="number">1</item>
                </item>
                    <item name="sortOrder" xsi:type="number">1</item>
            </argument>
        </column>
        <column name="title">
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/column</item>
                </item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="align" xsi:type="string">left</item>
                    <item name="label" xsi:type="string" translate="true">Title</item>
                </item>
            </argument>
        </column>
        
        <column name="status">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">Sugarcode\Test\Model\Status</item>
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/select</item>
                </item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">select</item>
                    <item name="align" xsi:type="string">left</item>
                    <item name="label" xsi:type="string" translate="true">Status</item>
                    <item name="sortOrder" xsi:type="number">3</item>
                </item>
                    <item name="sortOrder" xsi:type="number">3</item>
            </argument>
        </column>
       
        <column name="creation_at">
            <argument name="data" xsi:type="array">
                <item name="js_config" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Ui/js/grid/columns/date</item>
                </item>
                <item name="config" xsi:type="array">
                    <item name="dataType" xsi:type="string">date</item>
                    <item name="align" xsi:type="string">left</item>
                    <item name="label" xsi:type="string" translate="true">Created</item>
                    <item name="sortOrder" xsi:type="number">4</item>
                </item>
                    <item name="sortOrder" xsi:type="number">4</item>
            </argument>
        </column>
        <column name="actions" class="Sugarcode\Test\Ui\Component\Listing\Column\TestActions">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="draggable" xsi:type="boolean">false</item>
                    <item name="dataType" xsi:type="string">actions</item>
                    <item name="indexField" xsi:type="string">id</item>
                    <item name="align" xsi:type="string">left</item>
                    <item name="label" xsi:type="string" translate="true">Action</item>
                    <item name="data_type" xsi:type="string">actions</item>
                    <item name="filterable" xsi:type="boolean">false</item>
                    <item name="sortable" xsi:type="boolean">false</item>
                    <item name="sortOrder" xsi:type="number">5</item>
                </item>
                    <item name="sortOrder" xsi:type="number">5</item>
            </argument>
        </column>
    </columns>
</listing>

app\code\Sugarcode\Test\view\adminhtml\layout\test_lists_index.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
    <update handle="styles"/>
    <body>
        <referenceContainer name="content">
            <uiComponent name="test_lists_listing"/>
        </referenceContainer>
    </body>
</page>

i created data provider that is
app\code\Sugarcode\Test\Model\Test\DataProvider.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Sugarcode\Test\Model\Test;

use Sugarcode\Test\Model\Resource\Test\CollectionFactory;
use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface;
use Magento\Framework\View\Element\UiComponent\DataProvider\FilterPool;

/**
 * Class DataProvider
 */
class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
    /**
     * @var \Magento\Cms\Model\Resource\Block\Collection
     */
    protected $collection;

    /**
     * @var FilterPool
     */
    protected $filterPool;

    /**
     * @param string $name
     * @param string $primaryFieldName
     * @param string $requestFieldName
     * @param CollectionFactory $collectionFactory
     * @param FilterPool $filterPool
     * @param array $meta
     * @param array $data
     */
    public function __construct(
        $name,
        $primaryFieldName,
        $requestFieldName,
        CollectionFactory $collectionFactory,
        FilterPool $filterPool,
        array $meta = [],
        array $data = []
    ) {
        parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
        $this->collection = $collectionFactory->create();
        $this->filterPool = $filterPool;
    }

    /**
     * @return \Magento\Cms\Model\Resource\Block\Collection
     */
    protected function getCollection()
    {
        return $this->collection;
    }

    /**
     * @inheritdoc
     */
    public function addFilter($condition, $field = null, $type = 'regular')
    {
        $this->filterPool->registerNewFilter($condition, $field, $type);
    }

    /**
     * Get data
     *
     * @return array
     */
    public function getData()
    {
        $this->filterPool->applyFilters($this->collection);
        return $this->collection->toArray();
    }

    /**
     * Retrieve count of loaded items
     *
     * @return int
     */
    public function count()
    {
        $this->filterPool->applyFilters($this->collection);
        return $this->collection->count();
    }
    public function addFieldToSearchFilter($field, $condition = null)
    {
        $field = $this->_getMappedField($field);
        $this->_select->orWhere($this->_getConditionSql($field, $condition));
        return $this;
    }
}

my model collection is
app\code\Sugarcode\Test\Model\Resource\Test\Collection.php

<?php
namespace Sugarcode\Test\Model\Resource\Test;

class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
{
   
    protected function _construct()
    {
        $this->_init('Sugarcode\Test\Model\Test', 'Sugarcode\Test\Model\Resource\Test');
    }
    
    /**
     * @return \Magento\Cms\Model\Resource\Block\Collection
     */
    protected function _afterLoad()
    {
        $this->walk('afterLoad');
        parent::_afterLoad();
    }

    /**
     * @param string|array $field
     * @param string|int|array|null $condition
     * @return \Magento\Cms\Model\Resource\Block\Collection
     */
    public function addFieldToFilter($field, $condition = null)
    {
        
        return parent::addFieldToFilter($field, $condition);
    }

    

    /**
     * Returns pairs block_id - title
     *
     * @return array
     */
    public function toOptionArray()
    {
        return $this->_toOptionArray('id', 'title');
    }

    /**
 

    /**
     * Get SQL for get record count.
     * Extra GROUP BY strip added.
     *
     * @return \Magento\Framework\DB\Select
     */
    public function getSelectCountSql()
    {
        $countSelect = parent::getSelectCountSql();

        $countSelect->reset(\Zend_Db_Select::GROUP);

        return $countSelect;
    }
    
    public function addFieldToSearchFilter($field, $condition = null)
    {
        $field = $this->_getMappedField($field);
        $this->_select->orWhere($this->_getConditionSql($field, $condition));
        return $this;
    }
    
}

Every thing is working fine except full search or common search
Do any one has any idea ?

Best Answer

To enable fulltext search for custom grid you need to create fulltext index in your grid table. fulltext filter scans indexes list and builds query with fulltext condition only if index exists.

See example, how fulltext filter works, for Merchant Beta, Mainline