Custom Entity Types
Entity Discovery
In order to sync any entities first we have to discover them. In order to discover entites for a new entity type we must inject an EntityDiscoveryProvider into the EntityDiscoveryOrchestratorService e.g.
<type name="Klevu\Indexing\Service\EntityDiscoveryOrchestratorService">
<arguments>
<argument name="discoveryProviders" xsi:type="array">
<item name="custom_types"
xsi:type="object">Vendor\Module\Service\Provider\EntityDiscoveryProvider</item>
</argument>
</arguments>
</type>
That CustomTypeEntityDiscoveryProvider will be a virtual type of Klevu\Indexing\Service\Provider\EntityDiscoveryProvider e.g.
<virtualType name="Vendor\Module\Service\Provider\EntityDiscoveryProvider"
type="Klevu\Indexing\Service\Provider\EntityDiscoveryProvider">
<arguments>
<argument name="entityType" xsi:type="string">CUSTOM_TYPE</argument>
<argument name="entityProviders" xsi:type="array">
<item name="custom_type"
xsi:type="object">Vendor\Module\Service\Provider\CustomTypeEntityProvider</item>
</argument>
<argument name="isIndexableDeterminer"
xsi:type="object">Vendor\Module\Service\Determiner\IsIndexableDeterminer</argument>
</arguments>
</virtualType>
Create the CustomTypeEntityProvider which must implement Klevu\IndexingApi\Service\Provider\EntityProviderInterface
class CustomTypeEntityProvider implements EntityProviderInterface
{
public function get(?StoreInterface $store = null, ?array $entityIds = []): ?\Generator
{
$customEntityCollection = $this->getCollection(store: $store, entityIds: $entityIds);
foreach ($customEntityCollection as $customEntity) {
yield $customEntity;
}
}
private function getCollection(?StoreInterface $store, ?array $entityIds): CategoryCollection
{
$customEntityCollection = $this->customEntityCollectionFactory->create();
if ($store) {
$customEntityCollection->setStore(store: (int)$store->getId());
}
if ($entityIds) {
$customEntityCollection->addFieldToFilter(
Entity::DEFAULT_ENTITY_ID_FIELD,
['in' => implode(',', $entityIds)],
);
}
return $customEntityCollection;
}
}
Entity Sync
After discovering the entities, we need to sync them with Klevu by injecting EntityIndexerService services into the EntitySyncOrchestratorService. We inject a separate service for each action, i.e. Add, Delete and Update e.g.
<type name="Klevu\Indexing\Service\EntitySyncOrchestratorService">
<arguments>
<argument name="entityIndexerServices" xsi:type="array">
<item name="CUSTOM_TYPE" xsi:type="array">
<item name="add"
xsi:type="object">Vendor\Module\Service\EntityIndexerService\Add</item>
<item name="delete"
xsi:type="object">Vendor\Module\Service\EntityIndexerService\Delete</item>
<item name="update"
xsi:type="object">Vendor\Module\Service\EntityIndexerService\Update</item>
</item>
</argument>
</arguments>
</type>
Now create each of the injected EntityIndexerService.
You can create your own service classes that implement \Klevu\IndexingApi\Service\EntityIndexerServiceInterface and handle indexing the data with Klevu. If you choose this route please refer to the Klevu PHP-SDK documentation.
If you wish to use Klevu pipelines to index data with Klevu please continue following the example below.
Create a virtual type of Klevu\Indexing\Service\EntityIndexerService. Repeat this step for Delete and Update
<virtualType name="Vendor\Module\Service\EntityIndexerService\Add"
type="Klevu\Indexing\Service\EntityIndexerService">
<arguments>
<argument name="entityIndexingRecordProvider"
xsi:type="object">Vendor\Module\Service\Provider\Sync\EntityIndexingRecordProvider\Add</argument>
<argument name="pipelineConfigurationFilepath"
xsi:type="string">Vendor_Module::etc/pipeline/add_update.yml</argument>
</arguments>
</virtualType>
<!-- Repeat for Delete and Update -->Create a virtualType of Vendor\Module\Service\Provider\Sync\EntityIndexingRecordProvider (which doesn't exist yet) to set the action to be performed. Repeat this step for Delete and Update actions
<virtualType name="Vendor\Module\Service\Provider\Sync\EntityIndexingRecordProvider\Add"
type="Vendor\Module\Service\Provider\Sync\EntityIndexingRecordProvider">
<arguments>
<argument name="action" xsi:type="string">Add</argument>
</arguments>
</virtualType>
<!-- Repeat for Delete and Update -->
Now create the missing Vendor\Module\Service\Provider\Sync\EntityIndexingRecordProvider mentioned in the previous step. This is a virtual type of Klevu\Indexing\Service\Provider\Sync\EntityIndexingRecordProvider. Pass in the same entityProvider we created during the Entity Discover section above.
<virtualType name="Vendor\Module\Service\Provider\Sync\EntityIndexingRecordProvider"
type="Klevu\Indexing\Service\Provider\Sync\EntityIndexingRecordProvider">
<arguments>
<argument name="entityProviders" xsi:type="array">
<!-- ALREADY CREATED IN DISCOVERY SECTION ABOVE -->
<item name="custom_type"
xsi:type="object">Vendor\Module\Service\Provider\CustomTypeEntityProvider</item>
</argument>
<argument name="indexingRecordCreatorService"
xsi:type="object">Vendor\Module\Service\EntityIndexingRecordCreatorService</argument>
<argument name="entityType" xsi:type="string">CUSTOM_TYPE</argument>
</arguments>
</virtualType>Create Vendor\Module\Service\EntityIndexingRecordCreatorService which implements Klevu\IndexingApi\Service\EntityIndexingRecordCreatorServiceInterface
class EntityIndexingRecordCreatorService implements EntityIndexingRecordCreatorServiceInterface
{
public function execute(
int $recordId,
Actions $action,
PageInterface|ExtensibleDataInterface $entity,
PageInterface|ExtensibleDataInterface|null $parent = null,
): EntityIndexingRecordInterface {
return $this->entityIndexingRecordFactory->create([
'recordId' => $recordId,
'entity' => $entity,
'parent' => $parent, // this is used when indexing configurable variants. If the entity has no parent set this to null.
'action' => $action,
]);
}
}
Final step is to create the pipeline YAML file to process that data before it is sent to Klevu. Vendor_Module::etc/pipeline/add_update.yml. See Pipelines.