1<?php 2 3namespace dokuwiki\plugin\struct\test; 4 5use dokuwiki\plugin\struct\meta\AccessTablePage; 6use dokuwiki\plugin\struct\meta\ConfigParser; 7use dokuwiki\plugin\struct\meta\PageMeta; 8use dokuwiki\plugin\struct\test\mock\AccessTable as MockAccessTableAlias; 9use dokuwiki\plugin\struct\test\mock\SearchConfig as MockSearchConfigAlias; 10 11/** 12 * Testing serial data 13 * 14 * @group plugin_struct 15 * @group plugins 16 */ 17class AggregationResultsTest extends StructTest 18{ 19 protected $sqlite; 20 21 public function setUp(): void 22 { 23 parent::setUp(); 24 25 $sqlite = plugin_load('helper', 'struct_db'); 26 $this->sqlite = $sqlite->getDB(); 27 28 $this->loadSchemaJSON('schema1'); 29 30 $assignments = mock\Assignments::getInstance(); 31 $assignments->clear(true); 32 33 // different values for each entry 34 $second = [ 35 ['green', 'red'], 36 ['green', 'blue'], 37 ['blue', 'yellow'] 38 ]; 39 40 for ($i = 0; $i < 3; $i++) { 41 // assign a schema 42 $assignments->assignPageSchema("test$i", 'schema1'); 43 44 // save wiki pages 45 saveWikiText("test$i", "test$i", "test$i"); 46 47 // save serial data 48 $data = [ 49 'first' => "foo$i", 50 'second' => $second[$i], 51 'third' => "foobar$i", 52 'fourth' => "barfoo$i", 53 ]; 54 $accessSerial = MockAccessTableAlias::getSerialAccess('schema1', "test$i"); 55 $accessSerial->saveData($data); 56 $accessPage = MockAccessTableAlias::getPageAccess('schema1', "test$i"); 57 $accessPage->saveData($data); 58 } 59 } 60 61 /** 62 * Test whether serial syntax produces a table of serial data limited to current page 63 */ 64 public function test_pid() 65 { 66 // \syntax_plugin_struct_serial accesses the global $ID 67 $id = 'test1'; 68 $schema = 'schema1'; 69 $result = $this->fetchNonPageResults($schema, $id); 70 71 $this->assertCount(1, $result); 72 $this->assertEquals('test1', $result[0][0]->getValue()); 73 // skip %rowid% column and test saved values 74 $this->assertEquals('foo1', $result[0][2]->getValue()); 75 $this->assertEquals(['green', 'blue'], $result[0][3]->getValue()); 76 $this->assertEquals('foobar1', $result[0][4]->getValue()); 77 $this->assertEquals('barfoo1', $result[0][5]->getValue()); 78 } 79 80 /** 81 * Test simple text filter 82 */ 83 public function test_filter_text() 84 { 85 $schema = 'schema1'; 86 $result = $this->fetchNonPageResults($schema, 'test0'); 87 $this->assertCount(1, $result); 88 89 $result = $this->fetchNonPageResults($schema, 'test0', ['first', '=', 'foo0', 'AND']); 90 $this->assertCount(1, $result); 91 92 $result = $this->fetchNonPageResults($schema, 'test0', ['first', '!=', 'foo0', 'AND']); 93 $this->assertCount(0, $result); 94 } 95 96 /** @noinspection PhpUnreachableStatementInspection */ 97 public function test_filter_multi() 98 { 99 $schema = 'schema1'; 100 $result = $this->fetchAllResults($schema, ''); 101 $this->assertCount(6, $result); 102 103 $result = $this->fetchAllResults($schema, '', ['second', '=', 'green', 'AND']); 104 $this->assertCount(4, $result); 105 106 $this->markTestIncomplete('negative filters currently do not work on multi fields. See #512'); 107 108 $result = $this->fetchAllResults($schema, '', ['second', '!~', 'green', 'AND']); 109 $this->assertCount(2, $result); 110 } 111 112 /** 113 * Test filtering on a page field, with 'usetitles' set to true and false 114 */ 115 public function test_filter_page() 116 { 117 $this->prepareLookup(); 118 $schema = 'pageschema'; 119 $result = $this->fetchNonPageResults($schema); 120 $this->assertCount(3, $result); 121 122 // 'usetitles' = true 123 $result = $this->fetchNonPageResults($schema, '', ['singletitle', '*~', 'another', 'AND']); 124 $this->assertCount(1, $result); 125 126 // 'usetitles' = false 127 $result = $this->fetchNonPageResults($schema, '', ['singlepage', '*~', 'this', 'AND']); 128 $this->assertCount(0, $result); 129 } 130 131 /** 132 * Test filtering on a DateTime field 133 */ 134 public function test_filter_datetime() 135 { 136 $this->prepareDatetime(); 137 $schema = 'datetime'; 138 $result = $this->fetchNonPageResults($schema); 139 $this->assertCount(3, $result); 140 141 $result = $this->fetchNonPageResults($schema, '', ['field', '<', '2023-01-02', 'AND']); 142 $this->assertCount(1, $result); 143 144 $result = $this->fetchNonPageResults($schema, '', ['field', '<', '2023-01-01 11:00', 'AND']); 145 $this->assertCount(0, $result); 146 } 147 148 /** 149 * Test whether aggregation tables respect revoking of schema assignments 150 */ 151 public function test_assignments() 152 { 153 $result = $this->fetchAllResults('schema1'); 154 $this->assertCount(6, $result); 155 156 // revoke assignment 157 $assignments = mock\Assignments::getInstance(); 158 $assignments->deassignPageSchema('test0', 'schema1'); 159 160 $result = $this->fetchAllResults('schema1'); 161 $this->assertCount(5, $result); 162 } 163 164 165 /** 166 * Initialize a table from syntax and return the result from its internal search. 167 * 168 * @param string $schema 169 * @param string $id 170 * @param array $filters 171 * @return \dokuwiki\plugin\struct\meta\Value[][] 172 */ 173 protected function fetchAllResults($schema, $id = '', $filters = []) 174 { 175 $syntaxConfig = ['schema: ' . $schema, 'cols: %pageid%, %rowid%, *']; 176 $configParser = new ConfigParser($syntaxConfig); 177 $config = $configParser->getConfig(); 178 179 if ($filters) $config['filter'][] = $filters; 180 $search = new MockSearchConfigAlias($config); 181 182 return $search->getRows(); 183 } 184 185 /** 186 * Initialize a lookup table from syntax and return the result from its internal search. 187 * 188 * @param string $schema 189 * @param string $id 190 * @param array $filters 191 * @return \dokuwiki\plugin\struct\meta\Value[][] 192 */ 193 protected function fetchNonPageResults($schema, $id = '', $filters = []) 194 { 195 $syntaxConfig = ['schema: ' . $schema, 'cols: %pageid%, %rowid%, *']; 196 $configParser = new ConfigParser($syntaxConfig); 197 $config = $configParser->getConfig(); 198 199 // simulate addYypeFilter() from \syntax_plugin_struct_serial and \syntax_plugin_struct_lookup 200 if ($id) { 201 $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND']; 202 $config['filter'][] = ['%pageid%', '=', $id, 'AND']; 203 } else { 204 $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND']; 205 $config['filter'][] = ['%pageid%', '=*', '^(?![\s\S])', 'AND']; 206 } 207 208 if ($filters) $config['filter'][] = $filters; 209 $search = new MockSearchConfigAlias($config); 210 211 return $search->getRows(); 212 } 213 214 protected function prepareLookup() 215 { 216 saveWikiText('title1', 'test', 'test'); 217 $pageMeta = new PageMeta('title1'); 218 $pageMeta->setTitle('This is a title'); 219 220 saveWikiText('title2', 'test', 'test'); 221 $pageMeta = new PageMeta('title2'); 222 $pageMeta->setTitle('This is a 2nd title'); 223 224 saveWikiText('title3', 'test', 'test'); 225 $pageMeta = new PageMeta('title3'); 226 $pageMeta->setTitle('Another Title'); 227 228 $this->loadSchemaJSON('pageschema'); 229 $access = MockAccessTableAlias::getGlobalAccess('pageschema'); 230 $access->saveData( 231 [ 232 'singlepage' => 'title1', 233 'multipage' => ['title1'], 234 'singletitle' => 'title1', 235 'multititle' => ['title1'], 236 ] 237 ); 238 $access = MockAccessTableAlias::getGlobalAccess('pageschema'); 239 $access->saveData( 240 [ 241 'singlepage' => 'title2', 242 'multipage' => ['title2'], 243 'singletitle' => 'title2', 244 'multititle' => ['title2'], 245 ] 246 ); 247 $access = MockAccessTableAlias::getGlobalAccess('pageschema'); 248 $access->saveData( 249 [ 250 'singlepage' => 'title3', 251 'multipage' => ['title3'], 252 'singletitle' => 'title3', 253 'multititle' => ['title3'], 254 ] 255 ); 256 } 257 258 protected function prepareDatetime() 259 { 260 $this->loadSchemaJSON('datetime'); 261 $access = MockAccessTableAlias::getGlobalAccess('datetime'); 262 $access->saveData(['field' => '2023-01-01 12:00']); 263 $access = MockAccessTableAlias::getGlobalAccess('datetime'); 264 $access->saveData(['field' => '2023-01-02 00:00']); 265 $access = MockAccessTableAlias::getGlobalAccess('datetime'); 266 $access->saveData(['field' => '2023-01-02 12:00']); 267 } 268} 269