1d92c078cSAndreas Gohr<?php 2d92c078cSAndreas Gohr 3d92c078cSAndreas Gohrnamespace dokuwiki\Search\Collection; 4d92c078cSAndreas Gohr 5d92c078cSAndreas Gohruse dokuwiki\Search\Exception\IndexAccessException; 621fbd01bSAndreas Gohruse dokuwiki\Search\Exception\IndexIntegrityException; 7d92c078cSAndreas Gohruse dokuwiki\Search\Exception\IndexLockException; 8d92c078cSAndreas Gohruse dokuwiki\Search\Exception\IndexWriteException; 9d92c078cSAndreas Gohr 10d92c078cSAndreas Gohr/** 11d92c078cSAndreas Gohr * Abstract collection for direct 1:1 entity-token mappings 12d92c078cSAndreas Gohr * 13d92c078cSAndreas Gohr * In a direct collection each entity has exactly one token stored at the entity's position 14d92c078cSAndreas Gohr * in the token index (entity.RID === token.RID). No frequency or reverse indexes are used. 15d92c078cSAndreas Gohr * 16d92c078cSAndreas Gohr * Example: each page has exactly one title. 17d92c078cSAndreas Gohr * 18d92c078cSAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 19d92c078cSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 20d92c078cSAndreas Gohr */ 21d92c078cSAndreas Gohrabstract class DirectCollection extends AbstractCollection 22d92c078cSAndreas Gohr{ 2321fbd01bSAndreas Gohr /** @inheritdoc */ 2421fbd01bSAndreas Gohr public function checkIntegrity(): void 2521fbd01bSAndreas Gohr { 2621fbd01bSAndreas Gohr $entityIndex = $this->getEntityIndex(); 27*9369b4a9SAndreas Gohr $tokenIndex = $this->getTokenIndex(); 2821fbd01bSAndreas Gohr 2921fbd01bSAndreas Gohr if ($entityIndex->exists() && $tokenIndex->exists()) { 3021fbd01bSAndreas Gohr $ec = count($entityIndex); 3121fbd01bSAndreas Gohr $tc = count($tokenIndex); 3221fbd01bSAndreas Gohr if ($ec !== $tc) { 3321fbd01bSAndreas Gohr throw new IndexIntegrityException( 3421fbd01bSAndreas Gohr "Entity count ($ec) != token count ($tc)" 3521fbd01bSAndreas Gohr ); 3621fbd01bSAndreas Gohr } 3721fbd01bSAndreas Gohr } 3821fbd01bSAndreas Gohr } 3921fbd01bSAndreas Gohr 40d92c078cSAndreas Gohr /** 41d92c078cSAndreas Gohr * Store a single token for the given entity 42d92c078cSAndreas Gohr * 43d92c078cSAndreas Gohr * Takes the first token from the list and writes it directly at the entity's position 44d92c078cSAndreas Gohr * in the token index. An empty list stores an empty string. 45d92c078cSAndreas Gohr * 46d92c078cSAndreas Gohr * @param string $entity The name of the entity 47d92c078cSAndreas Gohr * @param string[] $tokens The list of tokens (only the first is used) 4883b3acccSAndreas Gohr * @return static 49d92c078cSAndreas Gohr * @throws IndexLockException 50d92c078cSAndreas Gohr * @throws IndexAccessException 51d92c078cSAndreas Gohr * @throws IndexWriteException 52d92c078cSAndreas Gohr */ 5383b3acccSAndreas Gohr public function addEntity(string $entity, array $tokens): static 54d92c078cSAndreas Gohr { 55d92c078cSAndreas Gohr if (!$this->isWritable) { 56d92c078cSAndreas Gohr throw new IndexLockException('Indexes not locked. Forgot to call lock()?'); 57d92c078cSAndreas Gohr } 58d92c078cSAndreas Gohr 59d92c078cSAndreas Gohr $entityIndex = $this->getEntityIndex(); 60d92c078cSAndreas Gohr $entityId = $entityIndex->accessCachedValue($entity); 61d92c078cSAndreas Gohr 62d92c078cSAndreas Gohr $token = $tokens[0] ?? ''; 63*9369b4a9SAndreas Gohr $tokenIndex = $this->getTokenIndex(); 64d92c078cSAndreas Gohr $tokenIndex->changeRow($entityId, $token); 65d92c078cSAndreas Gohr $tokenIndex->save(); 6683b3acccSAndreas Gohr 6783b3acccSAndreas Gohr return $this; 68d92c078cSAndreas Gohr } 69d92c078cSAndreas Gohr 70d92c078cSAndreas Gohr /** 71d92c078cSAndreas Gohr * Get the token stored for the given entity 72d92c078cSAndreas Gohr * 73d92c078cSAndreas Gohr * @param string $entity The name of the entity 74d92c078cSAndreas Gohr * @return string The stored token, or empty string if none 75d92c078cSAndreas Gohr * @throws IndexAccessException 76d92c078cSAndreas Gohr * @throws IndexLockException 77d92c078cSAndreas Gohr * @throws IndexWriteException 78d92c078cSAndreas Gohr */ 79d92c078cSAndreas Gohr public function getToken(string $entity): string 80d92c078cSAndreas Gohr { 81d92c078cSAndreas Gohr $entityIndex = $this->getEntityIndex(); 82d92c078cSAndreas Gohr $entityId = $entityIndex->accessCachedValue($entity); 83d92c078cSAndreas Gohr 84*9369b4a9SAndreas Gohr $tokenIndex = $this->getTokenIndex(); 85d92c078cSAndreas Gohr return $tokenIndex->retrieveRow($entityId); 86d92c078cSAndreas Gohr } 87d92c078cSAndreas Gohr 886734bb8cSAndreas Gohr /** @inheritdoc */ 896734bb8cSAndreas Gohr public function resolveTokenFrequencies(int $group, array $tokenIds): array 906734bb8cSAndreas Gohr { 916734bb8cSAndreas Gohr // In a DirectCollection, token RID = entity RID, frequency is always 1 926734bb8cSAndreas Gohr $result = []; 936734bb8cSAndreas Gohr foreach ($tokenIds as $tokenId) { 946734bb8cSAndreas Gohr $result[$tokenId] = [$tokenId => 1]; 956734bb8cSAndreas Gohr } 966734bb8cSAndreas Gohr return $result; 976734bb8cSAndreas Gohr } 986734bb8cSAndreas Gohr 996734bb8cSAndreas Gohr /** @inheritdoc */ 1006734bb8cSAndreas Gohr public function getEntitiesWithData(): array 1016734bb8cSAndreas Gohr { 1026734bb8cSAndreas Gohr $entityIndex = $this->getEntityIndex(); 103*9369b4a9SAndreas Gohr $tokenIndex = $this->getTokenIndex(); 1046734bb8cSAndreas Gohr 1056734bb8cSAndreas Gohr $entities = []; 1066734bb8cSAndreas Gohr foreach ($tokenIndex as $entityId => $token) { 1076734bb8cSAndreas Gohr if ($token === '') continue; 1086734bb8cSAndreas Gohr $name = $entityIndex->retrieveRow($entityId); 1096734bb8cSAndreas Gohr if ($name !== '') { 1106734bb8cSAndreas Gohr $entities[] = $name; 1116734bb8cSAndreas Gohr } 1126734bb8cSAndreas Gohr } 1136734bb8cSAndreas Gohr return $entities; 1146734bb8cSAndreas Gohr } 1156734bb8cSAndreas Gohr 116d92c078cSAndreas Gohr /** 117d92c078cSAndreas Gohr * Not actually used, because we override addEntity() to directly write the token. 118d92c078cSAndreas Gohr * @inheritdoc 119d92c078cSAndreas Gohr */ 120d92c078cSAndreas Gohr protected function countTokens(array $tokens): array 121d92c078cSAndreas Gohr { 122d92c078cSAndreas Gohr $token = $tokens[0] ?? ''; 123d92c078cSAndreas Gohr return [$token => 1]; 124d92c078cSAndreas Gohr } 125d92c078cSAndreas Gohr} 126