diff options
author | Michael Hamann <michael@content-space.de> | 2013-01-26 02:26:17 -0800 |
---|---|---|
committer | Michael Hamann <michael@content-space.de> | 2013-01-26 02:26:17 -0800 |
commit | bcc1938ed0f7c97629d290070aec14b180e441ae (patch) | |
tree | 6cedd6a884abcc2a15d32cab487cc15ccaefb1b9 | |
parent | ba56222349781fd8e3938ab18127d46f3c1e0061 (diff) | |
parent | bc27f3e28790e9a25e9428ed275624578b3e9a2d (diff) | |
download | rpg-bcc1938ed0f7c97629d290070aec14b180e441ae.tar.gz rpg-bcc1938ed0f7c97629d290070aec14b180e441ae.tar.bz2 |
Merge pull request #159 from michitux/indexer
Indexer: Added page and meta value rename functions
-rw-r--r-- | _test/tests/inc/indexer_rename.test.php | 83 | ||||
-rw-r--r-- | inc/indexer.php | 123 |
2 files changed, 203 insertions, 3 deletions
diff --git a/_test/tests/inc/indexer_rename.test.php b/_test/tests/inc/indexer_rename.test.php new file mode 100644 index 000000000..d8c456f8e --- /dev/null +++ b/_test/tests/inc/indexer_rename.test.php @@ -0,0 +1,83 @@ +<?php +/** + * Test cases for the Doku_Indexer::renamePage and Doku_Indexer::renameMetaValue methods + */ +class indexer_rename_test extends DokuWikiTest { + /** @var Doku_Indexer $indexer */ + private $indexer; + + private $old_id = 'old_testid'; + + function setUp() { + parent::setUp(); + $this->indexer = idx_get_indexer(); + $this->indexer->clear(); + + saveWikiText($this->old_id, 'Old test content', 'Created old test page for indexer rename test'); + idx_addPage($this->old_id); + } + + function test_rename_to_new_page() { + $newid = 'new_id_1'; + + $oldpid = $this->indexer->getPID($this->old_id); + + $this->assertTrue($this->indexer->renamePage($this->old_id, $newid), 'Renaming the page to a new id failed'); + io_rename(wikiFN($this->old_id), wikiFN($newid)); + + $this->assertNotEquals($this->indexer->getPID($this->old_id), $oldpid, 'PID for the old page unchanged after rename.'); + $this->assertEquals($this->indexer->getPID($newid), $oldpid, 'New page has not the old pid.'); + $query = array('old'); + $this->assertEquals(array('old' => array($newid => 1)), $this->indexer->lookup($query), '"Old" doesn\'t find the new page'); + } + + function test_rename_to_existing_page() { + $newid = 'existing_page'; + saveWikiText($newid, 'Existing content', 'Created page for move_to_existing_page'); + idx_addPage($newid); + + $oldpid = $this->indexer->getPID($this->old_id); + $existingpid = $this->indexer->getPID($newid); + + $this->assertTrue($this->indexer->renamePage($this->old_id, $newid), 'Renaming the page to an existing id failed'); + + $this->assertNotEquals($this->indexer->getPID($this->old_id), $oldpid, 'PID for old page unchanged after rename.'); + $this->assertNotEquals($this->indexer->getPID($this->old_id), $existingpid, 'PID for old page is now PID of the existing page.'); + $this->assertEquals($this->indexer->getPID($newid), $oldpid, 'New page has not the old pid.'); + $query = array('existing'); + $this->assertEquals(array('existing' => array()), $this->indexer->lookup($query), 'Existing page hasn\'t been deleted from the index.'); + $query = array('old'); + $this->assertEquals(array('old' => array($newid => 1)), $this->indexer->lookup($query), '"Old" doesn\'t find the new page'); + } + + function test_meta_rename_to_new_value() { + $this->indexer->addMetaKeys($this->old_id, array('mkey' => 'old_value')); + + $this->assertTrue($this->indexer->renameMetaValue('mkey', 'old_value', 'new_value'), 'Meta value rename to new value failed.'); + $query = 'old_value'; + $this->assertEquals(array(), $this->indexer->lookupKey('mkey', $query), 'Page can still be found under old value.'); + $query = 'new_value'; + $this->assertEquals(array($this->old_id), $this->indexer->lookupKey('mkey', $query), 'Page can\'t be found under new value.'); + } + + function test_meta_rename_to_existing_value() { + $this->indexer->addMetaKeys($this->old_id, array('mkey' => array('old_value', 'new_value'))); + + saveWikiText('newvalue', 'Test page', ''); + idx_addPage('newvalue'); + $this->indexer->addMetaKeys('newvalue', array('mkey' => array('new_value'))); + + saveWikiText('oldvalue', 'Test page', ''); + idx_addPage('oldvalue'); + $this->indexer->addMetaKeys('oldvalue', array('mkey' => array('old_value'))); + + $this->assertTrue($this->indexer->renameMetaValue('mkey', 'old_value', 'new_value'), 'Meta value rename to existing value failed'); + $query = 'old_value'; + $this->assertEquals(array(), $this->indexer->lookupKey('mkey', $query), 'Page can still be found under old value.'); + $query = 'new_value'; + $result = $this->indexer->lookupKey('mkey', $query); + $this->assertContains($this->old_id, $result, 'Page with both values can\'t be found anymore'); + $this->assertContains('newvalue', $result, 'Page with new value can\'t be found anymore'); + $this->assertContains('oldvalue', $result, 'Page with only the old value can\'t be found anymore'); + } +} diff --git a/inc/indexer.php b/inc/indexer.php index 7a62345bf..e518907d7 100644 --- a/inc/indexer.php +++ b/inc/indexer.php @@ -339,6 +339,109 @@ class Doku_Indexer { } /** + * Rename a page in the search index without changing the indexed content. This function doesn't check if the + * old or new name exists in the filesystem. It returns an error if the old page isn't in the page list of the + * indexer and it deletes all previously indexed content of the new page. + * + * @param string $oldpage The old page name + * @param string $newpage The new page name + * @return string|bool If the page was successfully renamed, can be a message in the case of an error + */ + public function renamePage($oldpage, $newpage) { + if (!$this->lock()) return 'locked'; + + $pages = $this->getPages(); + + $id = array_search($oldpage, $pages); + if ($id === false) { + $this->unlock(); + return 'page is not in index'; + } + + $new_id = array_search($newpage, $pages); + if ($new_id !== false) { + // make sure the page is not in the index anymore + if ($this->deletePageNoLock($newpage) !== true) { + return false; + } + + $pages[$new_id] = 'deleted:'.time().rand(0, 9999); + } + + $pages[$id] = $newpage; + + // update index + if (!$this->saveIndex('page', '', $pages)) { + $this->unlock(); + return false; + } + + // reset the pid cache + $this->pidCache = array(); + + $this->unlock(); + return true; + } + + /** + * Renames a meta value in the index. This doesn't change the meta value in the pages, it assumes that all pages + * will be updated. + * + * @param string $key The metadata key of which a value shall be changed + * @param string $oldvalue The old value that shall be renamed + * @param string $newvalue The new value to which the old value shall be renamed, can exist (then values will be merged) + * @return bool|string If renaming the value has been successful, false or error message on error. + */ + public function renameMetaValue($key, $oldvalue, $newvalue) { + if (!$this->lock()) return 'locked'; + + // change the relation references index + $metavalues = $this->getIndex($key, '_w'); + $oldid = array_search($oldvalue, $metavalues); + if ($oldid !== false) { + $newid = array_search($newvalue, $metavalues); + if ($newid !== false) { + // free memory + unset ($metavalues); + + // okay, now we have two entries for the same value. we need to merge them. + $indexline = $this->getIndexKey($key, '_i', $oldid); + if ($indexline != '') { + $newindexline = $this->getIndexKey($key, '_i', $newid); + $pagekeys = $this->getIndex($key, '_p'); + $parts = explode(':', $indexline); + foreach ($parts as $part) { + list($id, $count) = explode('*', $part); + $newindexline = $this->updateTuple($newindexline, $id, $count); + + $keyline = explode(':', $pagekeys[$id]); + // remove old meta value + $keyline = array_diff($keyline, array($oldid)); + // add new meta value when not already present + if (!in_array($newid, $keyline)) { + array_push($keyline, $newid); + } + $pagekeys[$id] = implode(':', $keyline); + } + $this->saveIndex($key, '_p', $pagekeys); + unset($pagekeys); + $this->saveIndexKey($key, '_i', $oldid, ''); + $this->saveIndexKey($key, '_i', $newid, $newindexline); + } + } else { + $metavalues[$oldid] = $newvalue; + if (!$this->saveIndex($key, '_w', $metavalues)) { + $this->unlock(); + return false; + } + } + } + + $this->unlock(); + return true; + } + + /** * Remove a page from the index * * Erases entries in all known indexes. @@ -351,10 +454,26 @@ class Doku_Indexer { if (!$this->lock()) return "locked"; + $result = $this->deletePageNoLock($page); + + $this->unlock(); + + return $result; + } + + /** + * Remove a page from the index without locking the index, only use this function if the index is already locked + * + * Erases entries in all known indexes. + * + * @param string $page a page name + * @return boolean the function completed successfully + * @author Tom N Harris <tnharris@whoopdedo.org> + */ + protected function deletePageNoLock($page) { // load known documents $pid = $this->getPIDNoLock($page); if ($pid === false) { - $this->unlock(); return false; } @@ -380,7 +499,6 @@ class Doku_Indexer { } // Save the reverse index if (!$this->saveIndexKey('pageword', '', $pid, "")) { - $this->unlock(); return false; } @@ -397,7 +515,6 @@ class Doku_Indexer { $this->saveIndexKey($metaname.'_p', '', $pid, ''); } - $this->unlock(); return true; } |