1<?php
2
3namespace dokuwiki\plugin\struct\test;
4
5use dokuwiki\plugin\struct\meta;
6
7/**
8 * Tests for the building of SQL-Queries for the struct plugin
9 *
10 * @group plugin_struct
11 * @group plugins
12 *
13 */
14class AccessTableDataReplacement_struct_test extends StructTest
15{
16
17    /** @var array alway enable the needed plugins */
18    protected $pluginsEnabled = array('struct', 'sqlite');
19
20    public function setUp(): void
21    {
22        parent::setUp();
23        $schemafoo = array();
24        $schemafoo['new']['new1']['label'] = 'pages';
25        $schemafoo['new']['new1']['ismulti'] = 1;
26        $schemafoo['new']['new1']['class'] = 'Page';
27        $schemafoo['new']['new1']['isenabled'] = '1';
28
29        $schemabar['new']['new2']['label'] = 'data';
30        $schemabar['new']['new2']['ismulti'] = 0;
31        $schemabar['new']['new2']['class'] = 'Text';
32        $schemabar['new']['new2']['isenabled'] = '1';
33
34        $builder_foo = new meta\SchemaBuilder('foo', $schemafoo);
35        $builder_foo->build();
36
37        $builder_bar = new meta\SchemaBuilder('bar', $schemabar);
38        $builder_bar->build();
39
40        $as = mock\Assignments::getInstance();
41        $as->assignPageSchema('start', 'foo');
42        $as->assignPageSchema('no:data', 'foo');
43        $as->assignPageSchema('page1', 'bar');
44        $as->assignPageSchema('page2', 'bar');
45        $as->assignPageSchema('page2', 'bar');
46
47        // page data is saved with a rev timestamp
48        $now = time();
49        $this->saveData(
50            'start',
51            'foo',
52            array(
53                'pages' => array('page1', 'page2')
54            ),
55            $now
56        );
57
58        $this->saveData(
59            'page1',
60            'bar',
61            array(
62                'data' => 'data of page1'
63            ),
64            $now
65        );
66
67        $this->saveData(
68            'page2',
69            'bar',
70            array(
71                'data' => 'data of page2'
72            ),
73            $now
74        );
75    }
76
77    public function test_simple()
78    {
79        global $INFO;
80        $INFO['id'] = 'start';
81        $lines = array(
82            "schema    : bar",
83            "cols      : %pageid%, data",
84            "filter    : %pageid% = \$STRUCT.foo.pages$"
85        );
86
87        $configParser = new meta\ConfigParser($lines);
88        $actual_config = $configParser->getConfig();
89
90        $search = new meta\SearchConfig($actual_config);
91        list(, $opts) = $search->getSQL();
92        $result = $search->execute();
93
94        $this->assertEquals(array('page1', 'page2'), $opts, '$STRUCT.table.col$ should not require table to be selected');
95        $this->assertEquals('data of page1', $result[0][1]->getValue());
96        $this->assertEquals('data of page2', $result[1][1]->getValue());
97    }
98
99    public function test_emptyfield()
100    {
101        global $ID;
102        $ID = 'no:data';
103        $lines = array(
104            "schema    : bar",
105            "cols      : %pageid%, data",
106            "filter    : %pageid% = \$STRUCT.foo.pages$"
107        );
108
109        $configParser = new meta\ConfigParser($lines);
110        $actual_config = $configParser->getConfig();
111
112        $search = new meta\SearchConfig($actual_config);
113        $result = $search->execute();
114
115        $this->assertEquals(0, count($result), 'if no pages a given, then none should be shown');
116    }
117
118    public function dataProvider_DataFiltersAsSubQuery()
119    {
120        return array(
121            array(
122                array(
123                    "filter    : data = foo"
124                ),
125                "AND ((data_bar.col1 != '' AND data_bar.col1 = ?))",
126                "The WHERE-clauses from page-syntax should be wrapped in parentheses"
127            ),
128            array(
129                array(
130                    "OR    : data = foo"
131                ),
132                "AND ((data_bar.col1 != '' AND data_bar.col1 = ?))",
133                "A single OR clause should be treated as AND clauses"
134            ),
135            array(
136                array(
137                    "filter    : data = foo",
138                    "OR        : data = bar"
139                ),
140                "AND ((data_bar.col1 != '' AND data_bar.col1 = ?) OR (data_bar.col1 != '' AND data_bar.col1 = ?))",
141                "The WHERE-clauses from page-syntax should be wrapped in parentheses"
142            ),
143            array(
144                array(
145                    "OR        : data = bar",
146                    "filter    : data = foo"
147                ),
148                "AND ((data_bar.col1 != '' AND data_bar.col1 = ?) AND (data_bar.col1 != '' AND data_bar.col1 = ?))",
149                "A single OR clause should be treated as AND clauses"
150            )
151        );
152    }
153
154    /**
155     * @dataProvider dataProvider_DataFiltersAsSubQuery
156     */
157    public function test_DataFiltersAsSubQuery($inputFilterLines, $expectedFilterWhere, $msg)
158    {
159        $lines = array(
160            "schema    : bar",
161            "cols      : %pageid%, data",
162        );
163
164        $lines = array_merge($lines, $inputFilterLines);
165
166        $configParser = new meta\ConfigParser($lines);
167        $actual_config = $configParser->getConfig();
168
169        $search = new meta\SearchConfig($actual_config);
170        list($sql,) = $search->getSQL();
171        $where = array_filter(explode("\n", $sql), function ($elem) {
172            return strpos($elem, 'WHERE') !== false;
173        });
174        $where = trim(reset($where));
175
176        $baseWhere = "WHERE  (
177                (
178                    data_bar.pid = '' OR (
179                        GETACCESSLEVEL(data_bar.pid) > 0
180                        AND PAGEEXISTS(data_bar.pid) = 1
181                        AND (ASSIGNED = 1 OR ASSIGNED IS NULL)
182                    )
183                )
184            AND data_bar.latest = 1";
185
186        $expected_where = $baseWhere . $expectedFilterWhere . " )";
187        $this->assertEquals($this->cleanWS($expected_where), $this->cleanWS($where), $msg);
188    }
189
190}
191