xref: /dokuwiki/inc/Search/Collection/DirectCollection.php (revision 6734bb8cef71e8b4af23e627d4db5430304d55a2)
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