Add custom indexing entity
In this article we'll create a new custom News indexing entity step-by-step. Please note, that the same approach can be applied for developing any similar indexing entity, i.e. Articles, Categories, Blog posts, etc. After completing this, you'll find your new entity added to Hawkseaarch data indexing process.
Create module skeleton
In our example we will be using a module name HawkSearch_NewsEntityExample
. Start with creating a new Magento module in app/code/HawkSearch/NewsEntityExample
folder. Magento requires only two files for any module to be registered: registration.php
and etc/module.xml
.
We pushed the entire module package to GitHub repository. Feel free to install it and update on your own needs.
Register indexer for incremental delta updates
Register new Magento indexer in etc/indexer.xml
:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Indexer/etc/indexer.xsd">
<indexer id="hawksearch_news" view_id="hawksearch_news"
class="HawkSearch\NewsEntityExample\Model\Indexer\News" shared_index="hawksearch_entities_shared">
<title translate="true">Hawksearch News</title>
<description translate="true">
Rebuild news Hawksearch index
</description>
<dependencies>
<indexer id="hawksearch_entities" />
</dependencies>
</indexer>
</config>
and allow delta indexing updates for News entity by adding mview in etc/mview.xml
:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Mview/etc/mview.xsd">
<view id="hawksearch_news" class="HawkSearch\NewsEntityExample\Model\Indexer\News" group="indexer">
<!-- Add table subscriptions here to get delta indexing working -->
<!-- Don't forget to plugin news entity CRUD operations to get indexer working in "Update on Save" mode -->
<!--<subscriptions>
<table name="news" entity_column="news_id" />
</subscriptions>-->
</view>
</config>
Create indexer class \HawkSearch\NewsEntityExample\Model\Indexer\News
:
<?php
declare(strict_types=1);
namespace HawkSearch\NewsEntityExample\Model\Indexer;
use HawkSearch\EsIndexing\Model\Indexer\Entities as EntitiesIndexer;
use HawkSearch\EsIndexing\Model\Indexer\Entities\ActionAbstract as Action;
use Magento\Framework\Indexer\ActionInterface as IndexerActionInterface;
use Magento\Framework\Mview\ActionInterface as MviewActionInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
class News implements IndexerActionInterface, MviewActionInterface
{
/**
* Indexer ID in configuration
*/
const INDEXER_ID = 'hawksearch_news';
/**
* @var Action
*/
private Action $action;
/**
* @var ConsoleOutput
*/
private ConsoleOutput $output;
/**
* @param Action $action
* @param ConsoleOutput $output
*/
public function __construct(
Action $action,
ConsoleOutput $output
) {
$this->action = $action;
$this->output = $output;
}
/**
* This indexer is not designed to run full reindex
*
* @see Entities
* @inheritDoc
*/
public function executeFull()
{
$this->output->writeln(
sprintf(
'<comment>Indexer `%s` can\'t be run for full reindexing. Please run `%s` indexer instead.</comment>',
self::INDEXER_ID,
EntitiesIndexer::INDEXER_ID
)
);
}
/**
* @inheritdoc
*/
public function executeList(array $ids)
{
$this->execute($ids);
}
/**
* @inheritdoc
*/
public function executeRow($id)
{
$this->execute([$id]);
}
/**
* @inheritdoc
*/
public function execute($ids)
{
$this->action->execute($ids);
}
}
Define indexer action in etc/di.xml
:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="HawkSearch\NewsEntityExample\Model\Indexer\News">
<arguments>
<argument name="action" xsi:type="object">HawkSearch\NewsEntityExample\Model\Indexer\Entities\ActionEntityNews</argument>
</arguments>
</type>
<virtualType name="HawkSearch\NewsEntityExample\Model\Indexer\Entities\ActionEntityNews"
type="HawkSearch\EsIndexing\Model\Indexer\Entities\ActionEntityDefault">
<arguments>
<argument name="entityScheduler" xsi:type="object">HawkSearch\NewsEntityExample\Model\Indexer\Entities\Scheduler\News</argument>
</arguments>
</virtualType>
<virtualType name="HawkSearch\NewsEntityExample\Model\Indexer\Entities\Scheduler\News"
type="HawkSearch\EsIndexing\Model\Indexer\Entities\SchedulerAbstract">
<arguments>
<argument name="entityType" xsi:type="object">HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsEntityType</argument>
</arguments>
</virtualType>
</config>
Please note, that we've referenced \HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsEntityType
class which we'll setup in the next step.
NewsEntityType
\HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsEntityType
class injects a bunch of arguments which have to be specified in etc/di.xml
file:
<type name="HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsEntityType">
<arguments>
<argument name="rebuilder" xsi:type="object">HawkSearch\NewsEntityExample\Model\Indexing\Entity\News\EntityRebuild\Proxy</argument>
<argument name="itemsDataProvider" xsi:type="object">HawkSearch\NewsEntityExample\Model\Indexing\Entity\News\ItemsDataProvider</argument>
<argument name="attributeHandler" xsi:type="object">HawkSearch\NewsEntityExample\Model\News\Attribute\Handler\Composite</argument>
<argument name="configHelper" xsi:type="object">HawkSearch\NewsEntityExample\Model\Indexing\Entity\News\ConfigHelper</argument>
<argument name="itemsIndexer" xsi:type="object">HawkSearch\EsIndexing\Model\Indexing\ItemsIndexer\SearchedItemsIndexer</argument>
<argument name="typeName" xsi:type="const">HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsEntityType::ENTITY_TYPE_NAME</argument>
</arguments>
</type>
<type name="HawkSearch\NewsEntityExample\Model\Indexing\Entity\News\EntityRebuild\Proxy">
<arguments>
<argument name="shared" xsi:type="boolean">false</argument>
</arguments>
</type>
rebuilder argument
rebuilder
is exposed to queue message consumer handler and can be found in message body. This is the main translator between Magento entity and Hawksearch index. The rebuilder
class should implement \HawkSearch\EsIndexing\Model\Indexing\EntityRebuildInterface
through extending abstract class \HawkSearch\EsIndexing\Model\Indexing\AbstractEntityRebuild
which contains all the core logic. Lets implement our \HawkSearch\NewsEntityExample\Model\Indexing\Entity\News\EntityRebuild
class. It should be updated further to follow required needs.
<?php
declare(strict_types=1);
namespace HawkSearch\NewsEntityExample\Model\Indexing\Entity\News;
use HawkSearch\EsIndexing\Model\Indexing\AbstractEntityRebuild;
use Magento\Framework\DataObject;
class EntityRebuild extends AbstractEntityRebuild
{
/**
* @inheritDoc
*/
protected function isAllowedItem(DataObject $item): bool
{
return true;
}
/**
* @inheritDoc
*/
protected function getEntityId(DataObject $entityItem): ?int
{
return (int)$entityItem->getNewsId();
}
/**
* @inheritDoc
*/
protected function getIndexedAttributes(DataObject $item = null): array
{
return [];
}
}
attributeHandler argument
attributeHandler
class extends a composite handler class what allows to define an array of attribute handlers. If handler is not defined then attribute raw data will be used for getting values from entity table. attributeHandler
should implement \HawkSearch\EsIndexing\Model\Indexing\AttributeHandlerInterface
. For example, you can define the url
attribute handler and use a special handler class for building complex values.
<virtualType name="HawkSearch\NewsEntityExample\Model\News\Attribute\Handler\Composite"
type="HawkSearch\EsIndexing\Model\Indexing\AttributeHandler\Composite">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="url" xsi:type="array">
<item name="attribute" xsi:type="string">url</item>
<item name="class" xsi:type="string">HawkSearch\NewsEntityExample\Model\News\Attribute\Handler\Url</item>
</item>
</argument>
</arguments>
</virtualType>
configHelper argument
This is an utility class which allows to change indexing configuration parameter on Entity level. It is expected to be an instance of \HawkSearch\EsIndexing\Model\Indexing\AbstractConfigHelper
.
itemsIndexer argument
For any entities, which are going to be a part of Hawksearch items index, which is updated with the help of Indexing API, it is expected that itemsIndexer
is an instance of \HawkSearch\EsIndexing\Model\Indexing\ItemsIndexer\SearchedItemsIndexer
class. For non Indexing API implementation use custom API indexers, i.e. Hierarchy and Landing Page indexers
itemsDataProvider argument
itemsDataProvider
class loads data from entity source. Create class \HawkSearch\NewsEntityExample\Model\Indexing\Entity\News\ItemsDataProvider
and extend getItems()
method.
<?php
declare(strict_types=1);
namespace HawkSearch\NewsEntityExample\Model\Indexing\Entity\News;
use HawkSearch\EsIndexing\Model\Indexing\ItemsDataProviderInterface;
class ItemsDataProvider implements ItemsDataProviderInterface
{
public function getItems(int $storeId, $entityIds = null, $currentPage = 1, $pageSize = 0)
{
return [];
}
}
Any entity attributes which are going to be pushed to Hawksearch index should be defined in \HawkSearch\NewsEntityExample\Model\Indexing\Entity\News\EntityRebuild::getIndexedAttributes()
method. Make sure to create corresponding fields in Hawksearch Workbench.
Register NewsEntityType for full indexer and queue publisher
There is a hawksearch_entities
Magento indexer which is used to trigger full data re-indexing in Hawksearch indices. We need to register our custom NewsEntityType
for this indexer. Modify etc/di.xml
with the following content:
<virtualType name="HawkSearch\EsIndexing\Model\Indexer\Entities\Scheduler\All">
<arguments>
<argument name="schedulers" xsi:type="array">
<item name="news" xsi:type="string">HawkSearch\NewsEntityExample\Model\Indexer\Entities\Scheduler\News</item>
</argument>
</arguments>
</virtualType>
<type name="HawkSearch\EsIndexing\Model\Indexing\EntityTypePool">
<arguments>
<argument name="types" xsi:type="array">
<item name="news" xsi:type="string">HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsEntityType</item>
</argument>
</arguments>
</type>
<virtualType name="HawkSearch\EsIndexing\Model\MessageQueue\MessageTopicByEntityTypeResolver">
<arguments>
<argument name="resolvers" xsi:type="array">
<item name="news" xsi:type="object">HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsMessageTopicResolver</item>
</argument>
</arguments>
</virtualType>
<virtualType name="HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsMessageTopicResolver"
type="HawkSearch\EsIndexing\Model\MessageQueue\MessageTopicByObjectResolver">
<arguments>
<argument name="topic" xsi:type="string">hawksearch.indexing.news.reindex</argument>
<argument name="resolverClass" xsi:type="string">HawkSearch\NewsEntityExample\Model\Indexing\EntityType\NewsEntityType</argument>
</arguments>
</virtualType>
The message queue topology files should be updated to understand hawksearch.indexing.news.reindex
message topic: communication.xml
, queue_topology.xml
and queue_publisher.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd">
<topic name="hawksearch.indexing.news.reindex"
request="HawkSearch\EsIndexing\Api\Data\QueueOperationDataInterface[]">
</topic>
</config>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd">
<exchange name="magento-db" type="topic" connection="db">
<binding id="NewsBinding"
topic="hawksearch.indexing.news.reindex"
destinationType="queue"
destination="hawksearch.indexing"/>
</exchange>
</config>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd">
<publisher topic="hawksearch.indexing.news.reindex">
<connection name="db" exchange="magento-db" />
</publisher>
</config>
Updated 10 months ago