---
title: Custom Entity Types
slug: klevu-magento-v4/custom-entity-types
docTags: 
createdAt: 2024-08-06T17:16:22.810Z
---

## 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`&#x20;
e.g.

:::CodeblockTabs
Vendor/Module/etc/di.xml

```xml
<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.

:::CodeblockTabs
Vendor/Module/etc/di.xml

```xml
<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`

```php
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.

:::CodeblockTabs
Vendor/Module/etc/di.xml

```xml
<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`.

:::hint{type="info"}
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`.&#x20;
Repeat this step for `Delete` and `Update`

:::CodeblockTabs
Vendor/Module/etc/di.xml

```xml
<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.&#x20;
Repeat this step for `Delete` and `Update` actions

:::CodeblockTabs
Vendor/Module/etc/di.xml

```xml
<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.

:::CodeblockTabs
Vendor/Module/etc/di.xml

```xml
<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`

:::CodeblockTabs
php

```php
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](https://app.archbee.com/public/PREVIEW-8cIJaE_9UAmWKNnQcRcUb/PREVIEW-1ftUqiDYJF1lFcslr73EX).

