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