Passed
Branch feature-validator (0d7506)
by Thomas
02:52
created

Namer::getTableName()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 18
ccs 10
cts 10
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 10
nc 4
nop 3
crap 3
1
<?php
2
3
namespace ORM;
4
5
use ORM\Exceptions\InvalidConfiguration;
6
use ReflectionClass;
7
8
/**
9
 * Namer is for naming errors, columns, tables and methods
10
 *
11
 * Namer is an artificial word and is more a name giver. We just don't wanted to write so much.
12
 *
13
 * @package ORM
14
 */
15
class Namer
16
{
17
    /** The template to use to calculate the table name.
18
     * @var string */
19
    protected $tableNameTemplate = '%short%';
20
21
    /** The naming scheme to use for table names.
22
     * @var string */
23
    protected $tableNameScheme = 'snake_lower';
24
25
    /** The naming scheme to use for column names.
26
     * @var string */
27
    protected $columnNameScheme = 'snake_lower';
28
29
    /** The naming scheme used for method names.
30
     * @var string */
31
    protected $methodNameScheme = 'camelCase';
32
33
    /**
34
     * Namer constructor.
35
     *
36
     * @param array $options
37
     */
38 53
    public function __construct($options = [])
39
    {
40 53
        foreach ($options as $option => $value) {
41 2
            $this->setOption($option, $value);
42
        }
43 53
    }
44
45
    /**
46
     * Set $option to $value
47
     *
48
     * @param string $option
49
     * @param mixed $value
50
     * @return self
51
     */
52 2
    public function setOption($option, $value)
53
    {
54
        switch ($option) {
55 2
            case EntityManager::OPT_TABLE_NAME_TEMPLATE:
56 1
                $this->tableNameTemplate = $value;
57 1
                break;
58
59 1
            case EntityManager::OPT_NAMING_SCHEME_TABLE:
60 1
                $this->tableNameScheme = $value;
61 1
                break;
62
63
            case EntityManager::OPT_NAMING_SCHEME_COLUMN:
64
                $this->columnNameScheme = $value;
65
                break;
66
67
            case EntityManager::OPT_NAMING_SCHEME_METHODS:
68
                $this->methodNameScheme = $value;
69
                break;
70
        }
71
72 2
        return $this;
73
    }
74
75
    /**
76
     * Get the table name for $reflection
77
     *
78
     * @param ReflectionClass $reflection
79
     * @param null $template
80
     * @param null $namingScheme
81
     * @return string
82
     */
83 129
    public function getTableName(ReflectionClass $reflection, $template = null, $namingScheme = null)
84
    {
85 129
        if ($template === null) {
86 2
            $template = $this->tableNameTemplate;
87
        }
88
89 129
        if ($namingScheme === null) {
90 4
            $namingScheme = $this->tableNameScheme;
91
        }
92
93 129
        $name = $this->substitute($template, [
94 129
            'short' => $reflection->getShortName(),
95 129
            'namespace' => explode('\\', $reflection->getNamespaceName()),
96 129
            'name' => preg_split('/[\\\\_]+/', $reflection->getName()),
0 ignored issues
show
Bug introduced by
Consider using $reflection->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
97
        ]);
98
99 128
        return $this->forceNamingScheme($name, $namingScheme);
100
    }
101
102
    /**
103
     * Get the column name with $namingScheme or default naming scheme
104
     *
105
     * @param $field
106
     * @param null $namingScheme
107
     * @return string
108
     */
109 136
    public function getColumnName($field, $namingScheme = null)
110
    {
111 136
        if (!$namingScheme) {
112
            $namingScheme = $this->columnNameScheme;
113
        }
114
115 136
        return $this->forceNamingScheme($field, $namingScheme);
116
    }
117
118
    /**
119
     * Get the column name with $namingScheme or default naming scheme
120
     *
121
     * @param $name
122
     * @param null $namingScheme
123
     * @return string
124
     */
125 86
    public function getMethodName($name, $namingScheme = null)
126
    {
127 86
        if (!$namingScheme) {
128
            $namingScheme = $this->methodNameScheme;
129
        }
130
131 86
        return $this->forceNamingScheme($name, $namingScheme);
132
    }
133
134
    /**
135
     * Substitute a $template with $values
136
     *
137
     * $values is a key value pair array. The value should be a string or an array o
138
     *
139
     * @param string $template
140
     * @param array  $values
141
     * @param string $arrayGlue
142
     * @return string
143
     */
144 132
    public function substitute($template, $values = [], $arrayGlue = '_')
145
    {
146 132
        return preg_replace_callback(
147 132
            '/%(.*?)%/',
148
            function ($match) use ($values, $arrayGlue) {
149
                // escape % with another % ( %% => % )
150 132
                if ($match[0] === '%%') {
151 1
                    return '%';
152
                }
153
154 132
                $var = trim($match[1]);
155
156 132
                if (preg_match('/\[(-?\d+\*?)\]$/', $var, $arrayAccessor)) {
157 11
                    $var = substr($var, 0, strpos($var, '['));
158 11
                    $arrayAccessor = $arrayAccessor[1];
159
                }
160
161
                // throw when the variable is unknown
162 132
                if (!array_key_exists($var, $values)) {
163 1
                    throw new InvalidConfiguration(
164 1
                        'Template invalid: Placeholder %' . $match[1] . '% is not allowed'
165
                    );
166
                }
167
168 131
                if (is_scalar($values[$var]) || is_null($values[$var])) {
169 115
                    return (string)$values[$var];
170
                }
171
172
                // otherwise we assume it is an array
173 16
                $array = $values[$var];
174
175 16
                if (isset($arrayAccessor[0])) {
176 11
                    $from = $arrayAccessor[0] === '-' ?
177 11
                        count($array) - abs($arrayAccessor) : (int)$arrayAccessor;
178
179 11
                    if ($from >= count($array)) {
180 2
                        return '';
181
                    }
182
183 9
                    $array = substr($arrayAccessor, -1) === '*' ?
184 9
                        array_slice($array, $from) : [$array[$from]];
185
                }
186
187 14
                return implode($arrayGlue, $array);
188 132
            },
189
            $template
190
        );
191
    }
192
193
    /**
194
     * Enforce $namingScheme to $name
195
     *
196
     * Supported naming schemes: snake_case, snake_lower, SNAKE_UPPER, Snake_Ucfirst, camelCase, StudlyCaps, lower
197
     * and UPPER.
198
     *
199
     * @param string $name         The name of the var / column
200
     * @param string $namingScheme The naming scheme to use
201
     * @return string
202
     * @throws InvalidConfiguration
203
     */
204 221
    public function forceNamingScheme($name, $namingScheme)
205
    {
206 221
        $words = explode('_', preg_replace(
207 221
            '/([a-z0-9])([A-Z])/',
208 221
            '$1_$2',
209 221
            preg_replace_callback('/([a-z0-9])?([A-Z]+)([A-Z][a-z])/', function ($d) {
210 24
                return ($d[1] ? $d[1] . '_' : '') . $d[2] . '_' . $d[3];
211 221
            }, $name)
212
        ));
213
214
        switch ($namingScheme) {
215 221
            case 'snake_case':
216 25
                $newName = implode('_', $words);
217 25
                break;
218
219 196
            case 'snake_lower':
220 165
                $newName = implode('_', array_map('strtolower', $words));
221 165
                break;
222
223 114
            case 'SNAKE_UPPER':
224 4
                $newName = implode('_', array_map('strtoupper', $words));
225 4
                break;
226
227 110
            case 'Snake_Ucfirst':
228 4
                $newName = implode('_', array_map('ucfirst', $words));
229 4
                break;
230
231 106
            case 'camelCase':
232 89
                $newName = lcfirst(implode('', array_map('ucfirst', array_map('strtolower', $words))));
233 89
                break;
234
235 17
            case 'StudlyCaps':
236 8
                $newName = implode('', array_map('ucfirst', array_map('strtolower', $words)));
237 8
                break;
238
239 9
            case 'lower':
240 4
                $newName = implode('', array_map('strtolower', $words));
241 4
                break;
242
243 5
            case 'UPPER':
244 4
                $newName = implode('', array_map('strtoupper', $words));
245 4
                break;
246
247
            default:
248 1
                throw new InvalidConfiguration('Naming scheme ' . $namingScheme . ' unknown');
249
        }
250
251 220
        return $newName;
252
    }
253
}
254