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