![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-search/Model/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\Search\Model; use Magento\Search\Api\SynonymAnalyzerInterface; /** * SynonymAnalyzer responsible for search of synonyms matching a word or a phrase. */ class SynonymAnalyzer implements SynonymAnalyzerInterface { /** * @var SynonymReader $synReaderModel */ protected $synReaderModel; /** * Constructor * * @param SynonymReader $synReader */ public function __construct(SynonymReader $synReader) { $this->synReaderModel = $synReader; } /** * Returns an array of arrays consisting of the synonyms found for each word in the input phrase * * For phrase: "Elizabeth is the English queen" correct output is an array of arrays containing synonyms for each * word in the phrase: * * [ * 0 => [ 0 => "elizabeth" ], * 1 => [ 0 => "is" ], * 2 => [ 0 => "the" ], * 3 => [ 0 => "british", 1 => "english" ], * 4 => [ 0 => "queen", 1 => "monarch" ] * ] * * @param string $phrase * @return array * @throws \Magento\Framework\Exception\LocalizedException */ public function getSynonymsForPhrase($phrase) { $result = []; if ($phrase === null || empty(trim($phrase))) { return $result; } $synonymGroups = $this->getSynonymGroupsByPhrase($phrase); // Replace multiple spaces in a row with the only one space $phrase = preg_replace("/ {2,}/", " ", $phrase); // Go through every returned record looking for presence of the actual phrase. If there were no matching // records found in DB then create a new entry for it in the returned array $words = explode(' ', $phrase); foreach ($words as $offset => $word) { $synonyms = [$word]; if ($synonymGroups) { $pattern = $this->getSearchPattern(\array_slice($words, $offset)); $position = $this->findInArray($pattern, $synonymGroups); if ($position !== null) { $synonyms = explode(',', $synonymGroups[$position] ?? ''); } } $result[] = $synonyms; } return $result; } /** * Helper method to find the matching of $pattern to $synonymGroupsToExamine. * If matches, the particular array index is returned. * Otherwise null will be returned. * * @param string $pattern * @param array $synonymGroupsToExamine * @return int|null */ private function findInArray(string $pattern, array $synonymGroupsToExamine) { $position = 0; foreach ($synonymGroupsToExamine as $synonymGroup) { $matchingResultCode = preg_match($pattern, $synonymGroup ?? ''); if ($matchingResultCode === 1) { return $position; } $position++; } return null; } /** * Returns a regular expression to search for synonyms of the phrase represented as the list of words. * * Returned pattern contains expression to search for a part of the phrase from the beginning. * * For example, in the phrase "Elizabeth is the English queen" with subset from the very first word, * the method will build an expression which looking for synonyms for all these patterns: * - Elizabeth is the English queen * - Elizabeth is the English * - Elizabeth is the * - Elizabeth is * - Elizabeth * * For the same phrase on the second iteration with the first word "is" it will match for these synonyms: * - is the English queen * - is the English * - is the * - is * * The pattern looking for exact match and will not find these phrases as synonyms: * - Is there anybody in the room? * - Is the English is most popular language? * - Is the English queen Elizabeth? * * Take into account that returned pattern expects that data will be represented as comma-separated value. * * @param array $words * @return string */ private function getSearchPattern(array $words): string { $patterns = []; for ($lastItem = count($words); $lastItem > 0; $lastItem--) { $safeRegexWords = array_map(function ($word) { return preg_quote($word, '/'); }, $words); $phrase = implode("\s+", \array_slice($safeRegexWords, 0, $lastItem)); $patterns[] = '^' . $phrase . ','; $patterns[] = ',' . $phrase . ','; $patterns[] = ',' . $phrase . '$'; } $pattern = '/' . implode('|', $patterns) . '/i'; return $pattern; } /** * Get all synonym groups for the phrase * * Returns an array of synonyms which are represented as comma-separated value for each item in the list * * @param string $phrase * @return string[] * @throws \Magento\Framework\Exception\LocalizedException */ private function getSynonymGroupsByPhrase(string $phrase): array { $result = []; /** @var array $synonymGroups */ $synonymGroups = $this->synReaderModel->loadByPhrase($phrase)->getData(); foreach ($synonymGroups as $row) { $result[] = $row['synonyms']; } return $result; } }