1<?php 2 3namespace dokuwiki\Search\Collection; 4 5use dokuwiki\Search\Exception\IndexAccessException; 6use dokuwiki\Search\Exception\IndexLockException; 7use dokuwiki\Search\Exception\IndexWriteException; 8 9/** 10 * Abstract collection for direct 1:1 entity-token mappings 11 * 12 * In a direct collection each entity has exactly one token stored at the entity's position 13 * in the token index (entity.RID === token.RID). No frequency or reverse indexes are used. 14 * 15 * Example: each page has exactly one title. 16 * 17 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 18 * @author Andreas Gohr <andi@splitbrain.org> 19 */ 20abstract class DirectCollection extends AbstractCollection 21{ 22 /** 23 * Store a single token for the given entity 24 * 25 * Takes the first token from the list and writes it directly at the entity's position 26 * in the token index. An empty list stores an empty string. 27 * 28 * @param string $entity The name of the entity 29 * @param string[] $tokens The list of tokens (only the first is used) 30 * @return static 31 * @throws IndexLockException 32 * @throws IndexAccessException 33 * @throws IndexWriteException 34 */ 35 public function addEntity(string $entity, array $tokens): static 36 { 37 if (!$this->isWritable) { 38 throw new IndexLockException('Indexes not locked. Forgot to call lock()?'); 39 } 40 41 $entityIndex = $this->getEntityIndex(); 42 $entityId = $entityIndex->accessCachedValue($entity); 43 44 $token = $tokens[0] ?? ''; 45 $tokenIndex = $this->getTokenIndex(0); 46 $tokenIndex->changeRow($entityId, $token); 47 $tokenIndex->save(); 48 49 return $this; 50 } 51 52 /** 53 * Get the token stored for the given entity 54 * 55 * @param string $entity The name of the entity 56 * @return string The stored token, or empty string if none 57 * @throws IndexAccessException 58 * @throws IndexLockException 59 * @throws IndexWriteException 60 */ 61 public function getToken(string $entity): string 62 { 63 $entityIndex = $this->getEntityIndex(); 64 $entityId = $entityIndex->accessCachedValue($entity); 65 66 $tokenIndex = $this->getTokenIndex(0); 67 return $tokenIndex->retrieveRow($entityId); 68 } 69 70 /** @inheritdoc */ 71 public function resolveTokenFrequencies(int $group, array $tokenIds): array 72 { 73 // In a DirectCollection, token RID = entity RID, frequency is always 1 74 $result = []; 75 foreach ($tokenIds as $tokenId) { 76 $result[$tokenId] = [$tokenId => 1]; 77 } 78 return $result; 79 } 80 81 /** @inheritdoc */ 82 public function getEntitiesWithData(): array 83 { 84 $entityIndex = $this->getEntityIndex(); 85 $tokenIndex = $this->getTokenIndex(0); 86 87 $entities = []; 88 foreach ($tokenIndex as $entityId => $token) { 89 if ($token === '') continue; 90 $name = $entityIndex->retrieveRow($entityId); 91 if ($name !== '') { 92 $entities[] = $name; 93 } 94 } 95 return $entities; 96 } 97 98 /** 99 * Not actually used, because we override addEntity() to directly write the token. 100 * @inheritdoc 101 */ 102 protected function countTokens(array $tokens): array 103 { 104 $token = $tokens[0] ?? ''; 105 return [$token => 1]; 106 } 107} 108