<commit_before><?php

namespace Oro\Bundle\SearchBundle\Engine;

use Oro\Component\MessageQueue\Client\MessageProducerInterface;

class AsyncIndexer implements IndexerInterface
{
    const TOPIC_SAVE = 'oro.website.search.indexer.save';
    const TOPIC_DELETE = 'oro.website.search.indexer.delete';
    const TOPIC_RESET_INDEX = 'oro.website.search.indexer.reset_index';
    const TOPIC_REINDEX = 'oro.website.search.indexer.reindex';

    /**
     * @var IndexerInterface
     */
    private $baseIndexer;

    /**
     * @var MessageProducerInterface
     */
    private $messageProducer;

    /**
     * @param IndexerInterface $baseIndexer
     * @param MessageProducerInterface $messageProducer
     */
    public function __construct(IndexerInterface $baseIndexer, MessageProducerInterface $messageProducer)
    {
        $this->baseIndexer = $baseIndexer;
        $this->messageProducer = $messageProducer;
    }

    /**
     * @inheritdoc
     */
    public function save($entity, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_SAVE,
            [
                'entity' => $this->getOneOrManyEntitiesScalarRepresentation($entity),
                'context' => $context
            ]
        );
    }

    /**
     * @inheritdoc
     */
    public function delete($entity, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_DELETE,
            [
                'entity' => $this->getOneOrManyEntitiesScalarRepresentation($entity),
                'context' => $context
            ]
        );
    }

    /**
     * @inheritdoc
     */
    public function getClassesForReindex($class = null, $context = [])
    {
        return $this->baseIndexer->getClassesForReindex($class, $context);
    }

    /**
     * @inheritdoc
     */
    public function resetIndex($class = null, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_RESET_INDEX,
            [
                'class' => $class,
                'context' => $context
            ]
        );
    }

    /**
     * @inheritdoc
     */
    public function reindex($class = null, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_REINDEX,
            [
                'class' => $class,
                'context' => $context
            ]
        );
    }

    /**
     * Send a message to a que using message producer
     *
     * @param $topic
     * @param array $data
     */
    private function sendAsyncIndexerMessage($topic, array $data)
    {
        $this->messageProducer->send(
            $topic,
            $data
        );
    }

    /**
     * @param object|object[] $entity
     * @return array
     */
    private function getOneOrManyEntitiesScalarRepresentation($entity)
    {
        if (is_array($entity)) {
            $result = [];

            foreach ($entity as $entityEntry)  {
                $result[] = $this->getEntityScalarRepresentation($entityEntry);
            }

            return $result;
        }

        return $this->getEntityScalarRepresentation($entity);
    }

    /**
     * Parse entity and get the Id and class name from it, to send in the que message.
     *
     * @param object $entity
     * @return array
     * @throws \RuntimeException
     */
    private function getEntityScalarRepresentation($entity)
    {
        if (is_object($entity) && method_exists($entity, 'getId')) {
            return [
                'class' => get_class($entity),
                'id' => $entity->getId()
            ];
        }

        throw new \RuntimeException('Id can not be found in the given entity.');
    }
}
<commit_msg>BB-4185: Create async indexer to schedule index operations - fixes after review<commit_after><?php

namespace Oro\Bundle\SearchBundle\Engine;

use Oro\Component\MessageQueue\Client\MessageProducerInterface;

class AsyncIndexer implements IndexerInterface
{
    const TOPIC_SAVE = 'oro.website.search.indexer.save';
    const TOPIC_DELETE = 'oro.website.search.indexer.delete';
    const TOPIC_RESET_INDEX = 'oro.website.search.indexer.reset_index';
    const TOPIC_REINDEX = 'oro.website.search.indexer.reindex';

    /**
     * @var IndexerInterface
     */
    private $baseIndexer;

    /**
     * @var MessageProducerInterface
     */
    private $messageProducer;

    /**
     * @param IndexerInterface $baseIndexer
     * @param MessageProducerInterface $messageProducer
     */
    public function __construct(IndexerInterface $baseIndexer, MessageProducerInterface $messageProducer)
    {
        $this->baseIndexer = $baseIndexer;
        $this->messageProducer = $messageProducer;
    }

    /**
     * @inheritdoc
     */
    public function save($entity, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_SAVE,
            [
                'entity' => $this->getEntityData($entity),
                'context' => $context
            ]
        );
    }

    /**
     * @inheritdoc
     */
    public function delete($entity, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_DELETE,
            [
                'entity' => $this->getEntityData($entity),
                'context' => $context
            ]
        );
    }

    /**
     * @inheritdoc
     */
    public function getClassesForReindex($class = null, $context = [])
    {
        return $this->baseIndexer->getClassesForReindex($class, $context);
    }

    /**
     * @inheritdoc
     */
    public function resetIndex($class = null, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_RESET_INDEX,
            [
                'class' => $class,
                'context' => $context
            ]
        );
    }

    /**
     * @inheritdoc
     */
    public function reindex($class = null, $context = [])
    {
        $this->sendAsyncIndexerMessage(
            self::TOPIC_REINDEX,
            [
                'class' => $class,
                'context' => $context
            ]
        );
    }

    /**
     * Send a message to a que using message producer
     *
     * @param $topic
     * @param array $data
     */
    private function sendAsyncIndexerMessage($topic, array $data)
    {
        $this->messageProducer->send(
            $topic,
            $data
        );
    }

    /**
     * @param object|object[] $entity
     * @return array
     */
    private function getEntityData($entity)
    {
        if (is_array($entity)) {
            $result = [];

            foreach ($entity as $entityEntry)  {
                $result[] = $this->getEntityScalarRepresentation($entityEntry);
            }

            return $result;
        }

        return $this->getEntityScalarRepresentation($entity);
    }

    /**
     * Parse entity and get the Id and class name from it, to send in the que message.
     *
     * @param object $entity
     * @return array
     * @throws \RuntimeException
     */
    private function getEntityScalarRepresentation($entity)
    {
        if (is_object($entity) && method_exists($entity, 'getId')) {
            return [
                'class' => get_class($entity),
                'id' => $entity->getId()
            ];
        }

        throw new \RuntimeException('Id can not be found in the given entity.');
    }
}

{'fraction_non_alphanumeric': 0.12110914775044175, 'fraction_numerical': 0.0005436998776675275, 'mean_word_length': 1.840926640926641, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6434248', 'n_tokens_mistral': 2103, 'n_tokens_neox': 2042, 'n_words': 390}