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