Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
540 / 540
100.00% covered (success)
100.00%
56 / 56
CRAP
100.00% covered (success)
100.00%
1 / 1
DatabaseSchema
100.00% covered (success)
100.00%
540 / 540
100.00% covered (success)
100.00%
56 / 56
56
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllTables
100.00% covered (success)
100.00%
55 / 55
100.00% covered (success)
100.00%
1 / 1
1
 getTableNames
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 adminLog
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 attachment
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 attachmentFile
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 backup
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 faqbookmarks
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 faqcaptcha
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 faqcategories
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 faqcategoryNews
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqcategoryrelations
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 faqcategoryGroup
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqcategoryUser
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqcategoryOrder
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 faqchanges
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 faqcomments
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 faqconfig
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqdata
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
1
 faqdataRevisions
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
1
 faqdataGroup
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqdataTags
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqdataUser
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqforms
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 faqglossary
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 faqgroup
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 faqgroupRight
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqgroupRightCategory
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 faqinstances
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 faqinstancesConfig
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 faqapiKeys
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 faqoauthClients
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 faqoauthScopes
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqoauthAccessTokens
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 faqoauthRefreshTokens
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 faqoauthAuthCodes
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 faqnews
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
1
 faqcustompages
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
1
 faqjobs
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 faqquestions
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 faqright
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 faqsearches
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 faqseo
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 faqsessions
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 faqstopwords
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 faqtags
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faquser
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
1
 faquserdata
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 faquserlogin
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 faquserGroup
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faquserRight
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 faqvisits
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 faqvoting
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 faqchatMessages
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 faqpushSubscriptions
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
1
 faqadmindashboard
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * Dialect-agnostic database schema definition for phpMyFAQ.
5 *
6 * Single source of truth for the entire database schema. Each method returns
7 * a configured TableBuilder instance for one table.
8 *
9 * This Source Code Form is subject to the terms of the Mozilla Public License,
10 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
11 * obtain one at https://mozilla.org/MPL/2.0/.
12 *
13 * @package   phpMyFAQ
14 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
15 * @copyright 2026 phpMyFAQ Team
16 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
17 * @link      https://www.phpmyfaq.de
18 * @since     2026-01-31
19 */
20
21declare(strict_types=1);
22
23namespace phpMyFAQ\Setup\Installation;
24
25use phpMyFAQ\Setup\Migration\QueryBuilder\DialectInterface;
26use phpMyFAQ\Setup\Migration\QueryBuilder\TableBuilder;
27
28/* @mago-expect lint:too-many-methods - one builder per table in the installation schema */
29class DatabaseSchema
30{
31    public function __construct(
32        private readonly DialectInterface $dialect,
33    ) {
34    }
35
36    /**
37     * Returns all table definitions in creation order.
38     *
39     * @return array<string, TableBuilder>
40     */
41    public function getAllTables(): array
42    {
43        return [
44            'faqadminlog' => $this->adminLog(),
45            'faqattachment' => $this->attachment(),
46            'faqattachment_file' => $this->attachmentFile(),
47            'faqbackup' => $this->backup(),
48            'faqbookmarks' => $this->faqbookmarks(),
49            'faqcaptcha' => $this->faqcaptcha(),
50            'faqcategories' => $this->faqcategories(),
51            'faqcategory_news' => $this->faqcategoryNews(),
52            'faqcategoryrelations' => $this->faqcategoryrelations(),
53            'faqcategory_group' => $this->faqcategoryGroup(),
54            'faqcategory_user' => $this->faqcategoryUser(),
55            'faqcategory_order' => $this->faqcategoryOrder(),
56            'faqchanges' => $this->faqchanges(),
57            'faqcomments' => $this->faqcomments(),
58            'faqconfig' => $this->faqconfig(),
59            'faqdata' => $this->faqdata(),
60            'faqdata_revisions' => $this->faqdataRevisions(),
61            'faqdata_group' => $this->faqdataGroup(),
62            'faqdata_tags' => $this->faqdataTags(),
63            'faqdata_user' => $this->faqdataUser(),
64            'faqforms' => $this->faqforms(),
65            'faqglossary' => $this->faqglossary(),
66            'faqgroup' => $this->faqgroup(),
67            'faqgroup_right' => $this->faqgroupRight(),
68            'faqgroup_right_category' => $this->faqgroupRightCategory(),
69            'faqapi_keys' => $this->faqapiKeys(),
70            'faqoauth_clients' => $this->faqoauthClients(),
71            'faqoauth_scopes' => $this->faqoauthScopes(),
72            'faqoauth_access_tokens' => $this->faqoauthAccessTokens(),
73            'faqoauth_refresh_tokens' => $this->faqoauthRefreshTokens(),
74            'faqoauth_auth_codes' => $this->faqoauthAuthCodes(),
75            'faqinstances' => $this->faqinstances(),
76            'faqinstances_config' => $this->faqinstancesConfig(),
77            'faqnews' => $this->faqnews(),
78            'faqcustompages' => $this->faqcustompages(),
79            'faqjobs' => $this->faqjobs(),
80            'faqquestions' => $this->faqquestions(),
81            'faqright' => $this->faqright(),
82
83            'faqsearches' => $this->faqsearches(),
84            'faqseo' => $this->faqseo(),
85            'faqsessions' => $this->faqsessions(),
86            'faqstopwords' => $this->faqstopwords(),
87            'faqtags' => $this->faqtags(),
88            'faquser' => $this->faquser(),
89            'faquserdata' => $this->faquserdata(),
90            'faquserlogin' => $this->faquserlogin(),
91            'faquser_group' => $this->faquserGroup(),
92            'faquser_right' => $this->faquserRight(),
93            'faqvisits' => $this->faqvisits(),
94            'faqvoting' => $this->faqvoting(),
95            'faqchat_messages' => $this->faqchatMessages(),
96            'faqpush_subscriptions' => $this->faqpushSubscriptions(),
97            'faqadmindashboard' => $this->faqadmindashboard(),
98        ];
99    }
100
101    /**
102     * Returns the table names in order.
103     *
104     * @return string[]
105     */
106    public function getTableNames(): array
107    {
108        return array_keys($this->getAllTables());
109    }
110
111    public function adminLog(): TableBuilder
112    {
113        return new TableBuilder($this->dialect)
114            ->table('faqadminlog')
115            ->integer('id', false)
116            ->integer('time', false)
117            ->integer('usr', false)
118            ->text('text', false)
119            ->varchar('hash', 64)
120            ->varchar('previous_hash', 64)
121            ->varchar('ip', 64, false)
122            ->primaryKey('id');
123    }
124
125    public function attachment(): TableBuilder
126    {
127        return new TableBuilder($this->dialect)
128            ->table('faqattachment')
129            ->integer('id', false)
130            ->integer('record_id', false)
131            ->varchar('record_lang', 5, false)
132            ->char('real_hash', 32, false)
133            ->char('virtual_hash', 32, false)
134            ->char('password_hash', 40)
135            ->varchar('filename', 255, false)
136            ->integer('filesize', false)
137            ->integer('encrypted', false, 0)
138            ->varchar('mime_type', 255)
139            ->primaryKey('id');
140    }
141
142    public function attachmentFile(): TableBuilder
143    {
144        return new TableBuilder($this->dialect)
145            ->table('faqattachment_file')
146            ->char('virtual_hash', 32, false)
147            ->blob('contents', false)
148            ->primaryKey('virtual_hash');
149    }
150
151    public function backup(): TableBuilder
152    {
153        return new TableBuilder($this->dialect)
154            ->table('faqbackup')
155            ->integer('id', false)
156            ->varchar('filename', 255, false)
157            ->varchar('authkey', 255, false)
158            ->varchar('authcode', 255, false)
159            ->timestamp('created', false)
160            ->primaryKey('id');
161    }
162
163    public function faqbookmarks(): TableBuilder
164    {
165        return new TableBuilder($this->dialect)
166            ->table('faqbookmarks')
167            ->integer('userid')
168            ->integer('faqid');
169    }
170
171    public function faqcaptcha(): TableBuilder
172    {
173        return new TableBuilder($this->dialect)
174            ->table('faqcaptcha')
175            ->varchar('id', 6, false)
176            ->varchar('useragent', 255, false)
177            ->varchar('language', 5, false)
178            ->varchar('ip', 64, false)
179            ->integer('captcha_time', false)
180            ->primaryKey('id');
181    }
182
183    public function faqcategories(): TableBuilder
184    {
185        return new TableBuilder($this->dialect)
186            ->table('faqcategories')
187            ->integer('id', false)
188            ->varchar('lang', 5, false)
189            ->integer('parent_id', false)
190            ->varchar('name', 255, false)
191            ->varchar('description', 255)
192            ->integer('user_id', false)
193            ->integer('group_id', false, -1)
194            ->integer('active', true, 1)
195            ->varchar('image', 255)
196            ->smallInteger('show_home')
197            ->primaryKey(['id', 'lang']);
198    }
199
200    public function faqcategoryNews(): TableBuilder
201    {
202        return new TableBuilder($this->dialect)
203            ->table('faqcategory_news')
204            ->integer('category_id', false)
205            ->integer('news_id', false)
206            ->primaryKey(['category_id', 'news_id']);
207    }
208
209    public function faqcategoryrelations(): TableBuilder
210    {
211        return new TableBuilder($this->dialect)
212            ->table('faqcategoryrelations')
213            ->integer('category_id', false)
214            ->varchar('category_lang', 5, false)
215            ->integer('record_id', false)
216            ->varchar('record_lang', 5, false)
217            ->primaryKey(['category_id', 'category_lang', 'record_id', 'record_lang'])
218            ->index('idx_records', ['record_id', 'record_lang']);
219    }
220
221    public function faqcategoryGroup(): TableBuilder
222    {
223        return new TableBuilder($this->dialect)
224            ->table('faqcategory_group')
225            ->integer('category_id', false)
226            ->integer('group_id', false)
227            ->primaryKey(['category_id', 'group_id']);
228    }
229
230    public function faqcategoryUser(): TableBuilder
231    {
232        return new TableBuilder($this->dialect)
233            ->table('faqcategory_user')
234            ->integer('category_id', false)
235            ->integer('user_id', false)
236            ->primaryKey(['category_id', 'user_id']);
237    }
238
239    public function faqcategoryOrder(): TableBuilder
240    {
241        return new TableBuilder($this->dialect)
242            ->table('faqcategory_order')
243            ->integer('category_id', false)
244            ->integer('parent_id')
245            ->integer('position', false)
246            ->primaryKey('category_id');
247    }
248
249    public function faqchanges(): TableBuilder
250    {
251        return new TableBuilder($this->dialect)
252            ->table('faqchanges')
253            ->integer('id', false)
254            ->smallInteger('beitrag', false)
255            ->varchar('lang', 5, false)
256            ->integer('revision_id', false, 0)
257            ->integer('usr', false)
258            ->integer('datum', false)
259            ->text('what')
260            ->primaryKey(['id', 'lang']);
261    }
262
263    public function faqcomments(): TableBuilder
264    {
265        return new TableBuilder($this->dialect)
266            ->table('faqcomments')
267            ->integer('id_comment', false)
268            ->integer('id', false)
269            ->varchar('type', 10, false)
270            ->varchar('usr', 255, false)
271            ->varchar('email', 255, false)
272            ->text('comment', false)
273            ->varchar('datum', 64, false)
274            ->text('helped')
275            ->primaryKey('id_comment');
276    }
277
278    public function faqconfig(): TableBuilder
279    {
280        return new TableBuilder($this->dialect)
281            ->table('faqconfig')
282            ->varchar('config_name', 255, false, '')
283            ->text('config_value')
284            ->primaryKey('config_name');
285    }
286
287    public function faqdata(): TableBuilder
288    {
289        return new TableBuilder($this->dialect)
290            ->table('faqdata')
291            ->integer('id', false)
292            ->varchar('lang', 5, false)
293            ->integer('solution_id', false)
294            ->integer('revision_id', false, 0)
295            ->char('active', 3, false)
296            ->integer('sticky', false)
297            ->text('keywords')
298            ->text('thema', false)
299            ->longText('content')
300            ->varchar('author', 255, false)
301            ->varchar('email', 255, false)
302            ->char('comment', 1, true, 'y')
303            ->varchar('updated', 15, false)
304            ->varchar('date_start', 14, false, '00000000000000')
305            ->varchar('date_end', 14, false, '99991231235959')
306            ->timestamp('created', true, true)
307            ->text('notes')
308            ->integer('sticky_order')
309            ->fullTextIndex(['keywords', 'thema', 'content'])
310            ->primaryKey(['id', 'lang']);
311    }
312
313    public function faqdataRevisions(): TableBuilder
314    {
315        return new TableBuilder($this->dialect)
316            ->table('faqdata_revisions')
317            ->integer('id', false)
318            ->varchar('lang', 5, false)
319            ->integer('solution_id', false)
320            ->integer('revision_id', false, 0)
321            ->char('active', 3, false)
322            ->integer('sticky', false)
323            ->text('keywords')
324            ->text('thema', false)
325            ->longText('content')
326            ->varchar('author', 255, false)
327            ->varchar('email', 255, false)
328            ->char('comment', 1, true, 'y')
329            ->varchar('updated', 15, false)
330            ->varchar('date_start', 14, false, '00000000000000')
331            ->varchar('date_end', 14, false, '99991231235959')
332            ->timestamp('created', true, true)
333            ->text('notes')
334            ->integer('sticky_order')
335            ->primaryKey(['id', 'lang', 'solution_id', 'revision_id']);
336    }
337
338    public function faqdataGroup(): TableBuilder
339    {
340        return new TableBuilder($this->dialect)
341            ->table('faqdata_group')
342            ->integer('record_id', false)
343            ->integer('group_id', false)
344            ->primaryKey(['record_id', 'group_id']);
345    }
346
347    public function faqdataTags(): TableBuilder
348    {
349        return new TableBuilder($this->dialect)
350            ->table('faqdata_tags')
351            ->integer('record_id', false)
352            ->integer('tagging_id', false)
353            ->primaryKey(['record_id', 'tagging_id']);
354    }
355
356    public function faqdataUser(): TableBuilder
357    {
358        return new TableBuilder($this->dialect)
359            ->table('faqdata_user')
360            ->integer('record_id', false)
361            ->integer('user_id', false)
362            ->primaryKey(['record_id', 'user_id']);
363    }
364
365    public function faqforms(): TableBuilder
366    {
367        return new TableBuilder($this->dialect)
368            ->table('faqforms')
369            ->integer('form_id', false)
370            ->integer('input_id', false)
371            ->varchar('input_type', 1000, false)
372            ->varchar('input_label', 500, false)
373            ->integer('input_active', false)
374            ->integer('input_required', false)
375            ->varchar('input_lang', 11, false);
376    }
377
378    public function faqglossary(): TableBuilder
379    {
380        return new TableBuilder($this->dialect)
381            ->table('faqglossary')
382            ->integer('id', false)
383            ->varchar('lang', 5, false)
384            ->varchar('item', 255, false)
385            ->text('definition', false)
386            ->primaryKey(['id', 'lang']);
387    }
388
389    public function faqgroup(): TableBuilder
390    {
391        return new TableBuilder($this->dialect)
392            ->table('faqgroup')
393            ->integer('group_id', false)
394            ->varchar('name', 25)
395            ->text('description')
396            ->integer('auto_join')
397            ->primaryKey('group_id')
398            ->index('idx_name', 'name');
399    }
400
401    public function faqgroupRight(): TableBuilder
402    {
403        return new TableBuilder($this->dialect)
404            ->table('faqgroup_right')
405            ->integer('group_id', false)
406            ->integer('right_id', false)
407            ->primaryKey(['group_id', 'right_id']);
408    }
409
410    public function faqgroupRightCategory(): TableBuilder
411    {
412        return new TableBuilder($this->dialect)
413            ->table('faqgroup_right_category')
414            ->integer('group_id', false)
415            ->integer('right_id', false)
416            ->integer('category_id', false)
417            ->primaryKey(['group_id', 'right_id', 'category_id']);
418    }
419
420    public function faqinstances(): TableBuilder
421    {
422        return new TableBuilder($this->dialect)
423            ->table('faqinstances')
424            ->integer('id', false)
425            ->varchar('url', 255, false)
426            ->varchar('instance', 255, false)
427            ->text('comment')
428            ->timestamp('created', false)
429            ->timestamp('modified', false)
430            ->primaryKey('id');
431    }
432
433    public function faqinstancesConfig(): TableBuilder
434    {
435        return new TableBuilder($this->dialect)
436            ->table('faqinstances_config')
437            ->integer('instance_id', false)
438            ->varchar('config_name', 255, false, '')
439            ->varchar('config_value', 255)
440            ->primaryKey(['instance_id', 'config_name']);
441    }
442
443    public function faqapiKeys(): TableBuilder
444    {
445        return new TableBuilder($this->dialect)
446            ->table('faqapi_keys')
447            ->integer('id', false)
448            ->integer('user_id', false)
449            ->varchar('api_key', 64, false)
450            ->varchar('name', 255)
451            ->text('scopes')
452            ->timestamp('last_used_at')
453            ->timestamp('expires_at')
454            ->timestamp('created', false, true)
455            ->primaryKey('id')
456            ->uniqueIndex('idx_api_key_unique', 'api_key')
457            ->index('idx_api_key_user', 'user_id');
458    }
459
460    public function faqoauthClients(): TableBuilder
461    {
462        return new TableBuilder($this->dialect)
463            ->table('faqoauth_clients')
464            ->varchar('client_id', 80, false)
465            ->varchar('client_secret', 255)
466            ->varchar('name', 255, false)
467            ->text('redirect_uri')
468            ->varchar('grants', 255)
469            ->smallInteger('is_confidential', true, 1)
470            ->integer('user_id')
471            ->timestamp('created', false, true)
472            ->primaryKey('client_id');
473    }
474
475    public function faqoauthScopes(): TableBuilder
476    {
477        return new TableBuilder($this->dialect)
478            ->table('faqoauth_scopes')
479            ->varchar('scope_id', 80, false)
480            ->varchar('description', 255)
481            ->primaryKey('scope_id');
482    }
483
484    public function faqoauthAccessTokens(): TableBuilder
485    {
486        return new TableBuilder($this->dialect)
487            ->table('faqoauth_access_tokens')
488            ->varchar('identifier', 100, false)
489            ->varchar('client_id', 80, false)
490            ->varchar('user_id', 80)
491            ->text('scopes')
492            ->smallInteger('revoked', true, 0)
493            ->timestamp('expires_at', false)
494            ->timestamp('created', false, true)
495            ->primaryKey('identifier')
496            ->index('idx_oauth_access_client', 'client_id')
497            ->index('idx_oauth_access_user', 'user_id');
498    }
499
500    public function faqoauthRefreshTokens(): TableBuilder
501    {
502        return new TableBuilder($this->dialect)
503            ->table('faqoauth_refresh_tokens')
504            ->varchar('identifier', 100, false)
505            ->varchar('access_token_identifier', 100, false)
506            ->smallInteger('revoked', true, 0)
507            ->timestamp('expires_at', false)
508            ->timestamp('created', false, true)
509            ->primaryKey('identifier')
510            ->index('idx_oauth_refresh_access', 'access_token_identifier');
511    }
512
513    public function faqoauthAuthCodes(): TableBuilder
514    {
515        return new TableBuilder($this->dialect)
516            ->table('faqoauth_auth_codes')
517            ->varchar('identifier', 100, false)
518            ->varchar('client_id', 80, false)
519            ->varchar('user_id', 80)
520            ->text('redirect_uri')
521            ->text('scopes')
522            ->smallInteger('revoked', true, 0)
523            ->timestamp('expires_at', false)
524            ->timestamp('created', false, true)
525            ->primaryKey('identifier')
526            ->index('idx_oauth_code_client', 'client_id')
527            ->index('idx_oauth_code_user', 'user_id');
528    }
529
530    public function faqnews(): TableBuilder
531    {
532        return new TableBuilder($this->dialect)
533            ->table('faqnews')
534            ->integer('id', false)
535            ->varchar('lang', 5, false)
536            ->varchar('header', 255, false)
537            ->text('artikel', false)
538            ->varchar('datum', 14, false)
539            ->varchar('author_name', 255)
540            ->varchar('author_email', 255)
541            ->char('active', 1, true, 'y')
542            ->char('comment', 1, true, 'n')
543            ->varchar('link', 255)
544            ->varchar('linktitel', 255)
545            ->varchar('target', 255, false)
546            ->primaryKey('id');
547    }
548
549    public function faqcustompages(): TableBuilder
550    {
551        return new TableBuilder($this->dialect)
552            ->table('faqcustompages')
553            ->integer('id', false)
554            ->varchar('lang', 5, false)
555            ->varchar('page_title', 255, false)
556            ->varchar('slug', 255, false)
557            ->text('content', false)
558            ->varchar('author_name', 255, false)
559            ->varchar('author_email', 255, false)
560            ->char('active', 1, false, 'n')
561            ->timestamp('created', false, true)
562            ->timestamp('updated')
563            ->varchar('seo_title', 60)
564            ->varchar('seo_description', 160)
565            ->varchar('seo_robots', 50, false, 'index,follow')
566            ->primaryKey(['id', 'lang'])
567            ->index('idx_custompages_slug', ['slug', 'lang']);
568    }
569
570    public function faqjobs(): TableBuilder
571    {
572        return new TableBuilder($this->dialect)
573            ->table('faqjobs')
574            ->autoIncrement('id')
575            ->varchar('queue', 100, false, 'default')
576            ->text('body', false)
577            ->text('headers')
578            ->timestamp('available_at', false)
579            ->timestamp('delivered_at')
580            ->timestamp('created', false, true)
581            ->index('idx_faqjobs_queue_available', ['queue', 'available_at'])
582            ->index('idx_faqjobs_delivered_at', 'delivered_at');
583    }
584
585    public function faqquestions(): TableBuilder
586    {
587        return new TableBuilder($this->dialect)
588            ->table('faqquestions')
589            ->integer('id', false)
590            ->varchar('lang', 5, false)
591            ->varchar('username', 100, false)
592            ->varchar('email', 100, false)
593            ->integer('category_id', false)
594            ->text('question', false)
595            ->varchar('created', 20, false)
596            ->char('is_visible', 1, true, 'Y')
597            ->integer('answer_id', false, 0)
598            ->primaryKey('id');
599    }
600
601    public function faqright(): TableBuilder
602    {
603        return new TableBuilder($this->dialect)
604            ->table('faqright')
605            ->integer('right_id', false)
606            ->varchar('name', 50)
607            ->text('description')
608            ->integer('for_users', true, 1)
609            ->integer('for_groups', true, 1)
610            ->integer('for_sections', true, 1)
611            ->primaryKey('right_id');
612    }
613
614    public function faqsearches(): TableBuilder
615    {
616        return new TableBuilder($this->dialect)
617            ->table('faqsearches')
618            ->integer('id', false)
619            ->varchar('lang', 5, false)
620            ->varchar('searchterm', 255, false)
621            ->timestamp('searchdate', false, true)
622            ->primaryKey(['id', 'lang'])
623            ->index('idx_faqsearches_searchterm', 'searchterm')
624            ->index('idx_faqsearches_date_term', ['searchdate', 'searchterm'])
625            ->index('idx_faqsearches_date_term_lang', ['searchdate', 'searchterm', 'lang']);
626    }
627
628    public function faqseo(): TableBuilder
629    {
630        return new TableBuilder($this->dialect)
631            ->table('faqseo')
632            ->integer('id', false)
633            ->varchar('type', 32, false)
634            ->integer('reference_id', false)
635            ->varchar('reference_language', 5, false)
636            ->text('title')
637            ->text('description')
638            ->text('slug')
639            ->timestamp('created', false, true)
640            ->primaryKey('id');
641    }
642
643    public function faqsessions(): TableBuilder
644    {
645        return new TableBuilder($this->dialect)
646            ->table('faqsessions')
647            ->integer('sid', false)
648            ->integer('user_id', false)
649            ->varchar('ip', 64, false)
650            ->integer('time', false)
651            ->primaryKey('sid')
652            ->index('idx_time', 'time');
653    }
654
655    public function faqstopwords(): TableBuilder
656    {
657        return new TableBuilder($this->dialect)
658            ->table('faqstopwords')
659            ->integer('id', false)
660            ->varchar('lang', 5, false)
661            ->varchar('stopword', 64, false)
662            ->primaryKey(['id', 'lang']);
663    }
664
665    public function faqtags(): TableBuilder
666    {
667        return new TableBuilder($this->dialect)
668            ->table('faqtags')
669            ->integer('tagging_id', false)
670            ->varchar('tagging_name', 255, false)
671            ->primaryKey(['tagging_id', 'tagging_name']);
672    }
673
674    public function faquser(): TableBuilder
675    {
676        return new TableBuilder($this->dialect)
677            ->table('faquser')
678            ->integer('user_id', false)
679            ->varchar('login', 128, false)
680            ->varchar('session_id', 150)
681            ->integer('session_timestamp')
682            ->varchar('ip', 64)
683            ->varchar('account_status', 50)
684            ->varchar('last_login', 14)
685            ->varchar('auth_source', 100)
686            ->varchar('member_since', 14)
687            ->varchar('remember_me', 150)
688            ->smallInteger('success', true, 1)
689            ->smallInteger('is_superadmin', true, 0)
690            ->smallInteger('login_attempts', true, 0)
691            ->text('refresh_token')
692            ->text('access_token')
693            ->varchar('code_verifier', 255)
694            ->text('jwt')
695            ->text('webauthnkeys')
696            ->primaryKey('user_id');
697    }
698
699    public function faquserdata(): TableBuilder
700    {
701        return new TableBuilder($this->dialect)
702            ->table('faquserdata')
703            ->integer('user_id', false)
704            ->varchar('last_modified', 14)
705            ->varchar('display_name', 128)
706            ->varchar('email', 128)
707            ->varchar('keycloak_sub', 255)
708            ->smallInteger('is_visible', true, 0)
709            ->smallInteger('twofactor_enabled', true, 0)
710            ->varchar('secret', 128);
711    }
712
713    public function faquserlogin(): TableBuilder
714    {
715        return new TableBuilder($this->dialect)
716            ->table('faquserlogin')
717            ->varchar('login', 128, false)
718            ->varchar('pass', 80)
719            ->varchar('domain', 255)
720            ->primaryKey('login');
721    }
722
723    public function faquserGroup(): TableBuilder
724    {
725        return new TableBuilder($this->dialect)
726            ->table('faquser_group')
727            ->integer('user_id', false)
728            ->integer('group_id', false)
729            ->primaryKey(['user_id', 'group_id']);
730    }
731
732    public function faquserRight(): TableBuilder
733    {
734        return new TableBuilder($this->dialect)
735            ->table('faquser_right')
736            ->integer('user_id', false)
737            ->integer('right_id', false)
738            ->primaryKey(['user_id', 'right_id']);
739    }
740
741    public function faqvisits(): TableBuilder
742    {
743        return new TableBuilder($this->dialect)
744            ->table('faqvisits')
745            ->integer('id', false)
746            ->varchar('lang', 5, false)
747            ->integer('visits', false)
748            ->integer('last_visit', false)
749            ->primaryKey(['id', 'lang']);
750    }
751
752    public function faqvoting(): TableBuilder
753    {
754        return new TableBuilder($this->dialect)
755            ->table('faqvoting')
756            ->integer('id', false)
757            ->integer('artikel', false)
758            ->integer('vote', false)
759            ->integer('usr', false)
760            ->varchar('datum', 20, true, '')
761            ->varchar('ip', 15, true, '')
762            ->primaryKey('id');
763    }
764
765    public function faqchatMessages(): TableBuilder
766    {
767        return new TableBuilder($this->dialect)
768            ->table('faqchat_messages')
769            ->autoIncrement('id')
770            ->integer('sender_id', false)
771            ->integer('recipient_id', false)
772            ->text('message', false)
773            ->boolean('is_read', false, false)
774            ->timestamp('created_at', false, true)
775            ->index('idx_chat_sender', 'sender_id')
776            ->index('idx_chat_recipient', 'recipient_id')
777            ->index('idx_chat_conversation', ['sender_id', 'recipient_id'])
778            ->index('idx_chat_created', 'created_at');
779    }
780
781    public function faqpushSubscriptions(): TableBuilder
782    {
783        return new TableBuilder($this->dialect)
784            ->table('faqpush_subscriptions')
785            ->autoIncrement('id')
786            ->integer('user_id', false)
787            ->text('endpoint', false)
788            ->varchar('endpoint_hash', 64, false)
789            ->text('public_key', false)
790            ->text('auth_token', false)
791            ->varchar('content_encoding', 50)
792            ->timestamp('created_at', false, true)
793            ->index('idx_push_user_id', 'user_id')
794            ->uniqueIndex('idx_push_endpoint_hash', 'endpoint_hash');
795    }
796
797    public function faqadmindashboard(): TableBuilder
798    {
799        return new TableBuilder($this->dialect)
800            ->table('faqadmindashboard')
801            ->integer('user_id', false)
802            ->text('config')
803            ->primaryKey('user_id');
804    }
805}