/** * Renames all occurances of a page ID in the database * * @param Doku_Event $event event object by reference * @param mixed $param [the parameters passed as fifth argument to register_hook() when this * handler was registered] * @return bool */ public function handle_move(Doku_Event $event, $param) { /** @var helper_plugin_struct_db $hlp */ $hlp = plugin_load('helper', 'struct_db'); $db = $hlp->getDB(); if (!$db) { return false; } $old = $event->data['src_id']; $new = $event->data['dst_id']; // ALL data tables (we don't trust the assigments are still there) foreach (Schema::getAll() as $tbl) { $sql = "UPDATE data_{$tbl} SET pid = ? WHERE pid = ?"; $db->query($sql, array($new, $old)); $sql = "UPDATE multi_{$tbl} SET pid = ? WHERE pid = ?"; $db->query($sql, array($new, $old)); } // assignments $sql = "UPDATE schema_assignments SET pid = ? WHERE pid = ?"; $db->query($sql, array($new, $old)); // make sure assignments still match patterns; $assignments = new Assignments(); $assignments->reevaluatePageAssignments($new); return true; }
/** * Adds the structured data to the page body to be snippeted * * @param Doku_Event $event event object by reference * @param mixed $param [the parameters passed as fifth argument to register_hook() when this * handler was registered] * @return bool */ public function handle_snippets(Doku_Event $event, $param) { $id = $event->data['id']; $assignments = new Assignments(); $tables = $assignments->getPageAssignments($id); if (!$tables) { return; } foreach ($tables as $table) { $schemadata = AccessTable::byTableName($table, $id, 0); $event->data['text'] .= $schemadata->getDataPseudoSyntax(); } }
/** * Enhance the editing form with structural data editing * * @param Doku_Event $event event object by reference * @param mixed $param [the parameters passed as fifth argument to register_hook() when this * handler was registered] * @return bool */ public function handle_editform(Doku_Event $event, $param) { global $ID; $assignments = new Assignments(); $tables = $assignments->getPageAssignments($ID); $html = ''; foreach ($tables as $table) { $html .= $this->createForm($table); } /** @var Doku_Form $form */ $form = $event->data; $html = "<div class=\"struct_entry_form\">{$html}</div>"; $pos = $form->findElementById('wiki__editbar'); // insert the form before the main buttons $form->insertElement($pos, $html); return true; }
/** * Save the data, by loading it from the old revision and storing it as a new revision * * @param Doku_Event $event event object by reference * @param mixed $param [the parameters passed as fifth argument to register_hook() when this * handler was registered] * @return bool */ public function handle_pagesave_after(Doku_Event $event, $param) { global $ACT; global $REV; if ($ACT != 'revert' || !$REV) { return false; } $assignments = new Assignments(); // we load the data to restore from DB: $tosave = $assignments->getPageAssignments($event->data['id']); foreach ($tosave as $table) { $accessOld = AccessTable::byTableName($table, $event->data['id'], $REV); $accessNew = AccessTable::byTableName($table, $event->data['id'], $event->data['newRevision']); $accessNew->saveData($accessOld->getDataArray()); // make sure this schema is assigned $assignments->assignPageSchema($event->data['id'], $table); } return true; }
public function test_diff() { $page = 'test_save_page_without_new_text'; $assignment = new meta\Assignments(); $schema = 'schema1'; $assignment->addPattern($page, $schema); $wikitext = 'teststring'; // first save; $request = new \TestRequest(); $structData = array($schema => array('first' => 'foo', 'second' => 'bar, baz', 'third' => 'foobar', 'fourth' => '42')); $request->setPost('struct_schema_data', $structData); $request->setPost('wikitext', $wikitext); $request->setPost('summary', 'content and struct data saved'); $request->post(array('id' => $page, 'do' => 'save'), '/doku.php'); $this->waitForTick(true); // second save - only struct data $request = new \TestRequest(); $structData = array($schema => array('first' => 'foo', 'second' => 'bar2, baz2', 'third' => 'foobar2', 'fourth' => '42')); $request->setPost('struct_schema_data', $structData); $request->setPost('wikitext', $wikitext); $request->setPost('summary', '2nd revision'); $request->post(array('id' => $page, 'do' => 'save'), '/doku.php'); // diff $request = new \TestRequest(); $response = $request->post(array('id' => $page, 'do' => 'diff'), '/doku.php'); $pq = $response->queryHTML('table.diff_sidebyside'); $this->assertEquals(1, $pq->length); $added = $pq->find('td.diff-addedline'); $deleted = $pq->find('td.diff-deletedline'); $this->assertEquals(2, $added->length); $this->assertEquals(2, $deleted->length); $this->assertContains('bar', $deleted->eq(0)->html()); $this->assertContains('baz', $deleted->eq(0)->html()); $this->assertContains('bar2', $added->eq(0)->html()); $this->assertContains('baz2', $added->eq(0)->html()); $this->assertContains('foobar', $deleted->eq(1)->html()); $this->assertContains('foobar2', $added->eq(1)->html()); }
/** * Add structured data to the diff * * This is done by adding pseudo syntax to the page source when it is loaded in diff context * * @param Doku_Event $event event object by reference * @param mixed $param [the parameters passed as fifth argument to register_hook() when this * handler was registered] * @return bool */ public function handle_diffload(Doku_Event $event, $param) { global $ACT; global $INFO; if ($ACT != 'diff') { return; } $id = $event->data[2]; $rev = $event->data[3]; if ($INFO['id'] != $id) { return; } $assignments = new Assignments(); $tables = $assignments->getPageAssignments($id); if (!$tables) { return; } $event->result .= "\n---- struct data ----\n"; foreach ($tables as $table) { $schemadata = AccessTable::byTableName($table, $id, $rev); $event->result .= $schemadata->getDataPseudoSyntax(); } $event->result .= "----\n"; }
/** * Save the struct data * * @param Doku_Event $event event object by reference * @param mixed $param [the parameters passed as fifth argument to register_hook() when this * handler was registered] * @return bool */ public function handle_save(Doku_Event $event, $param) { // get all struct values and their associated schemas $tosave = array(); foreach ($event->data['fields'] as $field) { if (!is_a($field, 'helper_plugin_struct_field')) { continue; } /** @var helper_plugin_struct_field $field */ $tbl = $field->column->getTable(); $lbl = $field->column->getLabel(); if (!isset($tosave[$tbl])) { $tosave[$tbl] = array(); } $tosave[$tbl][$lbl] = $field->getParam('value'); } // save all the struct data of assigned schemas $id = $event->data['id']; $time = filemtime(wikiFN($id)); $assignments = new Assignments(); $assigned = $assignments->getPageAssignments($id); foreach ($tosave as $table => $data) { if (!in_array($table, $assigned)) { continue; } $access = AccessTable::byTableName($table, $id, $time); $validator = $access->getValidator($data); if ($validator->validate()) { $validator->saveData($time); } } return true; }
/** * Returns all pages known to the struct plugin * * That means all pages that have or had once struct data saved * * @param string|null $schema limit the result to a given schema * @return array (page => (schema => true), ...) * @throws StructException */ public function getPages($schema = null) { $assignments = new Assignments(); return $assignments->getPages($schema); }
/** * Render schema data * * Currently completely renderer agnostic * * @todo we currently have no schema headlines * * @param string $mode Renderer mode * @param Doku_Renderer $R The renderer * @param array $data The data from the handler() function * @return bool If rendering was successful. */ public function render($mode, Doku_Renderer $R, $data) { global $ID; global $INFO; global $REV; if ($ID != $INFO['id']) { return true; } if (!$INFO['exists']) { return true; } if ($this->hasBeenRendered) { return true; } // do not render the output twice on the same page, e.g. when another page has been included $this->hasBeenRendered = true; $assignments = new Assignments(); $tables = $assignments->getPageAssignments($ID); if (!$tables) { return true; } if ($mode == 'xhtml') { $R->doc .= '<div id="plugin__struct_output">'; } foreach ($tables as $table) { $schemadata = AccessTable::byTableName($table, $ID, $REV); $schemadata->optionSkipEmpty(true); $data = $schemadata->getData(); if (!count($data)) { continue; } $R->table_open(); $R->tablethead_open(); $R->tablerow_open(); $R->tableheader_open(2); $R->cdata($table); $R->tableheader_close(); $R->tablerow_close(); $R->tablethead_open(); $R->tabletbody_open(); foreach ($data as $field) { $R->tablerow_open(); $R->tableheader_open(); $R->cdata($field->getColumn()->getTranslatedLabel()); $R->tableheader_close(); $R->tablecell_open(); $field->render($R, $mode); $R->tablecell_close(); $R->tablerow_close(); } $R->tabletbody_close(); $R->table_close(); } if ($mode == 'xhtml') { $R->doc .= '</div>'; } return true; }
/** * Render HTML output, e.g. helpful text and a form */ public function html() { global $ID; echo $this->locale_xhtml('assignments_intro'); $ass = new Assignments(); $assignments = $ass->getAllPatterns(); echo '<form action="' . wl($ID) . '" action="post">'; echo '<input type="hidden" name="do" value="admin" />'; echo '<input type="hidden" name="page" value="struct_assignments" />'; echo '<input type="hidden" name="sectok" value="' . getSecurityToken() . '" />'; echo '<table class="inline">'; // header echo '<tr>'; echo '<th>' . $this->getLang('assign_assign') . '</th>'; echo '<th>' . $this->getLang('assign_tbl') . '</th>'; echo '<th></th>'; echo '</tr>'; // existing assignments foreach ($assignments as $assignment) { $schema = $assignment['tbl']; $assignee = $assignment['pattern']; $link = wl($ID, array('do' => 'admin', 'page' => 'struct_assignments', 'action' => 'delete', 'sectok' => getSecurityToken(), 'assignment[tbl]' => $schema, 'assignment[assign]' => $assignee)); echo '<tr>'; echo '<td>' . hsc($assignee) . '</td>'; echo '<td>' . hsc($schema) . '</td>'; echo '<td><a class="deleteSchema" href="' . $link . '">' . $this->getLang('assign_del') . '</a></td>'; echo '</tr>'; } // new assignment form echo '<tr>'; echo '<td><input type="text" name="assignment[assign]" /></td>'; echo '<td>'; echo '<select name="assignment[tbl]">'; foreach (Schema::getAll('page') as $table) { echo '<option value="' . hsc($table) . '">' . hsc($table) . '</option>'; } echo '</select>'; echo '</td>'; echo '<td><button type="submit" name="action" value="add">' . $this->getLang('assign_add') . '</button></td>'; echo '</tr>'; echo '</table>'; }
/** * Saves struct data for given page and schema * * Please note that setting the $rev only influences the struct data timestamp, * not the page and changelog entries. * * @param string $page * @param string $schema * @param array $data * @param int $rev allows to override the revision timestamp */ protected function saveData($page, $schema, $data, $rev = 0) { if (!$rev) { $rev = time(); } saveWikiText($page, "test for {$page}", "saved for testing"); $schemaData = AccessTable::byTableName($schema, $page, $rev); $schemaData->saveData($data); $assignments = new Assignments(); $assignments->assignPageSchema($page, $schema); }
/** * Save the data * * When this is called, INPUT data has been validated already. * * @param Doku_Event $event event object by reference * @param mixed $param [the parameters passed as fifth argument to register_hook() when this * handler was registered] * @return bool */ public function handle_pagesave_after(Doku_Event $event, $param) { global $ACT; if ($ACT == 'revert') { return false; } // handled in revert $assignments = new Assignments(); if ($event->data['changeType'] == DOKU_CHANGE_TYPE_DELETE && empty($GLOBALS['PLUGIN_MOVE_WORKING'])) { // clear all data on delete unless it's a move operation $tables = $assignments->getPageAssignments($event->data['id']); foreach ($tables as $table) { $schemaData = AccessTable::byTableName($table, $event->data['id'], time()); if ($schemaData->getSchema()->isEditable()) { $schemaData->clearData(); } } } else { // save the provided data if ($this->tosave) { foreach ($this->tosave as $validation) { if ($validation->getAccessTable()->getSchema()->isEditable()) { $validation->saveData($event->data['newRevision']); // make sure this schema is assigned $assignments->assignPageSchema($event->data['id'], $validation->getAccessTable()->getSchema()->getTable()); } } } } return true; }
/** * @group slow */ public function test_revert_page() { $page = 'test_revert_page'; $assignment = new meta\Assignments(); $schema = 'Schema2'; $assignment->addPattern($page, $schema); $wikitext = 'teststring'; global $conf; $conf['useacl'] = 1; $conf['superuser'] = '******'; $_SERVER['REMOTE_USER'] = '******'; //now it's testing as admin global $default_server_vars; $default_server_vars['REMOTE_USER'] = '******'; //Hack until Issue #1099 is fixed $USERINFO['grps'] = array('admin', 'user'); // first save; $request = new \TestRequest(); $structData = array($schema => array('afirst' => 'foo', 'asecond' => 'bar, baz', 'athird' => 'foobar', 'afourth' => '42')); $request->setPost('struct_schema_data', $structData); $request->setPost('wikitext', $wikitext); $request->setPost('summary', 'content and struct data saved'); $request->post(array('id' => $page, 'do' => 'save', 'sectok' => getSecurityToken()), '/doku.php'); $this->waitForTick(true); // second save $request = new \TestRequest(); $structData = array($schema => array('afirst' => 'foo2', 'asecond' => 'bar2, baz2', 'athird' => 'foobar2', 'afourth' => '43')); $request->setPost('struct_schema_data', $structData); $request->setPost('wikitext', $wikitext . $wikitext); $request->setPost('summary', 'delete page'); $request->post(array('id' => $page, 'do' => 'save', 'sectok' => getSecurityToken()), '/doku.php'); $this->waitForTick(true); // revert to first save $actpagelog = new \PageChangelog($page); $actrevisions = $actpagelog->getRevisions(0, 200); $actrevinfo = $actpagelog->getRevisionInfo($actrevisions[0]); $request = new \TestRequest(); $request->setPost('summary', 'revert page'); $request->post(array('id' => $page, 'do' => 'revert', 'rev' => $actrevinfo['date'], 'sectok' => getSecurityToken()), '/doku.php'); // assert $pagelog = new \PageChangelog($page); $revisions = $pagelog->getRevisions(-1, 200); $revinfo = $pagelog->getRevisionInfo($revisions[0]); $schemaData = meta\AccessTable::byTableName($schema, $page, 0); $actual_struct_data = $schemaData->getDataArray(); $expected_struct_data = array('afirst' => 'foo', 'asecond' => array('bar', 'baz'), 'athird' => 'foobar', 'afourth' => '42'); $this->assertEquals(3, count($revisions), 'there should be 3 (three) revisions'); $this->assertContains('restored', $revinfo['sum']); $this->assertEquals(DOKU_CHANGE_TYPE_REVERT, $revinfo['type']); $this->assertEquals($expected_struct_data, $actual_struct_data); // todo: timestamps? }
public function matchPagePattern($pattern, $page, $pns = null) { return parent::matchPagePattern($pattern, $page, $pns); }