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\AggregationEditorTable as MockAggregationEditorTableAlias; 10use dokuwiki\plugin\struct\test\mock\AggregationTable as MockAggregationTableAlias; 11use dokuwiki\plugin\struct\test\mock\SearchConfig as MockSearchConfigAlias; 12 13/** 14 * Testing serial data 15 * 16 * @group plugin_struct 17 * @group plugins 18 */ 19class AggregationResultsTest extends StructTest 20{ 21 protected $sqlite; 22 23 public function setUp(): void 24 { 25 parent::setUp(); 26 27 $sqlite = plugin_load('helper', 'struct_db'); 28 $this->sqlite = $sqlite->getDB(); 29 30 $this->loadSchemaJSON('schema1'); 31 32 $assignments = mock\Assignments::getInstance(); 33 $assignments->clear(true); 34 35 // different values for each entry 36 $second = [ 37 ['green', 'red'], 38 ['green', 'blue'], 39 ['blue', 'yellow'] 40 ]; 41 42 for ($i = 0; $i < 3; $i++) { 43 // assign a schema 44 $assignments->assignPageSchema("test$i", 'schema1'); 45 46 // save wiki pages 47 saveWikiText("test$i", "test$i", "test$i"); 48 49 // save serial data 50 $data = [ 51 'first' => "foo$i", 52 'second' => $second[$i], 53 'third' => "foobar$i", 54 'fourth' => "barfoo$i", 55 ]; 56 $access = MockAccessTableAlias::getSerialAccess('schema1', "test$i"); 57 $access->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->fetchResult($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->fetchResult($schema, 'test0'); 87 $this->assertCount(1, $result); 88 89 $result = $this->fetchResult($schema, 'test0', ['first', '=', 'foo0', 'AND']); 90 $this->assertCount(1, $result); 91 92 $result = $this->fetchResult($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->fetchPagesResult($schema, ''); 101 $this->assertCount(3, $result); 102 103 $result = $this->fetchPagesResult($schema, '', ['second', '=', 'green', 'AND']); 104 $this->assertCount(2, $result); 105 106 $this->markTestIncomplete('negative filters currently do not work on multi fields. See #512'); 107 108 $result = $this->fetchPagesResult($schema, '', ['second', '!~', 'green', 'AND']); 109 $this->assertCount(1, $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->fetchResult($schema); 120 $this->assertCount(3, $result); 121 122 // 'usetitles' = true 123 $result = $this->fetchResult($schema, '', ['singletitle', '*~', 'another', 'AND']); 124 $this->assertCount(1, $result); 125 126 // 'usetitles' = false 127 $result = $this->fetchResult($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->fetchResult($schema); 139 $this->assertCount(3, $result); 140 141 $result = $this->fetchResult($schema, '', ['field', '<', '2023-01-02', 'AND']); 142 $this->assertCount(1, $result); 143 144 $result = $this->fetchResult($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->fetchPagesResult('schema1'); 154 $this->assertCount(3, $result); 155 156 // revoke assignment 157 $assignments = mock\Assignments::getInstance(); 158 $assignments->deassignPageSchema('test0', 'schema1'); 159 160 $result = $this->fetchPagesResult('schema1'); 161 $this->assertCount(2, $result); 162 } 163 164 165 /** 166 * Initialize a lookup 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 fetchPagesResult($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 $table = new MockAggregationTableAlias($id, 'xhtml', new \Doku_Renderer_xhtml(), $search); 183 return $table->getResult(); 184 } 185 186 /** 187 * Initialize a lookup table from syntax and return the result from its internal search. 188 * 189 * @param string $schema 190 * @param string $id 191 * @param array $filters 192 * @return \dokuwiki\plugin\struct\meta\Value[][] 193 */ 194 protected function fetchResult($schema, $id = '', $filters = []) 195 { 196 $syntaxConfig = ['schema: ' . $schema, 'cols: %pageid%, %rowid%, *']; 197 $configParser = new ConfigParser($syntaxConfig); 198 $config = $configParser->getConfig(); 199 200 // FIXME simulate addYypeFilter() from \syntax_plugin_struct_serial or \syntax_plugin_struct_lookup 201 if ($id) { 202 $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND']; 203 $config['filter'][] = ['%pageid%', '=', $id, 'AND']; 204 } else { 205 $config['filter'][] = ['%rowid%', '!=', (string)AccessTablePage::DEFAULT_PAGE_RID, 'AND']; 206 $config['filter'][] = ['%pageid%', '=*', '^(?![\s\S])', 'AND']; 207 } 208 209 if ($filters) $config['filter'][] = $filters; 210 $search = new MockSearchConfigAlias($config); 211 212 $table = new MockAggregationEditorTableAlias($id, 'xhtml', new \Doku_Renderer_xhtml(), $search); 213 return $table->getResult(); 214 } 215 216 protected function prepareLookup() 217 { 218 saveWikiText('title1', 'test', 'test'); 219 $pageMeta = new PageMeta('title1'); 220 $pageMeta->setTitle('This is a title'); 221 222 saveWikiText('title2', 'test', 'test'); 223 $pageMeta = new PageMeta('title2'); 224 $pageMeta->setTitle('This is a 2nd title'); 225 226 saveWikiText('title3', 'test', 'test'); 227 $pageMeta = new PageMeta('title3'); 228 $pageMeta->setTitle('Another Title'); 229 230 $this->loadSchemaJSON('pageschema'); 231 $access = MockAccessTableAlias::getGlobalAccess('pageschema'); 232 $access->saveData( 233 [ 234 'singlepage' => 'title1', 235 'multipage' => ['title1'], 236 'singletitle' => 'title1', 237 'multititle' => ['title1'], 238 ] 239 ); 240 $access = MockAccessTableAlias::getGlobalAccess('pageschema'); 241 $access->saveData( 242 [ 243 'singlepage' => 'title2', 244 'multipage' => ['title2'], 245 'singletitle' => 'title2', 246 'multititle' => ['title2'], 247 ] 248 ); 249 $access = MockAccessTableAlias::getGlobalAccess('pageschema'); 250 $access->saveData( 251 [ 252 'singlepage' => 'title3', 253 'multipage' => ['title3'], 254 'singletitle' => 'title3', 255 'multititle' => ['title3'], 256 ] 257 ); 258 } 259 260 protected function prepareDatetime() 261 { 262 $this->loadSchemaJSON('datetime'); 263 $access = MockAccessTableAlias::getGlobalAccess('datetime'); 264 $access->saveData(['field' => '2023-01-01 12:00']); 265 $access = MockAccessTableAlias::getGlobalAccess('datetime'); 266 $access->saveData(['field' => '2023-01-02 00:00']); 267 $access = MockAccessTableAlias::getGlobalAccess('datetime'); 268 $access->saveData(['field' => '2023-01-02 12:00']); 269 } 270} 271