<?php
/**
* project: Pimcore - Schutzverband Nuernberg Rostbratwuerste
* User: erikb
* Year: 2022
*/
namespace Devkitchen\DocumentIndexingBundle\IndexingService;
use Devkitchen\DocumentIndexingBundle\DataExtractorService\DataExtractorService;
use Devkitchen\DocumentIndexingBundle\ElasticSearchService\ElasticSearchService;
use Devkitchen\DocumentIndexingBundle\Logger\LoggerInterface;
use Pimcore\Model\Document;
use Safe\Exceptions\JsonException;
use Symfony\Component\HttpFoundation\RequestStack;
class IndexingService {
/** @var bool */
protected bool $enabled;
/** @var LoggerInterface */
protected LoggerInterface $logger;
/** @var ElasticSearchService */
protected ElasticSearchService $elastic;
/** @var DataExtractorService */
protected DataExtractorService $extractor;
protected string $orderBy = 'documentIndex';
protected string $orderDirection = 'asc';
protected int $resultSize = 1000;
protected int $resultFrom = 0;
public function __construct(bool $enabled, ElasticSearchService $elasticSearch, DataExtractorService $extractor, LoggerInterface $logger) {
$this->enabled = $enabled;
$this->elastic = $elasticSearch;
$this->extractor = $extractor;
$this->logger = $logger;
}
/**
* @param string $documentIndexName
* @param mixed $language
*
* @return array
* @throws JsonException
*/
public function getDocumentTypes(string $documentIndexName = 'default', mixed $language = null) {
$query = [
'aggs' => [
'field_values' => [
'terms' => [
'field' => 'documentType',
'size' => 1000,
'order' => [
'_key' => 'asc'
]
]
]
]
];
$esQuery = [
'aggs' => $query['aggs'],
'size' => 0
];
$response = $this->elastic
->setLanguage( $language )
->setDocumentType( $documentIndexName )
->search( $esQuery );
$body = \Safe\json_decode( $response->getBody() );
if ( $response->getStatusCode() <= 200) {
if ($body->hits->total->value > 0) {
$aggregatedFieldValues = [];
foreach($body->aggregations->field_values->buckets as $bucket) {
$aggregatedFieldValues[] = $bucket;
}
return $aggregatedFieldValues;
}
}
return [];
}
/**
* @param string $filteredByDocumentType
* @param string $inField
* @param string $documentIndexName
* @param mixed $language
*
* @return array
* @throws JsonException
*/
public function getFieldAggregated(string $filteredByDocumentType, string $inField = 'documentSubtype', string $documentIndexName = 'default', mixed $language = null) : array {
if ( ! $this->enabled ) { return []; }
$query = [
'aggs' => [
'field_values' => [
'filter' => [
'term' => [
'documentType' => $filteredByDocumentType
]
],
'aggs' => [
'values' => [
'terms' => [
'field' => $inField,
'size' => 1000,
'order' => [
'_key' => 'asc'
],
]
]
]
]
]
];
$esQuery = [
'aggs' => $query['aggs'],
//post filter doesnt affect aggs -> only results
//'post_filter' => [
// 'term' => [
// 'documentType' => $filteredByDocumentType
// ]
//],
'size' => 0
];
//p_r($esQuery);
$response = $this->elastic
->setLanguage( $language )
->setDocumentType( $documentIndexName )
->search( $esQuery );
$body = \Safe\json_decode( $response->getBody() );
if ( $response->getStatusCode() <= 200) {
if ($body->hits->total->value > 0) {
$aggregatedFieldValues = [];
foreach($body->aggregations->field_values->values->buckets as $bucket) {
$aggregatedFieldValues[] = $bucket;
}
return $aggregatedFieldValues;
}
}
return [];
}
/**
* @param string $type
* @param array $subtypes
* @param string $documentIndexName
* @param mixed $language
*
* @return array|null
* @throws JsonException
*/
public function listing(string $type, array $subtypes = [], string $documentIndexName = 'default', string $language = null) : array | null {
if ( ! $this->enabled ) { return null; }
$query = [
'bool' => [
'must' => [
['term' => [ 'documentType' => $type]],
['term' => [ 'published' => true]]
]
]
];
if (count( $subtypes ) > 0) {
foreach($subtypes as $subtype) {
if ($subtype == 'default') continue;
$query['bool']['should'][] = [
'term' => [
'documentSubtype' => $subtype
]
];
}
if (isset($query['bool']['should'])) {
$query['bool']['minimum_should_match'] = 1;
}
}
$esQuery = [
'query' => $query,
'sort' => [
$this->orderBy => ['order' => $this->orderDirection]
]
];
$response = $this->elastic
->setLanguage( $language )
->setDocumentType( $documentIndexName )
->search( $esQuery, $this->resultFrom, $this->resultSize );
$body = \Safe\json_decode( $response->getBody() );
if ( $response->getStatusCode() <= 200) {
if ($body->hits->total->value > 0) {
$listing = [];
foreach ($body->hits->hits as $hit) {
$listing[] = (object)array_merge( ['id' => (int)$hit->_id], (array)$hit->_source);
}
return $listing;
}
}
return null;
}
/**
* @param Document $document
*
* @return bool
*/
public function add( Document $document ) : bool {
if ( ! $this->enabled ) { return false; }
try {
if ($this->extractor->create( $document )) {
try {
$this->elastic->add( $this->extractor );
}
catch (\Exception $exception) {
throw new \Exception($exception->getMessage());
}
return true;
}
}
catch (\Exception $exception) {
$this->logger->log( 'debug', 'indexing -> cant create or update, reasion: '.$exception->getMessage());
}
return false;
}
/**
* @param Document $document
*
* @return stdClass|null
*/
public function get( Document $document ) : \stdClass | null {
if ( ! $this->enabled ) { return null; }
try {
if ($this->extractor->create( $document )) {
$query = [
'bool' => [
'must' => [
'term' => [
'documentId' => $this->extractor->getId()
]
]
]
];
$esQuery = [
'query' => $query,
'size' => 1
];
$response = $this->elastic
->setLanguage( $this->extractor->getLanguage() )
->setDocumentType( $this->extractor->getElasticIndex() )
->search( $esQuery );
$body = \Safe\json_decode( $response->getBody() );
if ( $response->getStatusCode() <= 200) {
if ($body->hits->total->value > 0) {
$hit = $body->hits->hits[0];
return (object)array_merge( ['id' => (int)$hit->_id], (array)$hit->_source);
}
}
//return $this->extractor->getElasticSearchData();
}
}
catch (\Exception $exception) {
$this->logger->log( 'debug', 'indexing -> cant get, reasion: '.$exception->getMessage());
}
return null;
}
/**
* @param Document $document
*
* @return bool
*/
public function delete( Document $document) : bool {
if ( ! $this->enabled ) { return false; }
try {
if ($this->extractor->create( $document )) {
try {
$this->elastic->delete( $this->extractor );
}
catch (\Exception $exception) {
throw new \Exception($exception->getMessage());
}
return true;
}
}
catch (\Exception $exception) {
$this->logger->log( 'debug', 'indexing -> cant get, reasion: '.$exception->getMessage());
}
return false;
}
/**
* Sets the elasticsearch field with which the result is sorted
* @param string $orderBy
*
* @return IndexingService
*/
public function setOrderBy( string $orderBy ): IndexingService {
$this->orderBy = $orderBy;
return $this;
}
/**
* sets sorting direction
* @param string $orderDirection
*
* @return IndexingService
*/
public function setOrderDirection( string $orderDirection ): IndexingService {
$this->orderDirection = $orderDirection;
return $this;
}
/**
* Set result size (limit)
* @param int $resultSize
*
* @return IndexingService
*/
public function setResultSize( int $resultSize ): IndexingService {
$this->resultSize = $resultSize;
return $this;
}
/**
* set the the beginning of the result (limit)
* @param int $resultFrom
*
* @return IndexingService
*/
public function setResultFrom( int $resultFrom ): IndexingService {
$this->resultFrom = $resultFrom;
return $this;
}
}