Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
54.55% covered (warning)
54.55%
30 / 55
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
table_helper
54.55% covered (warning)
54.55%
30 / 55
50.00% covered (danger)
50.00%
3 / 6
114.52
0.00% covered (danger)
0.00%
0 / 1
 convert_column_data
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 resolve_dbms_specific_options
84.21% covered (warning)
84.21%
16 / 19
0.00% covered (danger)
0.00%
0 / 1
11.48
 get_default_column_option
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
182
 map_short_table_names
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 generate_shortname
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13namespace phpbb\db\doctrine;
14
15use InvalidArgumentException;
16use phpbb\db\tools\doctrine as doctrine_dbtools;
17
18class table_helper
19{
20    /**
21     * Converts phpBB's column representation to Doctrine's representation.
22     *
23     * @param array $column_data Column data.
24     *
25     * @return array<string, array> A pair of type and array of column options.
26     * @psalm-return array{string, array}
27     */
28    public static function convert_column_data(array $column_data, string $dbms_layer): array
29    {
30        $options = self::resolve_dbms_specific_options($column_data, $dbms_layer);
31        list($type, $opts) = type_converter::convert($column_data[0], $dbms_layer);
32        $options = array_merge($options, $opts);
33        return [$type, $options];
34    }
35
36    /**
37     * Resolve DBMS specific options in column data.
38     *
39     * @param array  $column_data Original column data.
40     * @param string $dbms_layer  DBMS layer name.
41     *
42     * @return array Doctrine column options.
43     */
44    private static function resolve_dbms_specific_options(array $column_data, string $dbms_layer): array
45    {
46        $doctrine_options = [];
47
48        if (is_array($column_data[1]))
49        {
50            $column_data[1] = self::get_default_column_option($column_data[1], $dbms_layer);
51        }
52
53        if (!is_null($column_data[1]))
54        {
55            $doctrine_options['default'] = $column_data[1];
56            $doctrine_options['notnull'] = true;
57        }
58        else
59        {
60            $doctrine_options['notnull'] = false;
61        }
62
63        $non_string_pattern = '/^[a-z]*(?:int|decimal|bool|timestamp)(?::[0-9]+)?$/';
64        if ($dbms_layer === 'oracle'
65            && !preg_match($non_string_pattern, strtolower($column_data[0]))
66            && array_key_exists('default', $doctrine_options)
67            && $doctrine_options['default'] === '')
68        {
69            // Not null is true by default and Oracle does not allow empty strings in not null columns
70            $doctrine_options['notnull'] = false;
71        }
72
73        if (isset($column_data[2]))
74        {
75            if ($column_data[2] === 'auto_increment')
76            {
77                $doctrine_options['autoincrement'] = true;
78            }
79            else if ($dbms_layer === 'mysql' && $column_data[2] === 'true_sort')
80            {
81                $doctrine_options['platformoptions']['collation'] = 'utf8_unicode_ci';
82            }
83        }
84
85        return $doctrine_options;
86    }
87
88    /**
89     * Returns the DBMS specific default value for a column definition.
90     *
91     * @param array  $default_options Database specific default value options.
92     * @param string $dbms_layer      Name of the DBMS layer.
93     *
94     * @return mixed Default value for the current DBMS.
95     *
96     * @throws InvalidArgumentException When `$schema_name` contains an invalid legacy DBMS name.
97     */
98    private static function get_default_column_option(array $default_options, string $dbms_layer)
99    {
100        switch ($dbms_layer)
101        {
102            case 'mysql':
103                return array_key_exists('mysql_41', $default_options)
104                    ? $default_options['mysql_41']
105                    : $default_options['default'];
106            case 'oracle':
107                return array_key_exists('oracle', $default_options)
108                    ? $default_options['oracle']
109                    : $default_options['default'];
110            case 'postgresql':
111                return array_key_exists('postgres', $default_options)
112                    ? $default_options['postgres']
113                    : $default_options['default'];
114            case 'mssql':
115                return array_key_exists('mssqlnative', $default_options)
116                    ? $default_options['mssqlnative']
117                    : (array_key_exists('mssql', $default_options) ? $default_options['mssql'] : $default_options['default']);
118            case 'sqlite':
119                return array_key_exists('sqlite3', $default_options)
120                    ? $default_options['sqlite3']
121                    : $default_options['default'];
122            default:
123                throw new InvalidArgumentException('Invalid schema name.');
124        }
125    }
126
127    /**
128     * Maps table names to their short names for the purpose of prefixing tables' index names.
129     *
130     * @param array $table_names    Table names with prefix to add to the map.
131     * @param string $table_prefix    Tables prefix.
132     *
133     * @return array<string, string>    Pairs of table names and their short name representations.
134     * @psalm-return array{string, string}
135     */
136    public static function map_short_table_names(array $table_names = [], string $table_prefix = ''): array
137    {
138        $short_table_names_map = [];
139        foreach ($table_names as $table_name)
140        {
141            $short_table_names_map[$table_name] = self::generate_shortname(doctrine_dbtools::remove_prefix($table_name, $table_prefix));
142        }
143
144        return $short_table_names_map;
145    }
146
147    /**
148     * Generates short table names for the purpose of prefixing tables' index names.
149     *
150     * @param string $table_name    Table name without prefix to generate its short name.
151     *
152     * @return string    Short table name.
153     */
154    public static function generate_shortname(string $table_name = ''): string
155    {
156        // Only shorten actually long names
157        if (strlen($table_name) > 4)
158        {
159            // Remove vowels
160            $table_name = preg_replace('/([^aeiou_])([aeiou]+)/i', '$1', $table_name);
161
162            // Remove underscores
163            $table_name = str_replace('_', '', $table_name);
164
165            // Remove repeated consonants and their combinations (like 'ss', 'flfl' and similar)
166            $table_name = preg_replace('/(.+)\\1+/i', '$1', $table_name);
167
168            // Restrict short name length to 10 chars
169            $table_name = substr($table_name, 0, 10);
170        }
171
172        return $table_name;
173    }
174
175    /**
176     * Private constructor. Call methods of table_helper statically.
177     */
178    private function __construct()
179    {
180    }
181}