/**
  * 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();
     }
 }
 /**
  * Get the structured data of a given page
  *
  * @param string $page The page to get data for
  * @param string|null $schema The schema to use null for all
  * @param int $time A timestamp if you want historic data (0 for now)
  * @return array ('schema' => ( 'fieldlabel' => 'value', ...))
  * @throws StructException
  */
 public function getData($page, $schema = null, $time = 0)
 {
     $page = cleanID($page);
     if (is_null($schema)) {
         $assignments = new Assignments();
         $schemas = $assignments->getPageAssignments($page, false);
     } else {
         $schemas = array($schema);
     }
     $result = array();
     foreach ($schemas as $schema) {
         $schemaData = AccessTable::byTableName($schema, $page, $time);
         $result[$schema] = $schemaData->getDataArray();
     }
     return $result;
 }
 /**
  * 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_move()
 {
     $data = array('first' => 'data 1', 'second' => array('data 2.1', 'data 2.2'), 'third' => 'data 3', 'fourth' => 'data 4');
     $empty = array('first' => '', 'second' => array(), 'third' => '', 'fourth' => '');
     // add initial data
     $schemaData = meta\AccessTable::byTableName('schema1', 'somepage', time());
     $schemaData->saveData($data);
     $this->assertEquals($data, $schemaData->getDataArray());
     // fake move event
     $evdata = array('src_id' => 'somepage', 'dst_id' => 'newpage');
     $event = new \Doku_Event('PLUGIN_MOVE_PAGE_RENAME', $evdata);
     $evhandler = new \action_plugin_struct_move();
     $this->assertTrue($evhandler->handle_move($event, null));
     // old page should be gone
     $schemaData = meta\AccessTable::byTableName('schema1', 'somepage', 0);
     $this->assertEquals($empty, $schemaData->getDataArray());
     // new page should have data
     $schemaData = meta\AccessTable::byTableName('schema1', 'newpage', 0);
     $this->assertEquals($data, $schemaData->getDataArray());
 }
 /**
  * Create the form to edit schemadata
  *
  * @param string $tablename
  * @return string The HTML for this schema's form
  */
 protected function createForm($tablename)
 {
     global $ID;
     global $REV;
     global $INPUT;
     if (auth_quickaclcheck($ID) == AUTH_READ) {
         return '';
     }
     if (checklock($ID)) {
         return '';
     }
     $schema = AccessTable::byTableName($tablename, $ID, $REV);
     if (!$schema->getSchema()->isEditable()) {
         return '';
     }
     $schemadata = $schema->getData();
     $structdata = $INPUT->arr(self::$VAR);
     if (isset($structdata[$tablename])) {
         $postdata = $structdata[$tablename];
     } else {
         $postdata = array();
     }
     // we need a short, unique identifier to use in the cookie. this should be good enough
     $schemaid = 'SRCT' . substr(str_replace(array('+', '/'), '', base64_encode(sha1($tablename, true))), 0, 5);
     $html = '<fieldset data-schema="' . $schemaid . '">';
     $html .= '<legend>' . hsc($tablename) . '</legend>';
     foreach ($schemadata as $field) {
         $label = $field->getColumn()->getLabel();
         if (isset($postdata[$label])) {
             // posted data trumps stored data
             $field->setValue($postdata[$label], true);
         }
         $html .= $this->makeField($field, self::$VAR . "[{$tablename}][{$label}]");
     }
     $html .= '</fieldset>';
     return $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";
 }
 public function test_filtervars_struct()
 {
     global $ID;
     $ID = 'foo:bar:baz';
     // prepare some struct data
     $sb = new meta\SchemaImporter('schema1', file_get_contents(__DIR__ . '/json/schema1.struct.json'));
     $sb->build();
     $schemaData = meta\AccessTable::byTableName('schema1', $ID, time());
     $schemaData->saveData(array('first' => 'test', 'second' => array('multi1', 'multi2')));
     $searchConfig = new SearchConfig(array('schemas' => array(array('schema1', 'alias'))));
     $this->assertEquals('test', $searchConfig->applyFilterVars('$STRUCT.first$'));
     $this->assertEquals('test', $searchConfig->applyFilterVars('$STRUCT.alias.first$'));
     $this->assertEquals('test', $searchConfig->applyFilterVars('$STRUCT.schema1.first$'));
     $this->assertEquals('pretestpost', $searchConfig->applyFilterVars('pre$STRUCT.first$post'));
     $this->assertEquals('pretestpost', $searchConfig->applyFilterVars('pre$STRUCT.alias.first$post'));
     $this->assertEquals('pretestpost', $searchConfig->applyFilterVars('pre$STRUCT.schema1.first$post'));
     $this->assertEquals(array('multi1', 'multi2'), $searchConfig->applyFilterVars('$STRUCT.second$'));
     $this->assertEquals(array('multi1', 'multi2'), $searchConfig->applyFilterVars('$STRUCT.alias.second$'));
     $this->assertEquals(array('multi1', 'multi2'), $searchConfig->applyFilterVars('$STRUCT.schema1.second$'));
     $this->assertEquals(array('premulti1post', 'premulti2post'), $searchConfig->applyFilterVars('pre$STRUCT.second$post'));
     $this->assertEquals(array('premulti1post', 'premulti2post'), $searchConfig->applyFilterVars('pre$STRUCT.alias.second$post'));
     $this->assertEquals(array('premulti1post', 'premulti2post'), $searchConfig->applyFilterVars('pre$STRUCT.schema1.second$post'));
     $this->assertEquals('', $searchConfig->applyFilterVars('$STRUCT.notexisting$'));
 }
 /**
  * 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;
 }
 public function test_getDataArray_skipEmpty()
 {
     // arrange
     $testdata = array('testcolumn' => '', 'testMulitColumn' => array("value2.1_saved", "value2.2_saved"));
     $schemaData = meta\AccessTable::byTableName('testtable', 'testpage', time());
     $schemaData->saveData($testdata);
     // act
     $schemaData->optionSkipEmpty(true);
     $actual_data = $schemaData->getDataArray();
     $expected_data = array('testMulitColumn' => array('value2.1_saved', 'value2.2_saved'));
     // assert
     $this->assertEquals(1, count($actual_data), 'There should be only one value returned and the empty value skipped');
     $this->assertEquals($expected_data, $actual_data);
 }
 /**
  * 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;
 }
 /**
  * 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);
 }
 /**
  * @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?
 }
 /**
  * Save one new lookup row
  */
 protected function lookup_save()
 {
     global $INPUT;
     $tablename = $INPUT->str('schema');
     $data = $INPUT->arr('entry');
     action_plugin_struct_inline::checkCSRF();
     $access = AccessTable::byTableName($tablename, 0, 0);
     if (!$access->getSchema()->isEditable()) {
         throw new StructException('lookup save error: no permission for schema');
     }
     $validator = $access->getValidator($data);
     if (!$validator->validate()) {
         throw new StructException("Validation failed:\n%s", join("\n", $validator->getErrors()));
     }
     if (!$validator->saveData()) {
         throw new StructException('No data saved');
     }
     // create a new row based on the original aggregation config for the new pid
     $pid = $access->getPid();
     $config = json_decode($INPUT->str('searchconf'), true);
     $config['filter'] = array(array('%rowid%', '=', $pid, 'AND'));
     $lookup = new LookupTable('', 'xhtml', new Doku_Renderer_xhtml(), new SearchConfig($config));
     echo $lookup->getFirstRow();
 }
 /**
  * Initialize internal state based on input variables
  *
  * @return bool if initialization was successfull
  */
 protected function initFromInput()
 {
     global $INPUT;
     $this->schemadata = null;
     $this->column = null;
     $pid = $INPUT->str('pid');
     list($table, $field) = explode('.', $INPUT->str('field'));
     if (blank($pid)) {
         return false;
     }
     if (blank($table)) {
         return false;
     }
     if (blank($field)) {
         return false;
     }
     $this->pid = $pid;
     try {
         $this->schemadata = AccessTable::byTableName($table, $pid);
     } catch (StructException $ignore) {
         return false;
     }
     $this->column = $this->schemadata->getSchema()->findColumn($field);
     if (!$this->column || !$this->column->isVisibleInEditor()) {
         $this->schemadata = null;
         $this->column = null;
         return false;
     }
     return true;
 }