1 <?php namespace BookStack\Entities\Tools;
3 use BookStack\Entities\EntityProvider;
4 use BookStack\Entities\Models\Entity;
5 use BookStack\Entities\Models\SearchTerm;
12 protected $searchTerm;
17 protected $entityProvider;
20 public function __construct(SearchTerm $searchTerm, EntityProvider $entityProvider)
22 $this->searchTerm = $searchTerm;
23 $this->entityProvider = $entityProvider;
28 * Index the given entity.
30 public function indexEntity(Entity $entity)
32 $this->deleteEntityTerms($entity);
33 $nameTerms = $this->generateTermArrayFromText($entity->name, 5 * $entity->searchFactor);
34 $bodyTerms = $this->generateTermArrayFromText($entity->getText() ?? '', 1 * $entity->searchFactor);
35 $terms = array_merge($nameTerms, $bodyTerms);
36 foreach ($terms as $index => $term) {
37 $terms[$index]['entity_type'] = $entity->getMorphClass();
38 $terms[$index]['entity_id'] = $entity->id;
40 $this->searchTerm->newQuery()->insert($terms);
44 * Index multiple Entities at once
45 * @param Entity[] $entities
47 protected function indexEntities(array $entities)
50 foreach ($entities as $entity) {
51 $nameTerms = $this->generateTermArrayFromText($entity->name, 5 * $entity->searchFactor);
52 $bodyTerms = $this->generateTermArrayFromText($entity->getText(), 1 * $entity->searchFactor);
53 foreach (array_merge($nameTerms, $bodyTerms) as $term) {
54 $term['entity_id'] = $entity->id;
55 $term['entity_type'] = $entity->getMorphClass();
60 $chunkedTerms = array_chunk($terms, 500);
61 foreach ($chunkedTerms as $termChunk) {
62 $this->searchTerm->newQuery()->insert($termChunk);
67 * Delete and re-index the terms for all entities in the system.
69 public function indexAllEntities()
71 $this->searchTerm->newQuery()->truncate();
73 foreach ($this->entityProvider->all() as $entityModel) {
74 $selectFields = ['id', 'name', $entityModel->textField];
75 $entityModel->newQuery()
77 ->select($selectFields)
78 ->chunk(1000, function ($entities) {
79 $this->indexEntities($entities);
85 * Delete related Entity search terms.
87 public function deleteEntityTerms(Entity $entity)
89 $entity->searchTerms()->delete();
93 * Create a scored term array from the given text.
95 protected function generateTermArrayFromText(string $text, int $scoreAdjustment = 1): array
97 $tokenMap = []; // {TextToken => OccurrenceCount}
98 $splitChars = " \n\t.,!?:;()[]{}<>`'\"";
99 $token = strtok($text, $splitChars);
101 while ($token !== false) {
102 if (!isset($tokenMap[$token])) {
103 $tokenMap[$token] = 0;
106 $token = strtok($splitChars);
110 foreach ($tokenMap as $token => $count) {
113 'score' => $count * $scoreAdjustment