xref: /dokuwiki/inc/Search/Index/MemoryIndex.php (revision 8ed350114c28d737f70b07d31d3945e1fab55bb9)
1<?php
2
3namespace dokuwiki\Search\Index;
4
5use dokuwiki\Search\Exception\IndexWriteException;
6
7/**
8 * Access to a single index file
9 *
10 * Access using this class always happens by loading the full index into memory.
11 * All modifications need to be explicitly made permanent using the save() method.
12 * Should be used for small indexes that receive many changes at once.
13 */
14class MemoryIndex extends AbstractIndex
15{
16
17    /** @var string the raw data lines of the index, no newlines */
18    protected $data;
19
20    /**
21     * Loads the full contents of the index into memory
22     *
23     * @inheritdoc
24     */
25    public function __construct($idx, $suffix = '')
26    {
27        parent::__construct($idx, $suffix);
28
29        $this->data = [];
30        if (!file_exists($this->filename)) return;
31        $this->data = file($this->filename, FILE_IGNORE_NEW_LINES);
32
33    }
34
35    /** @inheritdoc */
36    public function changeRow($rid, $value)
37    {
38        if ($rid > count($this->data)) {
39            $this->data = array_pad($this->data, $rid, '');
40        }
41        $this->data[$rid] = $value;
42    }
43
44    /** @inheritdoc */
45    public function retrieveRow($rid)
46    {
47        if (isset($this->data[$rid])) return $this->data[$rid];
48        return '';
49    }
50
51    /** @inheritdoc */
52    public function getRowIDs($values)
53    {
54        $values = array_map('trim', $values);
55        $values = array_fill_keys($values, 1); // easier access as associative array
56
57        $result = [];
58        $count = count($this->data);
59        for ($ln = 0; $ln < $count; $ln++) {
60            $line = $this->data[$ln];
61            if (isset($values[$line])) {
62                $result[$line] = $ln;
63                unset($values[$line]);
64            }
65        }
66
67        // if there are still values, they have not been found and will be appended
68        foreach (array_keys($values) as $value) {
69            $this->data[] = $value;
70            $result[$value] = $ln++;
71        }
72
73        return $result;
74    }
75
76    /**
77     * Save the changed index back to its file
78     *
79     * @throws IndexWriteException
80     */
81    public function save()
82    {
83        global $conf;
84
85        $tempname = $this->filename . '.tmp';
86
87        $fh = @fopen($tempname, 'w');
88        if (!$fh) {
89            throw new IndexWriteException("Failed to write $tempname");
90        }
91        fwrite($fh, implode("\n", $this->data));
92        if (!empty($lines)) {
93            fwrite($fh, "\n");
94        }
95        fclose($fh);
96
97        if ($conf['fperm']) {
98            chmod($tempname, $conf['fperm']);
99        }
100
101        if (!io_rename($tempname, $this->filename)) {
102            throw new IndexWriteException("Failed to write {$this->filename}");
103        }
104    }
105
106}
107