yaroslavbr
9/22/2016 - 2:12 PM

IndexDataProvider.php

<?php

namespace Oro\Bundle\WebsiteSearchBundle\Provider;

use Doctrine\ORM\QueryBuilder;

use Oro\Bundle\EntityBundle\ORM\EntityAliasResolver;
use Oro\Bundle\WebsiteSearchBundle\Engine\AbstractIndexer;
use Oro\Bundle\WebsiteSearchBundle\Event\CollectContextEvent;
use Oro\Bundle\WebsiteSearchBundle\Event\IndexEntityEvent;
use Oro\Bundle\WebsiteSearchBundle\Event\RestrictIndexEntityEvent;
use Oro\Bundle\SearchBundle\Query\Query;
use Oro\Bundle\WebsiteSearchBundle\Helper\FieldHelper;
use Oro\Bundle\WebsiteSearchBundle\Placeholder\ChainReplacePlaceholder;

use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

/**
 * Class corresponds for triggering all events during indexation
 * and returning all collected event data
 */
class IndexDataProvider
{
    const ALL_TEXT_FIELD = 'all_text';
    const LOCALIZED_VALUES_KEY = 'localized_values_key';
    const STANDARD_VALUES_KEY = 'standard_values_key';

    /** @var EventDispatcherInterface */
    private $eventDispatcher;

    /** @var EntityAliasResolver */
    private $entityAliasResolver;

    /** @var ChainReplacePlaceholder */
    private $chainReplacePlaceholder;

    /** @var FieldHelper */
    private $fieldHelper;

    /** @var WebsiteSearchMappingProvider */
    private $mappingProvider;

    /** @var array */
    private $preparedIndexData = [];

    /**
     * @param EventDispatcherInterface $eventDispatcher
     * @param EntityAliasResolver $entityAliasResolver
     * @param ChainReplacePlaceholder $chainReplacePlaceholder
     * @param FieldHelper $fieldHelper
     * @param WebsiteSearchMappingProvider $mappingProvider
     */
    public function __construct(
        EventDispatcherInterface $eventDispatcher,
        EntityAliasResolver $entityAliasResolver,
        ChainReplacePlaceholder $chainReplacePlaceholder,
        FieldHelper $fieldHelper,
        WebsiteSearchMappingProvider $mappingProvider
    ) {
        $this->eventDispatcher = $eventDispatcher;
        $this->entityAliasResolver = $entityAliasResolver;
        $this->chainReplacePlaceholder = $chainReplacePlaceholder;
        $this->fieldHelper = $fieldHelper;
        $this->mappingProvider = $mappingProvider;
    }

    /**
     * @param int $websiteId
     * @param array $context
     * @return array
     */
    public function collectContextForWebsite($websiteId, array $context)
    {
        $context[AbstractIndexer::CONTEXT_WEBSITE_ID_KEY] = $websiteId;
        $collectContextEvent = new CollectContextEvent($context);
        $this->eventDispatcher->dispatch(CollectContextEvent::NAME, $collectContextEvent);

        return $collectContextEvent->getContext();
    }

    /**
     * @param string $entityClass
     * @param object[] $restrictedEntities
     * @param array $context
     * @return array
     */
    public function getEntitiesData($entityClass, array $restrictedEntities, array $context)
    {
        $indexEntityEvent = new IndexEntityEvent($entityClass, $restrictedEntities, $context);
        $this->eventDispatcher->dispatch(IndexEntityEvent::NAME, $indexEntityEvent);

        return $this->prepareIndexData($indexEntityEvent->getEntitiesData(), $entityClass);
    }

    /**
     * Adds mappings to the fields according to config
     * @param array $indexData
     * @param string $entityClass
     * @return array
     */
    private function prepareIndexData(array $indexData, $entityClass)
    {
        $mappingConfig = $this->mappingProvider->getEntityConfig($entityClass);
        $fieldsConfig = $mappingConfig['fields'];

        $this->preparedIndexData = [];
        //Fetch localized fields
        foreach ($indexData as $entityId => $fieldsCategories) {
            if (isset($fieldsCategories[self::STANDARD_VALUES_KEY])) {
                $this->processStandardValues(
                    $entityId,
                    $fieldsCategories[self::STANDARD_VALUES_KEY],
                    $fieldsConfig
                );
            }
            if (isset($fieldsCategories[self::LOCALIZED_VALUES_KEY])) {
                $this->processLocalizedValues(
                    $entityId,
                    $fieldsCategories[self::LOCALIZED_VALUES_KEY],
                    $fieldsConfig
                );
            }
            if (isset($fieldsCategories[self::ALL_TEXT_FIELD])) {
            }
            /*if ($fieldCategoryKey === self::LOCALIZED_VALUES_KEY) {
                foreach ($fieldValue as $localizedFieldName => $localizadVieldValue) {
                    $fieldConfig = $this->getFieldConfig($fieldsConfig, $localizedFieldName);
                }
            } elseif ($fieldCategoryKey === self::ALL_TEXT_FIELD) {
            } elseif() {

            }*/
        }
    }

    /**
     * @param $entityId
     * @param $fieldsData
     * @param $fieldsConfig
     */
    private function processStandardValues($entityId, $fieldsData, $fieldsConfig)
    {
        foreach ($fieldsData as $field => $value) {
            $fieldConfig = $this->getFieldConfig($fieldsConfig, $field);
            $type = $fieldConfig['type'];
            $this->preparedIndexData[$entityId][$type][$field] = $this->clearTextValue($type, $value);
        }
    }

    /**
     * @param $entityId
     * @param $fieldsData
     * @param $fieldsConfig
     */
    private function processLocalizedValues($entityId, $fieldsData, $fieldsConfig)
    {
        foreach ($fieldsData as $field => $localizedValues) {
            foreach ($localizedValues as $localeId => $value) {
                $fieldConfig = $this->getFieldConfig($fieldsConfig, $field);
                $type = $fieldConfig['type'];
                $field = $this->chainReplacePlaceholder->replace($fieldConfig['name'], $localeId);
                $this->preparedIndexData[$entityId][$type][$field] = $this->clearTextValue($type, $value);
            }
        }
    }

    /**
     * @param array $fieldsConfig
     * @param string $fieldName
     * @return array
     */
    private function getFieldConfig(array $fieldsConfig, $fieldName)
    {
        if (!isset($fieldsConfig[$fieldName])) {
            throw new InvalidConfigurationException(
                'You try to index field in listener which is not added to mapping - ' . $fieldName
            );
        }

        return $fieldsConfig[$fieldName];
    }

    /**
     * Checks if value is text type and applies stripping tags
     * @param string $type
     * @param string $value
     * @return string
     */
    private function clearTextValue($type, $value)
    {
        if ($type === Query::TYPE_TEXT) {
            $value = $this->fieldHelper->stripTagsAndSpaces($value);
        }

        return $value;
    }

    /**
     * @param $entityClass
     * @param $queryBuilder
     * @param $context
     * @return QueryBuilder
     */
    public function getRestrictedEntitiesQueryBuilder($entityClass, $queryBuilder, $context)
    {
        $entityAlias = $this->entityAliasResolver->getAlias($entityClass);

        $restrictEntitiesEvent = new RestrictIndexEntityEvent($queryBuilder, $context);
        $this->eventDispatcher->dispatch(RestrictIndexEntityEvent::NAME, $restrictEntitiesEvent);
        $this->eventDispatcher->dispatch(
            sprintf('%s.%s', RestrictIndexEntityEvent::NAME, $entityAlias),
            $restrictEntitiesEvent
        );

        return $restrictEntitiesEvent->getQueryBuilder();
    }
}