From 122eac88e9638bdc7d6459971dc0f30b497ba4fc Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Thu, 6 Jun 2024 13:51:38 +0300 Subject: [PATCH 01/16] UHF-10176: make the annif field non translatable --- conf/cmi/field.field.node.news_item.field_annif_keywords.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/cmi/field.field.node.news_item.field_annif_keywords.yml b/conf/cmi/field.field.node.news_item.field_annif_keywords.yml index 21772cf59..fb462ad05 100644 --- a/conf/cmi/field.field.node.news_item.field_annif_keywords.yml +++ b/conf/cmi/field.field.node.news_item.field_annif_keywords.yml @@ -13,7 +13,7 @@ bundle: news_item label: 'Annif keywords' description: '' required: false -translatable: true +translatable: false default_value: { } default_value_callback: '' settings: From 12b677aec446dd5226154b6ac3dd7eea7609a0a2 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Thu, 6 Jun 2024 14:33:37 +0300 Subject: [PATCH 02/16] UHF-10176: only run the code for finnish for now --- .../custom/helfi_annif/src/KeywordManager.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/public/modules/custom/helfi_annif/src/KeywordManager.php b/public/modules/custom/helfi_annif/src/KeywordManager.php index 17ce34f29..e542315be 100644 --- a/public/modules/custom/helfi_annif/src/KeywordManager.php +++ b/public/modules/custom/helfi_annif/src/KeywordManager.php @@ -18,6 +18,8 @@ */ final class KeywordManager { + CONST array SUPPORTED_LANGUAGES = ['fi']; + /** * Taxonomy term storage. * @@ -76,6 +78,16 @@ private function isEntityProcessed(EntityInterface $entity) : bool { return isset($this->processedItems[$this->getEntityKey($entity)]); } + /** + * Check if entity language is in supported languages. + * + * @param EntityInterface $entity + * The entity. + */ + private function isSupportedLanguage(EntityInterface $entity) : bool { + return in_array($entity->language()->getId(), self::SUPPORTED_LANGUAGES); + } + /** * Queues keyword generation for single entity. * @@ -90,6 +102,8 @@ public function queueEntity(EntityInterface $entity, bool $overwriteExisting = F $this->isEntityProcessed($entity) || // Skip if entity does not support keywords. !$this->supportsKeywords($entity) || + // Skip if entity's language is not supported + !$this->isSupportedLanguage($entity) || // Skip if entity already has keywords. (!$overwriteExisting && $this->hasKeywords($entity)) ) { From 35bde8a1c37f1a5814834dcd860de9c6cc4b89f1 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 7 Jun 2024 11:35:26 +0300 Subject: [PATCH 03/16] UHF-10176: refactored a bit. Added target_langcode to allow fetching recommendations based on one language instead of having separate recommendations for all translations --- .../src/Plugin/Block/RecommendationsBlock.php | 10 +- .../helfi_annif/src/RecommendationManager.php | 109 +++++++++++------- 2 files changed, 77 insertions(+), 42 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php b/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php index 889257d49..21c58560d 100644 --- a/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php +++ b/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php @@ -66,7 +66,15 @@ public function build() : array { '#title' => $this->t('You might be interested in'), ]; - $recommendations = $this->recommendationManager->getRecommendations($node); + $recommendations = []; + try { + $recommendations = $this->recommendationManager + ->getRecommendations($node, 3, 'fi'); + } + catch(\Exception $exception){ + $this->logger->error($exception->getMessage()); + } + if (!$recommendations) { return $this->handleNoRecommendations($response); } diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index c17572b77..785a9a707 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -4,18 +4,16 @@ namespace Drupal\helfi_annif; +use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; +use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; -use Psr\Log\LoggerAwareInterface; -use Psr\Log\LoggerAwareTrait; /** * The recommendation manager. */ -class RecommendationManager implements LoggerAwareInterface { - - use LoggerAwareTrait; +class RecommendationManager { /** * The constructor. @@ -34,14 +32,59 @@ public function __construct( /** * Get recommendations for a node. * - * @param \Drupal\Core\Entity\EntityInterface $node + * @param EntityInterface $entity * The node. + * @param int $limit + * How many recommendations should be be returned. + * @param string|null $target_langcode + * Allow sharing the recommendations between all translations. * * @return array * Array of recommendations. + * + * @throws InvalidPluginDefinitionException + * @throws PluginNotFoundException + */ + public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = null): array { + $target_langcode = $target_langcode ?? $entity->language()->getId(); + $response = []; + + $results = $this->executeQuery($entity, $target_langcode); + if (!$results || !is_array($results)) { + return $response; + } + + $this->sortByCreatedAt($results); + $nids = array_column($results, 'nid'); + + $entities = $this->entityManager + ->getStorage($entity->getEntityTypeId()) + ->loadByProperties([ + 'nid' => $nids, + 'langcode' => $entity->language()->getId(), + 'status' => 1 + ]); + $entities = array_reverse($entities); + + return array_splice($entities,0, $limit); + } + + /** + * Execute the recommendation query. + * + * The recommendations are unified between the translations + * by always getting the results using the primary language recommendations. + * + * @param EntityInterface $entity + * The entity we want to suggest recommendations for. + * @param string $langcode + * Langcode which is used to filter results. + * + * @return array + * Database query result. */ - public function getRecommendations(EntityInterface $node): array { - // @todo #UHF-9964 exclude unwanted keywords and entities and refactor. + private function executeQuery(EntityInterface $entity, string $langcode) { + // @todo #UHF-9964 exclude unwanted keywords $query = " select n.nid, @@ -63,48 +106,32 @@ public function getRecommendations(EntityInterface $node): array { and nfd.created > :timestamp group by n.nid order by relevancy DESC - limit 3; + limit 10; "; - $response = []; - try { - $timestamp = strtotime("-1 year", time()); - $results = $this->connection - ->query($query, [ - ':nid' => $node->id(), - ':langcode' => $node->language()->getId(), - ':timestamp' => $timestamp, - ]) - ->fetchAll(); - } - catch (\Exception $e) { - $this->logger->error($e->getMessage()); - return $response; - } - - if (!$results || !is_array($results)) { - return $response; - } + $timestamp = strtotime("-1 year", time()); + return $this->connection + ->query($query, [ + ':nid' => $entity->id(), + ':langcode' => $langcode, + ':timestamp' => $timestamp, + ]) + ->fetchAll(); + } + /** + * Sort results by created time. + * + * @param array $results + * Entities to sort. + */ + private function sortByCreatedAt(array &$results) : void { usort($results, function ($a, $b) { if ($a->created == $b->created) { return 0; } return ($a->created > $b->created) ? -1 : 1; }); - $nids = array_column($results, 'nid'); - - try { - $response = $this->entityManager - ->getStorage($node->getEntityTypeId()) - ->loadMultiple($nids); - } - catch (\Exception $e) { - $this->logger->error($e->getMessage()); - return []; - } - - return $response; } } From 6695b7543ca9610b777e2394781925487aeb4694 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 7 Jun 2024 12:37:11 +0300 Subject: [PATCH 04/16] UHF-10176: cannot fetch nodes by loadbyproperties method since it is unable handle translations. Must get translations manually --- .../helfi_annif/src/RecommendationManager.php | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 785a9a707..8776df466 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -46,7 +46,8 @@ public function __construct( * @throws PluginNotFoundException */ public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = null): array { - $target_langcode = $target_langcode ?? $entity->language()->getId(); + $entity_langcode = $entity->language()->getId(); + $target_langcode = $target_langcode ?? $entity_langcode; $response = []; $results = $this->executeQuery($entity, $target_langcode); @@ -59,20 +60,25 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri $entities = $this->entityManager ->getStorage($entity->getEntityTypeId()) - ->loadByProperties([ - 'nid' => $nids, - 'langcode' => $entity->language()->getId(), - 'status' => 1 - ]); - $entities = array_reverse($entities); + ->loadMultiple($nids); - return array_splice($entities,0, $limit); + $results = []; + foreach($entities as $entity) { + if ($entity->hasTranslation($entity_langcode)) { + $results[] = $entity->getTranslation($entity_langcode); + } + if (count($results) >= 3) { + break; + } + } + + return $results; } /** * Execute the recommendation query. * - * The recommendations are unified between the translations + * The recommendations can be unified between the translations * by always getting the results using the primary language recommendations. * * @param EntityInterface $entity From 4667296179ff2ebf291fb4d055923667e62f9069 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 7 Jun 2024 12:56:55 +0300 Subject: [PATCH 05/16] UHF-10176: removed useless variable, use limit variable instead of hardcoded value --- .../modules/custom/helfi_annif/src/RecommendationManager.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 8776df466..476766af8 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -48,11 +48,10 @@ public function __construct( public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = null): array { $entity_langcode = $entity->language()->getId(); $target_langcode = $target_langcode ?? $entity_langcode; - $response = []; $results = $this->executeQuery($entity, $target_langcode); if (!$results || !is_array($results)) { - return $response; + return []; } $this->sortByCreatedAt($results); @@ -67,7 +66,7 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri if ($entity->hasTranslation($entity_langcode)) { $results[] = $entity->getTranslation($entity_langcode); } - if (count($results) >= 3) { + if (count($results) >= $limit) { break; } } From 95013045d49fca114729f8c44877f3373cba671d Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 7 Jun 2024 13:05:37 +0300 Subject: [PATCH 06/16] UHF-10176: code fixes --- .../custom/helfi_annif/src/KeywordManager.php | 6 +++--- .../src/Plugin/Block/RecommendationsBlock.php | 2 +- .../helfi_annif/src/RecommendationManager.php | 14 ++++++-------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/KeywordManager.php b/public/modules/custom/helfi_annif/src/KeywordManager.php index e542315be..e2198dbd3 100644 --- a/public/modules/custom/helfi_annif/src/KeywordManager.php +++ b/public/modules/custom/helfi_annif/src/KeywordManager.php @@ -18,7 +18,7 @@ */ final class KeywordManager { - CONST array SUPPORTED_LANGUAGES = ['fi']; + const array SUPPORTED_LANGUAGES = ['fi']; /** * Taxonomy term storage. @@ -81,7 +81,7 @@ private function isEntityProcessed(EntityInterface $entity) : bool { /** * Check if entity language is in supported languages. * - * @param EntityInterface $entity + * @param \Drupal\Core\Entity\EntityInterface $entity * The entity. */ private function isSupportedLanguage(EntityInterface $entity) : bool { @@ -102,7 +102,7 @@ public function queueEntity(EntityInterface $entity, bool $overwriteExisting = F $this->isEntityProcessed($entity) || // Skip if entity does not support keywords. !$this->supportsKeywords($entity) || - // Skip if entity's language is not supported + // Skip if entity's language is not supported. !$this->isSupportedLanguage($entity) || // Skip if entity already has keywords. (!$overwriteExisting && $this->hasKeywords($entity)) diff --git a/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php b/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php index 21c58560d..1ba6a66ac 100644 --- a/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php +++ b/public/modules/custom/helfi_annif/src/Plugin/Block/RecommendationsBlock.php @@ -71,7 +71,7 @@ public function build() : array { $recommendations = $this->recommendationManager ->getRecommendations($node, 3, 'fi'); } - catch(\Exception $exception){ + catch (\Exception $exception) { $this->logger->error($exception->getMessage()); } diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 476766af8..4502d856e 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -4,8 +4,6 @@ namespace Drupal\helfi_annif; -use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException; -use Drupal\Component\Plugin\Exception\PluginNotFoundException; use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -32,7 +30,7 @@ public function __construct( /** * Get recommendations for a node. * - * @param EntityInterface $entity + * @param \Drupal\Core\Entity\EntityInterface $entity * The node. * @param int $limit * How many recommendations should be be returned. @@ -42,10 +40,10 @@ public function __construct( * @return array * Array of recommendations. * - * @throws InvalidPluginDefinitionException - * @throws PluginNotFoundException + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ - public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = null): array { + public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = NULL): array { $entity_langcode = $entity->language()->getId(); $target_langcode = $target_langcode ?? $entity_langcode; @@ -62,7 +60,7 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri ->loadMultiple($nids); $results = []; - foreach($entities as $entity) { + foreach ($entities as $entity) { if ($entity->hasTranslation($entity_langcode)) { $results[] = $entity->getTranslation($entity_langcode); } @@ -80,7 +78,7 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri * The recommendations can be unified between the translations * by always getting the results using the primary language recommendations. * - * @param EntityInterface $entity + * @param \Drupal\Core\Entity\EntityInterface $entity * The entity we want to suggest recommendations for. * @param string $langcode * Langcode which is used to filter results. From 943f253b04c10d847653f30feb8e7a64300da6c2 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 7 Jun 2024 13:21:24 +0300 Subject: [PATCH 07/16] UHF-10176: check if entity is translatable before fetching translated entities --- .../custom/helfi_annif/src/RecommendationManager.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 4502d856e..62e447416 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -59,10 +59,14 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri ->getStorage($entity->getEntityTypeId()) ->loadMultiple($nids); + if (!$entity->getEntityType()->isTranslatable()) { + return array_splice($entities, 0, 3); + } + $results = []; foreach ($entities as $entity) { - if ($entity->hasTranslation($entity_langcode)) { - $results[] = $entity->getTranslation($entity_langcode); + if ($entity->hasTranslation($target_langcode)) { + $results[] = $entity->getTranslation($target_langcode); } if (count($results) >= $limit) { break; From 729fb24159822b9d3d6b4cc159220714dd8c5953 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 7 Jun 2024 13:31:30 +0300 Subject: [PATCH 08/16] UHF-10176: check thant entity can be translated --- .../modules/custom/helfi_annif/src/RecommendationManager.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 62e447416..660b04ebc 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -7,6 +7,7 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Entity\TranslatableInterface; /** * The recommendation manager. @@ -64,8 +65,9 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri } $results = []; + foreach ($entities as $entity) { - if ($entity->hasTranslation($target_langcode)) { + if ($entity instanceof TranslatableInterface && $entity->hasTranslation($target_langcode)) { $results[] = $entity->getTranslation($target_langcode); } if (count($results) >= $limit) { From 3c0960b82761f406e0d5e8f2552fc7a6b56bbe26 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 7 Jun 2024 13:47:17 +0300 Subject: [PATCH 09/16] UHF-10176: useless variable --- .../modules/custom/helfi_annif/src/RecommendationManager.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 660b04ebc..422b42c75 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -45,8 +45,7 @@ public function __construct( * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = NULL): array { - $entity_langcode = $entity->language()->getId(); - $target_langcode = $target_langcode ?? $entity_langcode; + $target_langcode = $target_langcode ?? $entity->language()->getId(); $results = $this->executeQuery($entity, $target_langcode); if (!$results || !is_array($results)) { @@ -65,7 +64,6 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri } $results = []; - foreach ($entities as $entity) { if ($entity instanceof TranslatableInterface && $entity->hasTranslation($target_langcode)) { $results[] = $entity->getTranslation($target_langcode); From ca6cd56e84d6ea52bb889edf6356cbacef2d8c4e Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Wed, 12 Jun 2024 08:47:23 +0300 Subject: [PATCH 10/16] UHF-10176: always fetch the recommendations by the original entity's langcode --- .../custom/helfi_annif/src/RecommendationManager.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 422b42c75..19bad1b23 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -36,7 +36,7 @@ public function __construct( * @param int $limit * How many recommendations should be be returned. * @param string|null $target_langcode - * Allow sharing the recommendations between all translations. + * Which translation to use to select the recommendations, null meaning the entity's translation. * * @return array * Array of recommendations. @@ -45,7 +45,8 @@ public function __construct( * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = NULL): array { - $target_langcode = $target_langcode ?? $entity->language()->getId(); + $entity_langcode = $entity->language()->getId(); + $target_langcode = $target_langcode ?? $entity_langcode; $results = $this->executeQuery($entity, $target_langcode); if (!$results || !is_array($results)) { @@ -65,8 +66,8 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri $results = []; foreach ($entities as $entity) { - if ($entity instanceof TranslatableInterface && $entity->hasTranslation($target_langcode)) { - $results[] = $entity->getTranslation($target_langcode); + if ($entity instanceof TranslatableInterface && $entity->hasTranslation($entity_langcode)) { + $results[] = $entity->getTranslation($entity_langcode); } if (count($results) >= $limit) { break; From 777837b3fc2fbc881f5142c7f3b303d53d2baad1 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Wed, 12 Jun 2024 15:11:34 +0300 Subject: [PATCH 11/16] UHF-10176: just get the correct keywords always and decide what to show on the block itself maybe --- .../custom/helfi_annif/src/KeywordManager.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/KeywordManager.php b/public/modules/custom/helfi_annif/src/KeywordManager.php index e2198dbd3..17ce34f29 100644 --- a/public/modules/custom/helfi_annif/src/KeywordManager.php +++ b/public/modules/custom/helfi_annif/src/KeywordManager.php @@ -18,8 +18,6 @@ */ final class KeywordManager { - const array SUPPORTED_LANGUAGES = ['fi']; - /** * Taxonomy term storage. * @@ -78,16 +76,6 @@ private function isEntityProcessed(EntityInterface $entity) : bool { return isset($this->processedItems[$this->getEntityKey($entity)]); } - /** - * Check if entity language is in supported languages. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity. - */ - private function isSupportedLanguage(EntityInterface $entity) : bool { - return in_array($entity->language()->getId(), self::SUPPORTED_LANGUAGES); - } - /** * Queues keyword generation for single entity. * @@ -102,8 +90,6 @@ public function queueEntity(EntityInterface $entity, bool $overwriteExisting = F $this->isEntityProcessed($entity) || // Skip if entity does not support keywords. !$this->supportsKeywords($entity) || - // Skip if entity's language is not supported. - !$this->isSupportedLanguage($entity) || // Skip if entity already has keywords. (!$overwriteExisting && $this->hasKeywords($entity)) ) { From 541fa48ee29c0b361921c05de2decbb08847e683 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Thu, 13 Jun 2024 09:16:52 +0300 Subject: [PATCH 12/16] UHF-10176: line length --- .../modules/custom/helfi_annif/src/RecommendationManager.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 19bad1b23..456ee129d 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -34,9 +34,10 @@ public function __construct( * @param \Drupal\Core\Entity\EntityInterface $entity * The node. * @param int $limit - * How many recommendations should be be returned. + * How many recommendations should be returned. * @param string|null $target_langcode - * Which translation to use to select the recommendations, null meaning the entity's translation. + * Which translation to use to select the recommendations, + * null uses the entity's translation. * * @return array * Array of recommendations. From 9eac5a54adf1c6add43829ac3eefc37ab1b73615 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Thu, 13 Jun 2024 16:04:43 +0300 Subject: [PATCH 13/16] UHF-10176: more efficient query by taking the destination and target langcodes into account directly. Fixed the order by in the query. --- .../helfi_annif/src/RecommendationManager.php | 106 ++++++++++++------ 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index 456ee129d..f9c667401 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -46,36 +46,26 @@ public function __construct( * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = NULL): array { - $entity_langcode = $entity->language()->getId(); - $target_langcode = $target_langcode ?? $entity_langcode; + $destination_langcode = $entity->language()->getId(); + $target_langcode = $target_langcode ?? $destination_langcode; - $results = $this->executeQuery($entity, $target_langcode); - if (!$results || !is_array($results)) { + $queryResult = $this->executeQuery($entity, $target_langcode, $destination_langcode, $limit); + if (!$queryResult || !is_array($queryResult)) { return []; } - $this->sortByCreatedAt($results); - $nids = array_column($results, 'nid'); + $this->sortByCreatedAt($queryResult); + $nids = array_column($queryResult, 'nid'); $entities = $this->entityManager ->getStorage($entity->getEntityTypeId()) ->loadMultiple($nids); - if (!$entity->getEntityType()->isTranslatable()) { - return array_splice($entities, 0, 3); - } - - $results = []; - foreach ($entities as $entity) { - if ($entity instanceof TranslatableInterface && $entity->hasTranslation($entity_langcode)) { - $results[] = $entity->getTranslation($entity_langcode); - } - if (count($results) >= $limit) { - break; - } - } + // Entity query returns the results sorted by nid in ascending order + // while the raw query's results are in correct order. + $entities = $this->sortEntitiesByQueryResult($entities, $queryResult); - return $results; + return $this->getTranslations($entities, $destination_langcode); } /** @@ -86,13 +76,17 @@ public function getRecommendations(EntityInterface $entity, int $limit = 3, stri * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity we want to suggest recommendations for. - * @param string $langcode - * Langcode which is used to filter results. + * @param string $target_langcode + * What language are we using as a base for the recommendations. + * @param string $destination_langcode + * What is the destination langcode. + * @param int $limit + * How many items to get. * * @return array * Database query result. */ - private function executeQuery(EntityInterface $entity, string $langcode) { + private function executeQuery(EntityInterface $entity, string $target_langcode, string $destination_langcode, int $limit) { // @todo #UHF-9964 exclude unwanted keywords $query = " select @@ -107,32 +101,33 @@ private function executeQuery(EntityInterface $entity, string $langcode) { field_annif_keywords_target_id from node__field_annif_keywords where entity_id = :nid and - langcode = :langcode) - and n.langcode = :langcode - and annif.langcode = :langcode - and nfd.langcode = :langcode + langcode = :target_langcode) + and n.langcode = :target_langcode + and annif.langcode = :destination_langcode + and nfd.langcode = :target_langcode and n.nid != :nid and nfd.created > :timestamp group by n.nid - order by relevancy DESC - limit 10; + order by count(n.nid) DESC + limit {$limit}; "; - $timestamp = strtotime("-1 year", time()); + // Cannot add :limit as parameter here, must be added directly to the query string above. return $this->connection ->query($query, [ ':nid' => $entity->id(), - ':langcode' => $langcode, - ':timestamp' => $timestamp, + ':target_langcode' => $target_langcode, + ':destination_langcode' => $destination_langcode, + ':timestamp' => strtotime("-1 year", time()), ]) ->fetchAll(); } /** - * Sort results by created time. + * Sort query result by created time. * * @param array $results - * Entities to sort. + * Query results to sort. */ private function sortByCreatedAt(array &$results) : void { usort($results, function ($a, $b) { @@ -143,4 +138,47 @@ private function sortByCreatedAt(array &$results) : void { }); } + /** + * Entity query changes the result sorting, it must be corrected afterward. + * + * @param array $entities + * Array of entities sorted by id. + * @param array $queryResult + * Array of query results sorted correctly + * + * @return array + * Correctly sorted array of entities. + */ + private function sortEntitiesByQueryResult(array $entities, array $queryResult) : array { + $results = []; + foreach ($queryResult as $result) { + if (!isset($entities[$result->nid])) { + continue; + } + $results[] = $entities[$result->nid]; + } + return $results; + } + + /** + * Get the translations for the recommended entities. + * + * @param array $entities + * Array of entities. + * @param string $destination_langcode + * Which translation to get. + * + * @return array + * Array of translated entities. + */ + private function getTranslations(array $entities, string $destination_langcode) : array { + $results = []; + foreach ($entities as $entity) { + if ($entity instanceof TranslatableInterface && $entity->hasTranslation($destination_langcode)) { + $results[] = $entity->getTranslation($destination_langcode); + } + } + return $results; + } + } From d1070e878950ea77fd03fc071f57660793ccda54 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Thu, 13 Jun 2024 16:08:49 +0300 Subject: [PATCH 14/16] UHF-10176: code fixes --- .../modules/custom/helfi_annif/src/RecommendationManager.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index f9c667401..c2698c1f5 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -112,7 +112,8 @@ private function executeQuery(EntityInterface $entity, string $target_langcode, limit {$limit}; "; - // Cannot add :limit as parameter here, must be added directly to the query string above. + // Cannot add :limit as parameter here, + // must be added directly to the query string above. return $this->connection ->query($query, [ ':nid' => $entity->id(), @@ -144,7 +145,7 @@ private function sortByCreatedAt(array &$results) : void { * @param array $entities * Array of entities sorted by id. * @param array $queryResult - * Array of query results sorted correctly + * Array of query results sorted correctly. * * @return array * Correctly sorted array of entities. From d806e42e857319e9576df69426e071f5ca1c1a06 Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 14 Jun 2024 08:37:42 +0300 Subject: [PATCH 15/16] UHF-10176: fallback to entity translation as target language if entity doesn't have proper content for the expected language --- .../modules/custom/helfi_annif/src/RecommendationManager.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index c2698c1f5..f595f26fc 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -48,6 +48,9 @@ public function __construct( public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = NULL): array { $destination_langcode = $entity->language()->getId(); $target_langcode = $target_langcode ?? $destination_langcode; + if (!$entity->hasTranslation($target_langcode)) { + $target_langcode = $destination_langcode; + } $queryResult = $this->executeQuery($entity, $target_langcode, $destination_langcode, $limit); if (!$queryResult || !is_array($queryResult)) { From 829dda71ae86b4877ac1851ca07185ef26eec69f Mon Sep 17 00:00:00 2001 From: rpnykanen Date: Fri, 14 Jun 2024 08:54:44 +0300 Subject: [PATCH 16/16] UHF-10176: prevent phpstan error --- public/modules/custom/helfi_annif/src/RecommendationManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/modules/custom/helfi_annif/src/RecommendationManager.php b/public/modules/custom/helfi_annif/src/RecommendationManager.php index f595f26fc..e3454c320 100644 --- a/public/modules/custom/helfi_annif/src/RecommendationManager.php +++ b/public/modules/custom/helfi_annif/src/RecommendationManager.php @@ -48,7 +48,7 @@ public function __construct( public function getRecommendations(EntityInterface $entity, int $limit = 3, string $target_langcode = NULL): array { $destination_langcode = $entity->language()->getId(); $target_langcode = $target_langcode ?? $destination_langcode; - if (!$entity->hasTranslation($target_langcode)) { + if ($entity instanceof TranslatableInterface && !$entity->hasTranslation($target_langcode)) { $target_langcode = $destination_langcode; }