<?php
namespace Intedia\Doofinder\Doofinder\Api;
use GuzzleHttp\Client;
use Psr\Log\LoggerInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Contracts\Translation\TranslatorInterface;
class Search
{
const API_VERSION = '5';
const CLIENT_TIMEOUT = 2.5; // seconds
const CONFIG_KEY = 'IntediaDoofinderSW6.config.';
const MAX_RESULTS = 1500;
const PAGE_SIZE = 100;
/** @var SystemConfigService */
protected $systemConfigService;
/** @var TranslatorInterface */
protected $translator;
/** @var LoggerInterface */
protected $logger;
/** @var Client */
protected $client;
/** @var string */
protected $baseUrl;
/** @var string */
protected $engineHash;
/** @var string */
protected $apiKey;
/** @var string */
protected $apiZone;
/**
* Search constructor.
*
* @param SystemConfigService $systemConfigService
* @param TranslatorInterface $translator
* @param LoggerInterface $logger
*/
public function __construct(SystemConfigService $systemConfigService, TranslatorInterface $translator, LoggerInterface $logger)
{
$this->logger = $logger;
$this->translator = $translator;
$this->systemConfigService = $systemConfigService;
if ($this->initConfig()) {
$this->client = new Client([
'base_uri' => $this->baseUrl,
'timeout' => self::CLIENT_TIMEOUT
]);
}
}
/**
* Initializes api with config values
* @param SalesChannelContext|null $context
* @return bool
*/
protected function initConfig(?SalesChannelContext $context = null): bool
{
$translationHash = $this->translator->trans("intedia-doofinder.configuration.hashId") !== "intedia-doofinder.configuration.hashId" ? $this->translator->trans("intedia-doofinder.configuration.hashId") : null;
$pluginConfig = $this->systemConfigService->getDomain(self::CONFIG_KEY, $context ? $context->getSalesChannel()->getId() : null, true);
if (!empty($pluginConfig[self::CONFIG_KEY . 'apiKey']) && (!empty($pluginConfig[self::CONFIG_KEY . 'engineHashId']) || !empty($translationHash)) && !empty($pluginConfig[self::CONFIG_KEY . 'searchDomain'])) {
$apiInfo = explode('-', $pluginConfig[self::CONFIG_KEY . 'apiKey']);
if (count($apiInfo) != 2) {
return false;
}
$this->apiKey = $apiInfo[1];
$this->apiZone = $apiInfo[0];
$this->engineHash = $translationHash ? $translationHash : $pluginConfig[self::CONFIG_KEY . 'engineHashId'];
$this->baseUrl = sprintf("https://{$pluginConfig[self::CONFIG_KEY . 'searchDomain']}/%s/", $this->apiZone,self::API_VERSION);
return true;
}
return false;
}
/**
* @param SalesChannelContext|null $context
* @return Client
*/
protected function generateClient(?SalesChannelContext $context = null)
{
if ($this->initConfig($context)) {
$this->client = new Client([
'base_uri' => $this->baseUrl,
'timeout' => self::CLIENT_TIMEOUT
]);
}
return $this->client;
}
/**
* @param $term
* @param SalesChannelContext|null $context
* @return array
*/
public function queryIds($term, ?SalesChannelContext $context = null)
{
if ($context) {
$this->generateClient($context);
}
$resultIds = [];
$page = 1;
$dfResponse = $this->queryPage($term, $page, self::PAGE_SIZE);
$productsToLoad = self::MAX_RESULTS;
while ($dfResponse) {
$dfResults = $dfResponse['results'];
for ($i = 0; $i < count($dfResults) && ($productsToLoad > 0); $i++, --$productsToLoad) {
if (array_key_exists('group_id', $dfResults[$i])) {
$resultIds[$dfResults[$i]['group_id']] = $dfResults[$i]['id'];
}
else {
$resultIds[] = $dfResults[$i]['id'];
}
}
$dfResponse = $page * self::PAGE_SIZE < $dfResponse['total'] && $productsToLoad > 0 ? $this->queryPage($term, ++$page, self::PAGE_SIZE) : null;
}
return $resultIds;
}
/**
* @param $term
* @param $page
* @param $rpp
* @return mixed|null
*/
protected function queryPage($term, $page, $rpp)
{
try {
if ($this->client) {
$response = $this->client->request('GET', 'search',
[
'query' => [
'hashid' => $this->engineHash,
'query' => $term,
'page' => $page,
'rpp' => $rpp
],
'headers' => [
'Authorization' => 'Token ' . $this->apiKey
]
]
);
if ($response->getStatusCode() === 200) {
return \GuzzleHttp\json_decode($response->getBody(), true);
}
}
}
catch (\Exception $e) {
$this->logger->error("Exception receiving results from doofinder: " . $e->getMessage());
}
return null;
}
}