hits = $hits; $this->scores = $scores; $this->options = $options; $this->groupedByModule = $groupedByModule; $this->searchTime = $searchTime; $this->total = $total; if ($this->scores !== null && count($hits) !== count($scores)) { throw new InvalidArgumentException('The sizes of $hits and $scores must match.'); } } /** * Returns the results. * * Note that the structure of the results depends whether of not they have been nested by module or not. * * @return array */ public function getHits(): array { return $this->hits; } /** * Fetches the results (originally just module->id) as Beans. * * @return array * @throws Exception * @see getHits() */ public function getHitsAsBeans(): array { $searchHits = $this->hits; $parsed = []; foreach ($searchHits as $module => $beans) { foreach ((array)$beans as $bean) { $obj = BeanFactory::getBean($module, $bean); // if a search found a bean but suitecrm does not, it could happens // maybe the bean is deleted but elsasticsearch is not re-indexing yet. // so at this point we trying to rebuild the index and try again to get bean: if (!$obj) { ElasticSearch\ElasticSearchIndexer::repairElasticsearchIndex(); $obj = BeanFactory::getBean($module, $bean); } if (!$obj) { throw new Exception('Error retrieving bean: ' . $module . ' [' . $bean . ']'); } $obj->load_relationships(); $fieldDefs = $obj->getFieldDefinitions(); $parsed[$module][] = $this->updateFieldDefLinks($obj, $fieldDefs); } } return $parsed; } /** * * @param SugarBean $obj * @param array $fieldDefs * @return SugarBean */ protected function updateFieldDefLinks(SugarBean $obj, array $fieldDefs): SugarBean { foreach ($fieldDefs as $fieldDef) { if (isset($obj->{$fieldDef['name']})) { $obj = $this->updateObjLinks($obj, $fieldDef); } } return $obj; } /** * Update related links in a bean to show it on results page * * @param SugarBean $obj * @param array $fieldDef * @return SugarBean */ protected function updateObjLinks(SugarBean $obj, array $fieldDef): SugarBean { if (isset($fieldDef['link']) && !empty($fieldDef['id_name']) && $fieldDef['type'] === 'relate') { $relId = $this->getRelatedId($obj, $fieldDef['id_name'], $fieldDef['link']); if (!empty($relId)) { $obj->{$fieldDef['name']} = $this->getLink( $obj->{$fieldDef['name']}, $fieldDef['module'], $relId, 'DetailView' ); } } elseif ($fieldDef['name'] === 'name') { $obj->{$fieldDef['name']} = $this->getLink( $obj->{$fieldDef['name']}, $obj->module_name, $obj->id, 'DetailView' ); } return $obj; } /** * resolve related record ID * * @param SugarBean $obj * @param string $idName * @param string $link * @return null|string */ protected function getRelatedId(SugarBean $obj, string $idName, string $link): string { $relField = $idName; if (isset($obj->$link)) { $relId = $obj->$link->getFocus()->$relField; if (is_object($relId)) { if (method_exists($relId, "getFocus")) { $relId = $relId->getFocus()->id; } else { $relId = null; } } } elseif (isset($obj->$relField)) { $relId = $obj->$relField; } else { $relId = null; LoggerManager::getLogger()->warn('Unresolved related ID for field: ' . $relField); } if (!$relId) { $relId = ''; } return $relId; } /** * * @param string $label * @param string $module * @param string $record * @param string $action * @return string * @global array $sugar_config */ protected function getLink(string $label, string $module, string $record, string $action): string { global $sugar_config; return "{$label}"; } /** * Returns an arbitrary scores defining how much related a hit is to the query. * * @return array */ public function getScores(): ?array { return $this->scores; } /** * Returns the total number of hits (without pagination). * * @return int */ public function getTotal(): ?int { return $this->total; } /** * @return array */ public function getOptions(): ?array { return $this->options; } /** * @param string $key * * @return array */ public function getOption(string $key): array { return $this->options[$key]; } /** * Time in seconds it took to perform the search. * * @return float */ public function getSearchTime(): ?float { return $this->searchTime; } /** * @return bool */ public function isGroupedByModule(): bool { return $this->groupedByModule; } }