diff --git a/bundles/EcommerceFrameworkBundle/config/index_service_configs_workers.yaml b/bundles/EcommerceFrameworkBundle/config/index_service_configs_workers.yaml index c82a490f4c6..25cb43604f0 100644 --- a/bundles/EcommerceFrameworkBundle/config/index_service_configs_workers.yaml +++ b/bundles/EcommerceFrameworkBundle/config/index_service_configs_workers.yaml @@ -65,9 +65,6 @@ services: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\OptimizedMysql: parent: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\AbstractWorker - Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch7: - parent: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\AbstractWorker - Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch8: parent: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\AbstractWorker diff --git a/bundles/EcommerceFrameworkBundle/src/DependencyInjection/IndexService/DefaultWorkerConfigMapper.php b/bundles/EcommerceFrameworkBundle/src/DependencyInjection/IndexService/DefaultWorkerConfigMapper.php index f34695d88cd..59b8f7bd649 100644 --- a/bundles/EcommerceFrameworkBundle/src/DependencyInjection/IndexService/DefaultWorkerConfigMapper.php +++ b/bundles/EcommerceFrameworkBundle/src/DependencyInjection/IndexService/DefaultWorkerConfigMapper.php @@ -24,7 +24,7 @@ use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\OptimizedMysql as OptimizedMysqlConfig; use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\DefaultFindologic; use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\DefaultMysql; -use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch7; +use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch8; use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\OptimizedMysql; /** @@ -38,7 +38,7 @@ class DefaultWorkerConfigMapper OptimizedMysqlConfig::class => OptimizedMysql::class, DefaultMysqlConfig::class => DefaultMysql::class, DefaultMysqlSubTenantConfig::class => DefaultMysql::class, - ElasticSearch::class => DefaultElasticSearch7::class, + ElasticSearch::class => DefaultElasticSearch8::class, DefaultFindologicConfig::class => DefaultFindologic::class, ]; diff --git a/bundles/EcommerceFrameworkBundle/src/FilterService/FilterType/ElasticSearch/Select.php b/bundles/EcommerceFrameworkBundle/src/FilterService/FilterType/ElasticSearch/Select.php index 9b5103039b0..f219e825d78 100644 --- a/bundles/EcommerceFrameworkBundle/src/FilterService/FilterType/ElasticSearch/Select.php +++ b/bundles/EcommerceFrameworkBundle/src/FilterService/FilterType/ElasticSearch/Select.php @@ -41,7 +41,7 @@ public function addCondition(AbstractFilterDefinitionType $filterDefinition, Pro $value = $preSelect; } - $value = trim($value); + $value = trim((string)$value); $currentFilter[$field] = $value; if (!empty($value)) { diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearch.php b/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearch.php index 648ef85ea06..ca7f7cbc041 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearch.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearch.php @@ -30,7 +30,6 @@ /** * Default configuration for elastic search as product index implementation. * - * @method DefaultElasticSearchWorker getTenantWorker() */ class ElasticSearch extends AbstractConfig implements MockupConfigInterface, ElasticSearchConfigInterface { @@ -127,12 +126,6 @@ protected function processOptions(array $options) // TODO validate client config and other settings/params? $this->clientConfig = $options['client_config']; $this->indexSettings = $options['index_settings']; - $this->elasticSearchClientParams = $options['es_client_params']; - - //add default type for elasticsearch - if (empty($this->elasticSearchClientParams['indexType'])) { - $this->elasticSearchClientParams['indexType'] = '_doc'; - } } protected function configureOptionsResolver(string $resolverName, OptionsResolver $resolver) @@ -140,7 +133,6 @@ protected function configureOptionsResolver(string $resolverName, OptionsResolve $arrayFields = [ 'client_config', 'index_settings', - 'es_client_params', 'mapping', ]; @@ -161,8 +153,6 @@ protected function configureOptionsResolver(string $resolverName, OptionsResolve $resolver->setDefined('es_client_name'); $resolver->setAllowedTypes('es_client_name', 'string'); - //set options to deprecated - $resolver->setDeprecated('es_client_params'); } protected function extractPossibleFirstSubFieldnameParts(string $fieldName): array @@ -248,11 +238,6 @@ public function getIndexSettings(): array return $this->indexSettings; } - public function getElasticSearchClientParams(): array - { - return $this->elasticSearchClientParams; - } - /** * checks, if product should be in index for current tenant * diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearchConfigInterface.php b/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearchConfigInterface.php index 1de389e8c27..c7664daf996 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearchConfigInterface.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/Config/ElasticSearchConfigInterface.php @@ -24,12 +24,6 @@ */ interface ElasticSearchConfigInterface extends ConfigInterface { - /** - * returns elastic search client parameters defined in the tenant config - * - * @return array - */ - public function getElasticSearchClientParams(): array; /** * returns condition for current subtenant diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultFindologic.php b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultFindologic.php index 23e314495cb..5df1709c79e 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultFindologic.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultFindologic.php @@ -129,10 +129,10 @@ public function resetCondition(string $fieldname): void * Fieldname is optional but highly recommended - needed for resetting condition based on fieldname * and exclude functionality in group by results * - * @param string $condition + * @param string|array $condition * @param string $fieldname */ - public function addQueryCondition(string $condition, string $fieldname = '') + public function addQueryCondition(string|array $condition, string $fieldname = '') { $this->products = null; $this->queryConditions[$fieldname][] = $condition; diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultMysql.php b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultMysql.php index 1e7b833bd90..da30498a2a7 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultMysql.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/DefaultMysql.php @@ -124,10 +124,10 @@ public function resetConditions() * Fieldname is optional but highly recommended - needed for resetting condition based on fieldname * and exclude functionality in group by results * - * @param string $condition + * @param string|array $condition * @param string $fieldname */ - public function addQueryCondition(string $condition, string $fieldname = '') + public function addQueryCondition(string|array $condition, string $fieldname = '') { $this->products = null; $this->queryConditions[$fieldname][] = $condition; diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ElasticSearch/AbstractElasticSearch.php b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ElasticSearch/AbstractElasticSearch.php index 8b471204999..53024436df8 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ElasticSearch/AbstractElasticSearch.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ElasticSearch/AbstractElasticSearch.php @@ -16,6 +16,7 @@ namespace Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ElasticSearch; +use Elastic\Elasticsearch\Client; use Pimcore\Bundle\EcommerceFrameworkBundle\Exception\InvalidConfigException; use Pimcore\Bundle\EcommerceFrameworkBundle\Factory; use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\ElasticSearch; @@ -63,7 +64,7 @@ abstract class AbstractElasticSearch implements ProductListInterface protected ?string $order = null; - protected string|array $orderKey; + protected string|array $orderKey = ''; protected bool $orderByPrice = false; @@ -219,10 +220,10 @@ public function resetConditions() * Fieldname is optional but highly recommended - needed for resetting condition based on fieldname * and exclude functionality in group by results * - * @param string $condition + * @param string|array $condition * @param string $fieldname - must be set for elastic search */ - public function addQueryCondition(string $condition, string $fieldname = '') + public function addQueryCondition(string|array $condition, string $fieldname = '') { $this->queryConditions[$fieldname][] = $condition; $this->preparedGroupByValuesLoaded = false; @@ -417,7 +418,7 @@ public function load(): array $this->products = $this->productPositionMap = []; $i = 0; foreach ($objectRaws as $raw) { - $product = $this->loadElementById($raw); + $product = $this->loadElementById((int) $raw); if ($product) { $this->products[] = $product; $this->productPositionMap[$product->getId()] = $i; @@ -452,7 +453,6 @@ public function getQuery(): array $params = []; $params['index'] = $this->getIndexName(); - $params['type'] = $this->getTenantConfig()->getElasticSearchClientParams()['indexType']; $params['track_total_hits'] = true; $params['rest_total_hits_as_int'] = true; @@ -1161,39 +1161,36 @@ public function getTenantConfig(): ElasticSearchConfigInterface /** * send a request to elasticsearch - * - * @param array $params - * - * @return array */ protected function sendRequest(array $params): array { - $tenantWorker = $this->tenantConfig->getTenantWorker(); - if (!($tenantWorker instanceof \Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\AbstractElasticSearch)) { - throw new InvalidConfigException('Invalid tenant worker configured. Should be instance of AbstractElasticSearch.'); + + $worker = $this->tenantConfig->getTenantWorker(); + if(!$worker instanceof \Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\AbstractElasticSearch) { + throw new InvalidConfigException('Invalid worker configured, AbstractElasticSearch compatible worker expected.'); } /** - * @var \Elasticsearch\Client $esClient + * @var Client $esClient */ - $esClient = $tenantWorker->getElasticSearchClient(); + $esClient = $worker->getElasticSearchClient(); $result = []; - if ($esClient instanceof \Elasticsearch\Client) { + if ($esClient instanceof Client) { if ($this->doScrollRequest) { $params = array_merge(['scroll' => $this->scrollRequestKeepAlive], $params); //kind of dirty hack :/ $params['body']['size'] = $this->getLimit(); } - $result = $esClient->search($params); + $result = $esClient->search($params)->asArray(); if ($this->doScrollRequest) { $additionalHits = []; $scrollId = $result['_scroll_id']; while (true) { - $additionalResult = $esClient->scroll(['scroll_id' => $scrollId, 'scroll' => $this->scrollRequestKeepAlive]); + $additionalResult = $esClient->scroll(['scroll_id' => $scrollId, 'scroll' => $this->scrollRequestKeepAlive])->asArray(); if (count($additionalResult['hits']['hits'])) { $additionalHits = array_merge($additionalHits, $additionalResult['hits']['hits']); diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ElasticSearch/DefaultElasticSearch7.php b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ElasticSearch/DefaultElasticSearch7.php deleted file mode 100644 index 60c78314ca7..00000000000 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ElasticSearch/DefaultElasticSearch7.php +++ /dev/null @@ -1,24 +0,0 @@ -tenantConfig->getTenantWorker()->getElasticSearchClient(); - $result = []; - if ($esClient instanceof Client) { - if ($this->doScrollRequest) { - $params = array_merge(['scroll' => $this->scrollRequestKeepAlive], $params); - //kind of dirty hack :/ - $params['body']['size'] = $this->getLimit(); - } - - $result = $esClient->search($params)->asArray(); - - if ($this->doScrollRequest) { - $additionalHits = []; - $scrollId = $result['_scroll_id']; - - while (true) { - $additionalResult = $esClient->scroll(['scroll_id' => $scrollId, 'scroll' => $this->scrollRequestKeepAlive])->asArray(); - - if (count($additionalResult['hits']['hits'])) { - $additionalHits = array_merge($additionalHits, $additionalResult['hits']['hits']); - $scrollId = $additionalResult['_scroll_id']; - } else { - break; - } - } - $result['hits']['hits'] = array_merge($result['hits']['hits'], $additionalHits); - } - } - - return $result; - } } diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ProductListInterface.php b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ProductListInterface.php index 2c6eff459bd..907a2472c2e 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ProductListInterface.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/ProductList/ProductListInterface.php @@ -77,10 +77,10 @@ public function addCondition(array|string $condition, string $fieldname = ''); * Fieldname is optional but highly recommended - needed for resetting condition based on fieldname * and exclude functionality in group by results * - * @param string $condition + * @param string|array $condition * @param string $fieldname */ - public function addQueryCondition(string $condition, string $fieldname = ''); + public function addQueryCondition(string|array $condition, string $fieldname = ''); /** * Reset filter condition for fieldname diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php b/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php index d2943dc54c9..3262903b636 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php @@ -17,9 +17,8 @@ namespace Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch; use Doctrine\DBAL\Connection; -use Elasticsearch\Common\Exceptions\BadRequest400Exception; -use Elasticsearch\Common\Exceptions\Missing404Exception; -use Elasticsearch\Common\Exceptions\NoNodesAvailableException; +use Elastic\Elasticsearch\Client; +use Elastic\Elasticsearch\Exception\ClientResponseException; use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\ElasticSearch; use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\ElasticSearchConfigInterface; use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Interpreter\RelationInterpreterInterface; @@ -53,7 +52,7 @@ abstract class AbstractElasticSearch extends Worker\ProductCentricBatchProcessin */ protected bool $storeCustomAttributes = true; - protected ?\Elasticsearch\Client $elasticSearchClient = null; + protected ?Client $elasticSearchClient = null; /** * index name of elastic search must be lower case @@ -126,7 +125,7 @@ public function getIndexNameVersion(int $indexVersionOverride = null): string return $this->indexName . '-' . $indexVersion; } - public function getIndexVersion(): ?int + public function getIndexVersion(): int { if ($this->indexVersion === null) { $this->indexVersion = 0; @@ -135,7 +134,7 @@ public function getIndexVersion(): ?int try { $result = $esClient->indices()->getAlias([ 'name' => $this->indexName, - ]); + ])->asArray(); if (is_array($result)) { $aliasIndexName = array_key_first($result); @@ -147,8 +146,12 @@ public function getIndexVersion(): ?int } } } - } catch (Missing404Exception $e) { - $this->indexVersion = 0; + } catch (ClientResponseException $e) { + if ($e->getCode() === 404) { + $this->indexVersion = 0; + } else { + throw $e; + } } } @@ -162,36 +165,16 @@ public function setIndexVersion(int $indexVersion): static return $this; } - public function getElasticSearchClient(): ?\Elasticsearch\Client + /** + * @param Client|null $elasticSearchClient + */ + public function setElasticSearchClient(?Client $elasticSearchClient): void { - if (empty($this->elasticSearchClient)) { - $builder = \Elasticsearch\ClientBuilder::create(); - if ($this->tenantConfig->getClientConfig('logging')) { - $builder->setLogger($this->logger); - } - - $esSearchParams = $this->tenantConfig->getElasticSearchClientParams(); - $builder->setHosts($esSearchParams['hosts']); - - // timeout for search queries is important, because long queries can block PHP FPM - // distinguish CLI, because reindexing scripts tend to run longer than frontend search queries - $timeoutMsParamName = php_sapi_name() == 'cli' ? 'timeoutMsBackend' : 'timeoutMs'; - if (isset($esSearchParams[$timeoutMsParamName])) { - $timeoutMs = $esSearchParams[$timeoutMsParamName]; - } else { - $timeoutMs = php_sapi_name() == 'cli' ? self::DEFAULT_TIMEOUT_MS_BACKEND : self::DEFAULT_TIMEOUT_MS_FRONTEND; - } - $builder->setConnectionParams([ - 'client' => [ - 'curl' => [ - CURLOPT_TIMEOUT_MS => $timeoutMs, - ], - ], - ]); - - $this->elasticSearchClient = $builder->build(); - } + $this->elasticSearchClient = $elasticSearchClient; + } + public function getElasticSearchClient(): ?Client + { return $this->elasticSearchClient; } @@ -470,7 +453,7 @@ public function commitBatchToIndex(): void $esClient = $this->getElasticSearchClient(); $responses = $esClient->bulk([ 'body' => $this->bulkIndexData, - ]); + ])->asArray(); // save update status foreach ($responses['items'] as $response) { @@ -549,7 +532,7 @@ public function switchIndexAlias() ], ], ]; - $result = $esClient->indices()->updateAliases($params); + $result = $esClient->indices()->updateAliases($params)->asArray(); if (!$result['acknowledged']) { //set current index version throw new \Exception('Switching Alias failed for ' . $this->getIndexNameVersion()); @@ -559,10 +542,11 @@ public function switchIndexAlias() $this->cleanupUnusedEsIndices(); } + protected function cleanupUnusedEsIndices(): void { $esClient = $this->getElasticSearchClient(); - $stats = $esClient->indices()->stats(); + $stats = $esClient->indices()->stats()->asArray(); foreach ($stats['indices'] as $key => $data) { preg_match('/'.$this->indexName.'-(\d+)/', $key, $matches); if (is_array($matches) && count($matches) > 1) { @@ -614,13 +598,11 @@ protected function doDeleteFromIndex(int $objectId, IndexableInterface $object = } $esClient->delete([ 'index' => $this->getIndexNameVersion(), - 'type' => $tenantConfig->getElasticSearchClientParams()['indexType'], 'id' => $objectId, $this->routingParamName => $storeEntry['o_virtualProductId'], ]); - } catch (\Exception $e) { - //if \Elasticsearch\Common\Exceptions\Missing404Exception <- the object is not in the index so its ok. - if ($e instanceof Missing404Exception == false) { + } catch (ClientResponseException $e) { + if ($e->getCode() !== 404) { throw $e; } } @@ -636,7 +618,7 @@ protected function doCreateOrUpdateIndexStructures() $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $this->getIndexNameVersion()]); + $result = $esClient->indices()->exists(['index' => $this->getIndexNameVersion()])->asBool(); if (!$result) { $indexName = $this->getIndexNameVersion(); @@ -659,7 +641,7 @@ protected function doCreateOrUpdateIndexStructures() $currentSettings = $esClient->indices()->getSettings([ 'index' => $this->getIndexNameVersion(), - ]); + ])->asArray(); $currentSettings = $currentSettings[$this->getIndexNameVersion()]['settings']['index']; $settingsIntersection = array_intersect_key($currentSettings, $configuredSettings); @@ -704,7 +686,7 @@ public function fetchEsActiveIndex(): ?string $esClient = $this->getElasticSearchClient(); try { - $result = $esClient->indices()->getAlias(['index' => $this->indexName]); + $result = $esClient->indices()->getAlias(['index' => $this->indexName])->asArray(); } catch (\Exception $e) { Logger::error((string) $e); @@ -726,7 +708,7 @@ protected function createEsAliasIfMissing() { $esClient = $this->getElasticSearchClient(); //create alias for new index if alias doesn't exist so far - $aliasExists = $esClient->indices()->existsAlias(['name' => $this->indexName]); + $aliasExists = $esClient->indices()->existsAlias(['name' => $this->indexName])->asBool(); if (!$aliasExists) { Logger::info("Index-Actions - create alias for index since it doesn't exist at all. Name: " . $this->indexName); $params['body'] = [ @@ -739,7 +721,7 @@ protected function createEsAliasIfMissing() ], ], ]; - $result = $esClient->indices()->updateAliases($params); + $result = $esClient->indices()->updateAliases($params)->asArray(); if (!$result) { throw new \Exception('Alias '.$this->indexName.' could not be created.'); } @@ -768,7 +750,7 @@ protected function createEsIndex(string $indexName) $result = $esClient->indices()->create([ 'index' => $indexName, 'body' => ['settings' => $configuredSettings], - ]); + ])->asArray(); if (!$result['acknowledged']) { throw new \Exception('Index creation failed. IndexName: ' . $indexName); @@ -788,7 +770,7 @@ protected function putIndexMapping(string $indexName) $params = $this->getMappingParams(); $params['index'] = $indexName; - $result = $esClient->indices()->putMapping($params); + $result = $esClient->indices()->putMapping($params)->asArray(); if (!$result['acknowledged']) { throw new \Exception('Putting mapping to index failed. IndexName: ' . $indexName); @@ -805,10 +787,10 @@ protected function putIndexMapping(string $indexName) protected function deleteEsIndexIfExisting(string $indexName) { $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $indexName]); + $result = $esClient->indices()->exists(['index' => $indexName])->asBool(); if ($result) { Logger::info('Deleted index '.$indexName.'.'); - $result = $esClient->indices()->delete(['index' => $indexName]); + $result = $esClient->indices()->delete(['index' => $indexName])->asArray(); if (!array_key_exists('acknowledged', $result) && !$result['acknowledged']) { Logger::error("Could not delete index {$indexName} while cleanup. Please remove the index manually."); } @@ -823,7 +805,7 @@ protected function deleteEsIndexIfExisting(string $indexName) protected function blockIndexWrite(string $indexName) { $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $indexName]); + $result = $esClient->indices()->exists(['index' => $indexName])->asBool(); if ($result) { Logger::info('Block write index '.$indexName.'.'); $esClient->indices()->putSettings([ @@ -847,7 +829,7 @@ protected function blockIndexWrite(string $indexName) protected function unblockIndexWrite(string $indexName) { $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $indexName]); + $result = $esClient->indices()->exists(['index' => $indexName])->asBool(); if ($result) { Logger::info('Unlock write index '.$indexName.'.'); $esClient->indices()->putSettings([ @@ -924,8 +906,7 @@ protected function performReindex(string $sourceIndexName, string $targetIndexNa * - all index updates are stored into store table only, and transferred with next ecommerce:indexservice:process-update-queue * - no index structure updates are allowed * - * @throws BadRequest400Exception - * @throws NoNodesAvailableException + * @throws \Exception */ public function startReindexMode() { @@ -986,7 +967,8 @@ public function updateSynonyms(string $indexNameOverride = '', bool $skipCompari $esClient = $this->getElasticSearchClient(); if (!$skipComparison) { - $indexSettingsCurrentEs = $esClient->indices()->getSettings(['index' => $indexName])[$indexName]['settings']['index']; + $settings = $esClient->indices()->getSettings(['index' => $indexName])->asArray(); + $indexSettingsCurrentEs = $settings[$indexName]['settings']['index']; $indexSettingsSynonymPartEs = $this->extractMinimalSynonymFiltersTreeFromIndexSettings($indexSettingsCurrentEs); if ($indexSettingsSynonymPartEs == $indexSettingsSynonymPartLocalConfig) { @@ -1005,7 +987,7 @@ public function updateSynonyms(string $indexNameOverride = '', bool $skipCompari 'body' => [ 'index' => $indexSettingsSynonymPartLocalConfig, ], - ]); + ])->asArray(); $esClient->indices()->open(['index' => $indexName]); diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/DefaultElasticSearch7.php b/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/DefaultElasticSearch7.php deleted file mode 100644 index bed3efa28f2..00000000000 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/DefaultElasticSearch7.php +++ /dev/null @@ -1,30 +0,0 @@ -tenantConfig); - } -} diff --git a/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/DefaultElasticSearch8.php b/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/DefaultElasticSearch8.php index e9eab9ca467..6fa0a990d84 100644 --- a/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/DefaultElasticSearch8.php +++ b/bundles/EcommerceFrameworkBundle/src/IndexService/Worker/ElasticSearch/DefaultElasticSearch8.php @@ -31,488 +31,29 @@ public function getProductList(): \Pimcore\Bundle\EcommerceFrameworkBundle\Index return new \Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\ProductList\ElasticSearch\DefaultElasticSearch8($this->tenantConfig); } - public function getIndexVersion(): int - { - if ($this->indexVersion === null) { - $this->indexVersion = 0; - $esClient = $this->getElasticSearchClient(); - - try { - $result = $esClient->indices()->getAlias([ - 'name' => $this->indexName, - ])->asArray(); - - if (is_array($result)) { - $aliasIndexName = array_key_first($result); - preg_match('/'.$this->indexName.'-(\d+)/', $aliasIndexName, $matches); - if (is_array($matches) && count($matches) > 1) { - $version = (int)$matches[1]; - if ($version > $this->indexVersion) { - $this->indexVersion = $version; - } - } - } - } catch (ClientResponseException $e) { - if ($e->getCode() === 404) { - $this->indexVersion = 0; - } else { - throw $e; - } - } - } - - return $this->indexVersion; - } - - /** - * @param Client|null $elasticSearchClient - */ - public function setElasticSearchClient(?Client $elasticSearchClient): void - { - $this->elasticSearchClient = $elasticSearchClient; - } - - public function getElasticSearchClient(): ?\Elasticsearch\Client - { - return $this->elasticSearchClient; - } - - /** - * actually sending data to elastic search - */ - public function commitBatchToIndex(): void - { - if (count($this->bulkIndexData)) { - $esClient = $this->getElasticSearchClient(); - $responses = $esClient->bulk([ - 'body' => $this->bulkIndexData, - ])->asArray(); - - // save update status - foreach ($responses['items'] as $response) { - $operation = null; - if (isset($response['index'])) { - $operation = 'index'; - } elseif (isset($response['delete'])) { - $operation = 'delete'; - } - - if ($operation) { - $data = [ - 'update_status' => $response[$operation]['status'], - 'update_error' => null, - 'metadata' => isset($this->indexStoreMetaData[$response[$operation]['_id']]) ? $this->indexStoreMetaData[$response[$operation]['_id']] : null, - ]; - if (isset($response[$operation]['error']) && $response[$operation]['error']) { - $data['update_error'] = json_encode($response[$operation]['error']); - $data['crc_index'] = 0; - Logger::error( - 'Failed to Index Object with Id:' . $response[$operation]['_id'], - json_decode($data['update_error'], true) - ); - - $this->db->update( - $this->getStoreTableName(), - $data, - ['o_id' => $response[$operation]['_id'], 'tenant' => $this->name] - ); - } else { - //update crc sums in store table to mark element as indexed - $this->db->executeQuery( - 'UPDATE ' . $this->getStoreTableName() . ' SET crc_index = crc_current, update_status = ?, update_error = ?, metadata = ? WHERE o_id = ? and tenant = ?', - [$data['update_status'], $data['update_error'], $data['metadata'], $response[$operation]['_id'], $this->name] - ); - } - } else { - throw new \Exception('Unkown operation in response: ' . print_r($response, true)); - } - } - } - - // reset - $this->bulkIndexData = []; - $this->indexStoreMetaData = []; - } - - /** - * Sets the alias to the current index-version and deletes the old indices - * - * @throws \Exception - */ - public function switchIndexAlias() - { - Logger::info('Index-Actions - Switching Alias'); - $esClient = $this->getElasticSearchClient(); - - $params['body'] = [ - 'actions' => [ - [ - 'remove' => [ - 'index' => '*', - 'alias' => $this->indexName, - ], - ], - [ - 'add' => [ - 'index' => $this->getIndexNameVersion(), - 'alias' => $this->indexName, - ], - ], - ], - ]; - $result = $esClient->indices()->updateAliases($params)->asArray(); - if (!$result['acknowledged']) { - //set current index version - throw new \Exception('Switching Alias failed for ' . $this->getIndexNameVersion()); - } - - //delete old indices - $this->cleanupUnusedEsIndices(); - } - - protected function cleanupUnusedEsIndices(): void - { - $esClient = $this->getElasticSearchClient(); - $stats = $esClient->indices()->stats()->asArray(); - foreach ($stats['indices'] as $key => $data) { - preg_match('/'.$this->indexName.'-(\d+)/', $key, $matches); - if (is_array($matches) && count($matches) > 1) { - $version = (int)$matches[1]; - if ($version != $this->indexVersion) { - $indexNameVersion = $this->getIndexNameVersion($version); - Logger::info('Index-Actions - Delete old Index ' . $indexNameVersion); - $this->deleteEsIndexIfExisting($indexNameVersion); - } - } - } - } - - /** - * @param int $objectId - * @param IndexableInterface|null $object - * - * @throws \Exception - */ - protected function doDeleteFromIndex($objectId, IndexableInterface $object = null) - { - $esClient = $this->getElasticSearchClient(); - - $storeEntry = \Pimcore\Db::get()->fetchAssociative('SELECT * FROM ' . $this->getStoreTableName() . ' WHERE o_id=? AND tenant=? ', [$objectId, $this->getTenantConfig()->getTenantName()]); - if ($storeEntry) { - $isLocked = $this->checkIndexLock(false); - if ($isLocked) { - throw new \Exception('Delete not possible due to product index lock. Please re-try later.'); - } - - try { - $tenantConfig = $this->getTenantConfig(); - if (!$tenantConfig instanceof ElasticSearchConfigInterface) { - throw new \Exception('Expected a ElasticSearchConfigInterface'); - } - $esClient->delete([ - 'index' => $this->getIndexNameVersion(), - 'type' => $tenantConfig->getElasticSearchClientParams()['indexType'], - 'id' => $objectId, - $this->routingParamName => $storeEntry['o_virtualProductId'], - ]); - } catch (ClientResponseException $e) { - if ($e->getCode() !== 404) { - throw $e; - } - } - $this->deleteFromStoreTable($objectId); - } - } - - protected function doCreateOrUpdateIndexStructures() - { - $this->checkIndexLock(true); - - $this->createOrUpdateStoreTable(); - $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $this->getIndexNameVersion()])->asBool(); - if (!$result) { - $indexName = $this->getIndexNameVersion(); - $this->createEsIndex($indexName); - //index didn't exist -> reset index queue to make sure all products get re-indexed - $this->resetIndexingQueue(); - $this->createEsAliasIfMissing(); - } - try { - $this->putIndexMapping($this->getIndexNameVersion()); - $configuredSettings = $this->tenantConfig->getIndexSettings(); - $synonymSettings = $this->extractMinimalSynonymFiltersTreeFromTenantConfig(); - if (isset($synonymSettings['analysis'])) { - $configuredSettings['analysis']['filter'] = array_replace_recursive($configuredSettings['analysis']['filter'], $synonymSettings['analysis']['filter']); - } - $currentSettings = $esClient->indices()->getSettings([ - 'index' => $this->getIndexNameVersion(), - ])->asArray(); - $currentSettings = $currentSettings[$this->getIndexNameVersion()]['settings']['index']; - $settingsIntersection = array_intersect_key($currentSettings, $configuredSettings); - if ($settingsIntersection != $configuredSettings) { - $esClient->indices()->putSettings([ - 'index' => $this->getIndexNameVersion(), - 'body' => [ - 'index' => $this->tenantConfig->getIndexSettings(), - ], - ]); - Logger::info('Index-Actions - updated settings for Index: ' . $this->getIndexNameVersion()); - } else { - Logger::info('Index-Actions - no settings update necessary for Index: ' . $this->getIndexNameVersion()); - } - } catch (\Exception $e) { - Logger::info("Index-Actions - can't create Mapping - trying reindexing " . $e->getMessage()); - Logger::info('Index-Actions - Perform native reindexing for Index: ' . $this->getIndexNameVersion()); - $this->startReindexMode(); - } - } - - /** - * Retrieve the currently active index name from ES based on the alias. - * - * @return string|null null if no index is found. - */ - public function fetchEsActiveIndex(): ?string - { - $esClient = $this->getElasticSearchClient(); - - try { - $result = $esClient->indices()->getAlias(['index' => $this->indexName])->asArray(); - } catch (\Exception $e) { - Logger::error((string) $e); - - return null; - } - - reset($result); - $currentIndexName = key($result); - - return $currentIndexName; - } - - /** - * Create the index alias on demand. - * - * @throws \Exception if alias could not be created. - */ - protected function createEsAliasIfMissing() - { - $esClient = $this->getElasticSearchClient(); - //create alias for new index if alias doesn't exist so far - $aliasExists = $esClient->indices()->existsAlias(['name' => $this->indexName])->asBool(); - if (!$aliasExists) { - Logger::info("Index-Actions - create alias for index since it doesn't exist at all. Name: " . $this->indexName); - $params['body'] = [ - 'actions' => [ - [ - 'add' => [ - 'index' => $this->getIndexNameVersion(), - 'alias' => $this->indexName, - ], - ], - ], - ]; - $result = $esClient->indices()->updateAliases($params)->asArray(); - if (!$result) { - throw new \Exception('Alias '.$this->indexName.' could not be created.'); - } - } - } - - /** - * Create an ES index with the specified version. - * - * @param string $indexName the name of the index. - * - * @throws \Exception is thrown if index cannot be created, for instance if connection fails or index is already existing. - */ - protected function createEsIndex(string $indexName) - { - $esClient = $this->getElasticSearchClient(); - - Logger::info('Index-Actions - creating new Index. Name: ' . $indexName); - - $configuredSettings = $this->tenantConfig->getIndexSettings(); - $synonymSettings = $this->extractMinimalSynonymFiltersTreeFromTenantConfig(); - if (isset($synonymSettings['analysis'])) { - $configuredSettings['analysis']['filter'] = array_replace_recursive($configuredSettings['analysis']['filter'], $synonymSettings['analysis']['filter']); - } - - $result = $esClient->indices()->create([ - 'index' => $indexName, - 'body' => ['settings' => $configuredSettings], - ])->asArray(); - - if (!$result['acknowledged']) { - throw new \Exception('Index creation failed. IndexName: ' . $indexName); - } - } - /** - * puts current mapping to index with given name - * - * @param string $indexName - * - * @throws \Exception - */ - protected function putIndexMapping(string $indexName) - { - $esClient = $this->getElasticSearchClient(); - $params = $this->getMappingParams(); - $params['index'] = $indexName; - $result = $esClient->indices()->putMapping($params)->asArray(); - if (!$result['acknowledged']) { - throw new \Exception('Putting mapping to index failed. IndexName: ' . $indexName); - } - Logger::info('Index-Actions - updated Mapping for Index: ' . $indexName); - } - /** - * Delete an ES index if existing. - * - * @param string $indexName the name of the index. - */ - protected function deleteEsIndexIfExisting(string $indexName) - { - $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $indexName])->asBool(); - if ($result) { - Logger::info('Deleted index '.$indexName.'.'); - $result = $esClient->indices()->delete(['index' => $indexName])->asArray(); - if (!array_key_exists('acknowledged', $result) && !$result['acknowledged']) { - Logger::error("Could not delete index {$indexName} while cleanup. Please remove the index manually."); - } - } - } - /** - * Blocks all write operations - * - * @param string $indexName the name of the index. - */ - protected function blockIndexWrite(string $indexName) - { - $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $indexName])->asBool(); - if ($result) { - Logger::info('Block write index '.$indexName.'.'); - $esClient->indices()->putSettings([ - 'index' => $indexName, - 'body' => [ - 'index.blocks.write' => true, - ], - ]); - $esClient->indices()->refresh([ - 'index' => $indexName, - ]); - } - } - /** - * Unblocks all write operations - * - * @param string $indexName the name of the index. - */ - protected function unblockIndexWrite(string $indexName) - { - $esClient = $this->getElasticSearchClient(); - $result = $esClient->indices()->exists(['index' => $indexName])->asBool(); - if ($result) { - Logger::info('Unlock write index '.$indexName.'.'); - $esClient->indices()->putSettings([ - 'index' => $indexName, - 'body' => [ - 'index.blocks.write' => false, - ], - ]); - $esClient->indices()->refresh([ - 'index' => $indexName, - ]); - } - } - /** - * - * Perform a synonym update on the currently selected ES index, if necessary. - * - * Attention: the current index will be closed and opened, so it won't be available for a tiny moment (typically some milliseconds). - * - * @param string $indexNameOverride if given, then that index will be used instead of the current index. - * @param bool $skipComparison if explicitly set to true, then the comparison whether the synonyms between the current index settings - * and the local index settings vary, will be skipped, and the index settings will be updated regardless. - * @param bool $skipLocking if explictly set to true, then no global lock will be activated / released. - * - * @throws \Exception is thrown if the synonym transmission fails. - */ - public function updateSynonyms(string $indexNameOverride = '', bool $skipComparison = false, bool $skipLocking = true) - { - try { - if (!$skipLocking) { - $this->activateIndexLock(); //lock all other processes - } - - $indexName = $indexNameOverride ?: $this->getIndexNameVersion(); - - $indexSettingsSynonymPartLocalConfig = $this->extractMinimalSynonymFiltersTreeFromTenantConfig(); - if (empty($indexSettingsSynonymPartLocalConfig)) { - Logger::info('No index update required, as no synonym providers are configured. '. - 'If filters have been removed, then reindexing will help to get rid of old configurations.' - ); - - return; - } - $esClient = $this->getElasticSearchClient(); - if (!$skipComparison) { - $settings = $esClient->indices()->getSettings(['index' => $indexName])->asArray(); - $indexSettingsCurrentEs = $settings[$indexName]['settings']['index']; - $indexSettingsSynonymPartEs = $this->extractMinimalSynonymFiltersTreeFromIndexSettings($indexSettingsCurrentEs); - if ($indexSettingsSynonymPartEs == $indexSettingsSynonymPartLocalConfig) { - Logger::info(sprintf('The synonyms in ES index "%s" are identical with those of the local configuration. '. - 'No update required.', $indexName)); - return; - } - } - Logger::info(sprintf('Update synonyms in "%s"...', $indexName)); - $esClient->indices()->close(['index' => $indexName]); - - $result = $esClient->indices()->putSettings([ - 'index' => $indexName, - 'body' => [ - 'index' => $indexSettingsSynonymPartLocalConfig, - ], - ])->asArray(); - - $esClient->indices()->open(['index' => $indexName]); - - if (!$result['acknowledged']) { - //exception must be thrown after re-opening the index! - throw new \Exception('Index synonym settings update failed. IndexName: ' . $indexName); - } - } finally { - if (!$skipLocking) { - $this->releaseIndexLock(); - } - } - } } diff --git a/bundles/EcommerceFrameworkBundle/src/Tracking/AbstractProductData.php b/bundles/EcommerceFrameworkBundle/src/Tracking/AbstractProductData.php index 191a16b371e..1fa53a27c80 100644 --- a/bundles/EcommerceFrameworkBundle/src/Tracking/AbstractProductData.php +++ b/bundles/EcommerceFrameworkBundle/src/Tracking/AbstractProductData.php @@ -30,7 +30,7 @@ abstract class AbstractProductData extends AbstractData protected int $position = 0; - protected float $price; + protected ?float $price = null; public function getTransactionId(): string { @@ -116,7 +116,7 @@ public function setPosition(int $position): static return $this; } - public function getPrice(): float + public function getPrice(): ?float { return $this->price; } diff --git a/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/01_Configuration_Details.md b/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/01_Configuration_Details.md index 27804c4b5fc..99b2dcc980b 100644 --- a/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/01_Configuration_Details.md +++ b/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/01_Configuration_Details.md @@ -33,11 +33,6 @@ pimcore_elasticsearch_client: 2) Define the client name to be used by an elasticsearch tenant. This will be done via the `es_client_name` configuration in the `config_options`. -##### `es_client_params` (deprecated, for Elasticsearch 7 only) -- `hosts`: Array of hosts of the elasticsearch cluster to use. -- `timeoutMs`: optional parameter for setting the client timeout (frontend) in milliseconds. -- `timeoutMsBackend`: optional parameter for setting the client timeout (CLI) in milliseconds. This value is typically higher than ``timeoutMs``. - ##### `synonym_providers` Specify synonym providers for synonym filters defined in filter section of index settings. For details see [Synonyms](./02_Synonyms.md). @@ -58,13 +53,6 @@ pimcore_ecommerce_framework: # elasticsearch client name, for Elasticsearch 8 only es_client_name: default - - # deprecated, for Elasticsearch 7 only - es_client_params: - hosts: - - '%elasticsearch.host%' - timeoutMs: 20000, # 20 seconds - timeoutMsBackend: 120000 # 2 minutes index_settings: number_of_shards: 5 diff --git a/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/02_Synonyms.md b/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/02_Synonyms.md index cc52f07187e..108f170454b 100644 --- a/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/02_Synonyms.md +++ b/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/02_Synonyms.md @@ -15,7 +15,7 @@ needed. Pimcore ships with a simple `FileSynonymProvider` that can be used right away. The synonym source is a file (e.g. a Pimcore asset) that follows the [Solr file format](https://www.elastic.co/guide/en/elasticsearch/reference/7.12/analysis-synonym-tokenfilter.html#_solr_synonyms). -Besides the service configuration it self, the synonym providers need to be configured in index service +Besides the service configuration itself, the synonym providers need to be configured in index service configuration as follows. ```yml @@ -24,7 +24,7 @@ pimcore_ecommerce_framework: tenants: : enabled: true - worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch7 + worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch8 config_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\ElasticSearch config_options: @@ -53,7 +53,7 @@ pimcore_ecommerce_framework: tenants: : enabled: true - worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch7 + worker_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Worker\ElasticSearch\DefaultElasticSearch8 config_id: Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\ElasticSearch config_options: diff --git a/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/README.md b/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/README.md index b7fa247b704..3047807494b 100644 --- a/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/README.md +++ b/doc/Development_Documentation/10_E-Commerce_Framework/05_Index_Service/01_Product_Index_Configuration/07_Elastic_Search/README.md @@ -1,12 +1,9 @@ # Special Aspects for Elasticsearch Basically Elasticsearch worker works as described in the [optimized architecture](../README.md). -Currently, Elasticsearch 7 (deprecated) and Elasticsearch 8 are supported. +Currently, Elasticsearch 8 is supported. ## Installation -### Elasticsearch 7 (deprecated) -To work properly Pimcore requires the Elasticsearch bindings, install them with: `composer require elasticsearch/elasticsearch`. - ### Elasticsearch 8 To work properly Pimcore requires the Elasticsearch client, install them with: `composer require pimcore/elasticsearch-client`. diff --git a/doc/Development_Documentation/23_Installation_and_Upgrade/07_Updating_Pimcore/11_Preparing_for_V11.md b/doc/Development_Documentation/23_Installation_and_Upgrade/07_Updating_Pimcore/11_Preparing_for_V11.md index 6d8fc903fed..6f28d700612 100644 --- a/doc/Development_Documentation/23_Installation_and_Upgrade/07_Updating_Pimcore/11_Preparing_for_V11.md +++ b/doc/Development_Documentation/23_Installation_and_Upgrade/07_Updating_Pimcore/11_Preparing_for_V11.md @@ -75,3 +75,5 @@ - Use `Pimcore\Db\Helper::queryIgnoreError()` instead of `queryIgnoreError()` - Use `Pimcore\Db\Helper::selectAndDeleteWhere()` instead of `selectAndDeleteWhere()` - Use `Pimcore\Db\Helper::escapeLike()` instead of `escapeLike()` + +- [Ecommerce] Switch to ElasticSearch8 implementations in case you are using elasticsearch indices. \ No newline at end of file diff --git a/doc/Development_Documentation/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md b/doc/Development_Documentation/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md index 6b0437afd6b..d084a7b6968 100644 --- a/doc/Development_Documentation/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md +++ b/doc/Development_Documentation/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md @@ -108,7 +108,9 @@ Please make sure to set your preferred storage location ***before*** migration. - `EcommerceFrameworkBundle\Tracking\TrackingManager` requires session from request stack. - `Element\Service::getValidKey()` strips all control/unassigned, invalid and some more special (e.g. tabs, line-breaks, form-feed & vertical whitespace) characters. - [Data Objects]: Removed setter functions for calculated values, since they weren´t used anyway. - +- [Ecommerce] Elasticsearch 7 support was removed +- [Ecommerce] Config option `es_client_params` in `index_service` was removed + ## 10.6.0 - [AreabrickManagerInterface] The `enable`, `disable`, `isEnabled` and `getState` methods of `Pimcore\Extension\Document\Areabrick\AreabrickManagerInterface` are deprecated as maintaining state of extensions is deprecated. This impacts `\Pimcore\Document\Editable\EditableHandler::isBrickEnabled()` method which is also deprecated. - [Twig] Pimcore now requires the `twig/extra-bundle` which eases the usage of Twig's "extra" extensions. diff --git a/lib/Console/Traits/ParallelizationBase.php b/lib/Console/Traits/ParallelizationBase.php index 65208760a8e..2d2c2815643 100644 --- a/lib/Console/Traits/ParallelizationBase.php +++ b/lib/Console/Traits/ParallelizationBase.php @@ -46,7 +46,7 @@ public function execute(InputInterface $input, OutputInterface $output): int } foreach ($items as $item) { - $this->runSingleCommand(trim($item), $input, $output); + $this->runSingleCommand(trim((string)$item), $input, $output); } //Method executed after executing all the items diff --git a/lib/Image/Adapter/Imagick.php b/lib/Image/Adapter/Imagick.php index de5b8878470..6ce1a74a7e9 100644 --- a/lib/Image/Adapter/Imagick.php +++ b/lib/Image/Adapter/Imagick.php @@ -325,7 +325,6 @@ private function hasAlphaChannel(): bool for ($i = 0; $i < $width; $i++) { for ($j = 0; $j < $height; $j++) { $pixel = $this->resource->getImagePixelColor($i, $j); - // @phpstan-ignore-next-line - phpstan expects bool, but actually doc says int $color = $pixel->getColor(1); // get the real alpha not just 1/0 if ($color['a'] < 1) { // if there's an alpha pixel, return true return true; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index df49f636778..a935e3d7fa1 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -195,57 +195,3 @@ parameters: count: 1 path: models/Document/Hardlink/Wrapper/Snippet.php - - - message: "#^Parameter \\#1 \\$children of method Pimcore\\\\Model\\\\DataObject\\\\AbstractObject\\:\\:setChildren\\(\\) expects array\\\\|null, array\\ given\\.$#" - count: 1 - path: models/Element/Service.php - - - - message: "#^Class Elasticsearch\\\\Client not found\\.$#" - count: 1 - path: bundles/EcommerceFrameworkBundle/IndexService/ProductList/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^PHPDoc tag (.*) contains unknown class Elasticsearch\\\\Client\\.$#" - count: 1 - path: bundles/EcommerceFrameworkBundle/IndexService/ProductList/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^Call to method (.*) on an unknown class Elasticsearch\\\\Client\\.$#" - count: 2 - path: bundles/EcommerceFrameworkBundle/IndexService/ProductList/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^Property (.*) has unknown class Elasticsearch\\\\Client as its type\\.$#" - count: 1 - path: bundles/EcommerceFrameworkBundle/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^(.*) Elasticsearch\\\\Common\\\\Exceptions\\\\Missing404Exception not found\\.$#" - count: 2 - path: bundles/EcommerceFrameworkBundle/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^Method (.*) has invalid return type Elasticsearch\\\\Client\\.$#" - count: 1 - path: bundles/EcommerceFrameworkBundle/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^Call to method (.*) on an unknown class Elasticsearch\\\\Client\\.$#" - count: 26 - path: bundles/EcommerceFrameworkBundle/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^Call to static method (.*) on an unknown class Elasticsearch\\\\ClientBuilder\\.$#" - count: 1 - path: bundles/EcommerceFrameworkBundle/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^PHPDoc tag \\@throws with type Elasticsearch\\\\Common\\\\Exceptions\\\\BadRequest400Exception\\|Elasticsearch\\\\Common\\\\Exceptions\\\\NoNodesAvailableException is not subtype of Throwable$#" - count: 2 - path: bundles/EcommerceFrameworkBundle/IndexService/Worker/ElasticSearch/AbstractElasticSearch.php - - - - message: "#^PHPDoc type Elastic\\\\Elasticsearch\\\\Client\\|null of property Pimcore\\\\Bundle\\\\EcommerceFrameworkBundle\\\\IndexService\\\\Worker\\\\ElasticSearch\\\\DefaultElasticSearch8\\:\\:\\$elasticSearchClient is not covariant with PHPDoc type Elasticsearch\\\\Client\\|null of overridden property Pimcore\\\\Bundle\\\\EcommerceFrameworkBundle\\\\IndexService\\\\Worker\\\\ElasticSearch\\\\AbstractElasticSearch\\:\\:\\$elasticSearchClient\\.$#" - count: 1 - path: bundles/EcommerceFrameworkBundle/IndexService/Worker/ElasticSearch/DefaultElasticSearch8.php diff --git a/tests/Support/Helper/Pimcore.php b/tests/Support/Helper/Pimcore.php index 0e556392857..ccde36c7151 100644 --- a/tests/Support/Helper/Pimcore.php +++ b/tests/Support/Helper/Pimcore.php @@ -37,8 +37,6 @@ class Pimcore extends Module\Symfony { - protected static ?ContainerInterface $testServiceContainer = null; - protected array $groups = []; public function __construct(ModuleContainer $moduleContainer, $config = null) @@ -81,20 +79,6 @@ public function getContainer(): ContainerInterface return $this->kernel->getContainer(); } - /** - * - * @throws \Exception - */ - public function grabService(string $serviceId): ?object - { - if (empty(self::$testServiceContainer)) { - $container = $this->getContainer(); - self::$testServiceContainer = $container->has('test.service_container') ? $container->get('test.service_container') : $container; - } - - return self::$testServiceContainer->get($serviceId); - } - public function _initialize(): void { // don't initialize the kernel multiple times if running multiple suites @@ -134,6 +118,7 @@ protected function initializeKernel(): void // dispatch kernel booted event - will be used from services which need to reset state between tests $this->kernel->getContainer()->get('event_dispatcher')->dispatch(new GenericEvent(), TestEvents::KERNEL_BOOTED); + } protected function setupPimcoreDirectories(): void @@ -296,6 +281,10 @@ protected function purgeClassDirectory(): void public function _before(TestInterface $test): void { + //need to load initialize that service first, before module/symfony does its magic + //related to https://github.com/pimcore/pimcore/pull/10331 + $this->grabService(\Pimcore\Helper\LongRunningHelper::class); + parent::_before($test); $this->groups = $test->getMetadata()->getGroups(); @@ -328,7 +317,7 @@ public function unsetAdminMode(): void DataObject\Localizedfield::setGetFallbackValues(true); } - public function makeHtmlSnapshot($name = null) + public function makeHtmlSnapshot(?string $name = null): void { // TODO: Implement makeHtmlSnapshot() method. }