Passed
Push — master ( 050c29...4fa43a )
by Thomas
58s
created

Namer::forceNamingScheme()   C

Complexity

Conditions 10
Paths 9

Size

Total Lines 49
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 10

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 33
cts 33
cp 1
rs 5.5471
c 0
b 0
f 0
cc 10
eloc 35
nc 9
nop 2
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace ORM;
4
5
use ORM\Exception\InvalidConfiguration;
6
use ORM\Exception\InvalidName;
7
use ReflectionClass;
8
9
/**
10
 * Namer is for naming errors, columns, tables and methods
11
 *
12
 * Namer is an artificial word and is more a name giver. We just don't wanted to write so much.
13
 *
14
 * @package ORM
15
 * @author  Thomas Flori <[email protected]>
16
 */
17
class Namer
18
{
19
    /** The template to use to calculate the table name.
20
     * @var string */
21
    protected $tableNameTemplate = '%short%';
22
23
    /** The naming scheme to use for table names.
24
     * @var string */
25
    protected $tableNameScheme = 'snake_lower';
26
27
    /** @var string[] */
28
    protected $tableNames = [];
29
30
    /** @var string[][] */
31
    protected $columnNames = [];
32
33
    /** The naming scheme to use for column names.
34
     * @var string */
35
    protected $columnNameScheme = 'snake_lower';
36
37
    /** The naming scheme used for method names.
38
     * @var string */
39
    protected $methodNameScheme = 'camelCase';
40
41
    /**
42
     * Namer constructor.
43
     *
44
     * @param array $options
45
     */
46 293
    public function __construct($options = [])
47
    {
48 293
        foreach ($options as $option => $value) {
49 4
            $this->setOption($option, $value);
50
        }
51 293
    }
52
53
    /**
54
     * Set $option to $value
55
     *
56
     * @param string $option
57
     * @param mixed  $value
58
     * @return self
59
     */
60 4
    public function setOption($option, $value)
61
    {
62
        switch ($option) {
63 4
            case EntityManager::OPT_TABLE_NAME_TEMPLATE:
64 1
                $this->tableNameTemplate = $value;
65 1
                break;
66
67 3
            case EntityManager::OPT_NAMING_SCHEME_TABLE:
68 1
                $this->tableNameScheme = $value;
69 1
                break;
70
71 2
            case EntityManager::OPT_NAMING_SCHEME_COLUMN:
72 1
                $this->columnNameScheme = $value;
73 1
                break;
74
75 1
            case EntityManager::OPT_NAMING_SCHEME_METHODS:
76 1
                $this->methodNameScheme = $value;
77 1
                break;
78
        }
79
80 4
        return $this;
81
    }
82
83
    /**
84
     * Get the table name for $reflection
85
     *
86
     * @param string $class
87
     * @param string $template
88
     * @param string $namingScheme
89
     * @return string
90
     * @throws InvalidName
91
     */
92 147
    public function getTableName($class, $template = null, $namingScheme = null)
93
    {
94 147
        if (!isset($this->tableNames[$class])) {
95 147
            if ($template === null) {
96 2
                $template = $this->tableNameTemplate;
97
            }
98
99 147
            if ($namingScheme === null) {
100 4
                $namingScheme = $this->tableNameScheme;
101
            }
102
103 147
            $reflection = new ReflectionClass($class);
104
105 147
            $name = $this->substitute(
106
                $template,
107
                [
108 147
                    'short'     => $reflection->getShortName(),
109 147
                    'namespace' => explode('\\', $reflection->getNamespaceName()),
110 147
                    'name'      => preg_split('/[\\\\_]+/', $reflection->name),
111
                ],
112 147
                '_'
113
            );
114
115 146
            if (empty($name)) {
116 2
                throw new InvalidName('Table name can not be empty');
117
            }
118
119 144
            $this->tableNames[$class] = $this->forceNamingScheme($name, $namingScheme);
120
        }
121
122 143
        return $this->tableNames[$class];
123
    }
124
125
    /**
126
     * Get the column name with $namingScheme or default naming scheme
127
     *
128
     * @param string $class
129
     * @param string $attribute
130
     * @param string $prefix
131
     * @param string $namingScheme
132
     * @return string
133
     */
134 163
    public function getColumnName($class, $attribute, $prefix = null, $namingScheme = null)
135
    {
136 163
        if (!isset($this->columnNames[$class][$attribute])) {
137 163
            if ($namingScheme === null) {
138 2
                $namingScheme = $this->columnNameScheme;
139
            }
140
141 163
            $name = $this->forceNamingScheme($attribute, $namingScheme);
142
143 163
            if ($prefix !== null && strpos($name, $prefix) !== 0) {
144 22
                $name = $prefix . $name;
145
            }
146
147 163
            $this->columnNames[$class][$attribute] = $name;
148
        }
149
150 163
        return $this->columnNames[$class][$attribute];
151
    }
152
153
    /**
154
     * Get the column name with $namingScheme or default naming scheme
155
     *
156
     * @param string $name
157
     * @param string $namingScheme
158
     * @return string
159
     */
160 117
    public function getMethodName($name, $namingScheme = null)
161
    {
162 117
        if ($namingScheme === null) {
163 2
            $namingScheme = $this->methodNameScheme;
164
        }
165
166 117
        return $this->forceNamingScheme($name, $namingScheme);
167
    }
168
169
    /**
170
     * Substitute a $template with $values
171
     *
172
     * $values is a key value pair array. The value should be a string or an array o
173
     *
174
     * @param string $template
175
     * @param array  $values
176
     * @param string $arrayGlue
177
     * @return string
178
     */
179 186
    public function substitute($template, $values = [], $arrayGlue = ', ')
180
    {
181 186
        return preg_replace_callback(
182 186
            '/%(.*?)%/',
183
            function ($match) use ($values, $arrayGlue) {
184
                // escape % with another % ( %% => % )
185 185
                if ($match[0] === '%%') {
186 1
                    return '%';
187
                }
188
189 185
                return $this->getValue(trim($match[1]), $values, $arrayGlue);
190 186
            },
191
            $template
192
        );
193
    }
194
195
    /**
196
     * Enforce $namingScheme to $name
197
     *
198
     * Supported naming schemes: snake_case, snake_lower, SNAKE_UPPER, Snake_Ucfirst, camelCase, StudlyCaps, lower
199
     * and UPPER.
200
     *
201
     * @param string $name         The name of the var / column
202
     * @param string $namingScheme The naming scheme to use
203
     * @return string
204
     * @throws InvalidConfiguration
205
     */
206 251
    public function forceNamingScheme($name, $namingScheme)
207
    {
208 251
        $words = explode('_', preg_replace(
209 251
            '/([a-z0-9])([A-Z])/',
210 251
            '$1_$2',
211 251
            preg_replace_callback('/([a-z0-9])?([A-Z]+)([A-Z][a-z])/', function ($d) {
212 24
                return ($d[1] ? $d[1] . '_' : '') . $d[2] . '_' . $d[3];
213 251
            }, $name)
214
        ));
215
216
        switch ($namingScheme) {
217 251
            case 'snake_case':
218 23
                $newName = implode('_', $words);
219 23
                break;
220
221 228
            case 'snake_lower':
222 195
                $newName = implode('_', array_map('strtolower', $words));
223 195
                break;
224
225 145
            case 'SNAKE_UPPER':
226 4
                $newName = implode('_', array_map('strtoupper', $words));
227 4
                break;
228
229 141
            case 'Snake_Ucfirst':
230 4
                $newName = implode('_', array_map('ucfirst', $words));
231 4
                break;
232
233 137
            case 'camelCase':
234 119
                $newName = lcfirst(implode('', array_map('ucfirst', array_map('strtolower', $words))));
235 119
                break;
236
237 18
            case 'StudlyCaps':
238 9
                $newName = implode('', array_map('ucfirst', array_map('strtolower', $words)));
239 9
                break;
240
241 9
            case 'lower':
242 4
                $newName = implode('', array_map('strtolower', $words));
243 4
                break;
244
245 5
            case 'UPPER':
246 4
                $newName = implode('', array_map('strtoupper', $words));
247 4
                break;
248
249
            default:
250 1
                throw new InvalidConfiguration('Naming scheme ' . $namingScheme . ' unknown');
251
        }
252
253 250
        return $newName;
254
    }
255
256
    /**
257
     * Get the value for $attribute from $values using $arrayGlue
258
     *
259
     * @param string $attribute The key for $values
260
     * @param array  $values
261
     * @param string $arrayGlue
262
     * @return string
263
     * @throws InvalidConfiguration
264
     */
265 185
    protected function getValue($attribute, $values, $arrayGlue)
266
    {
267 185
        $placeholder = '%' . $attribute . '%';
268 185
        if (preg_match('/\[(-?\d+\*?)\]$/', $attribute, $arrayAccessor)) {
269 11
            $attribute     = substr($attribute, 0, strpos($attribute, '['));
270 11
            $arrayAccessor = $arrayAccessor[1];
271
        } else {
272 174
            $arrayAccessor = '';
273
        }
274
275
        // throw when the variable is unknown
276 185
        if (!array_key_exists($attribute, $values)) {
277 1
            throw new InvalidConfiguration(
278 1
                'Template invalid: Placeholder ' . $placeholder . ' is not allowed'
279
            );
280
        }
281
282 184
        if (is_scalar($values[$attribute]) || is_null($values[$attribute])) {
283 168
            return (string) $values[$attribute];
284
        }
285
286 16
        return $this->arrayToString($values[$attribute], $arrayAccessor, $arrayGlue);
287
    }
288
289
    /**
290
     * Convert array to string using indexes defined by $accessor
291
     *
292
     * @param array  $array
293
     * @param string $accessor
294
     * @param string $glue
295
     * @return string
296
     */
297 16
    protected function arrayToString(array $array, $accessor, $glue)
298
    {
299 16
        if (isset($accessor[0])) {
300 11
            $from = $accessor[0] === '-' ?
301 11
                count($array) - abs($accessor) : (int) $accessor;
302
303 11
            if ($from >= count($array)) {
304 2
                return '';
305
            }
306
307 9
            $array = substr($accessor, -1) === '*' ?
308 9
                array_slice($array, $from) : [ $array[$from] ];
309
        }
310
311 14
        return implode($glue, $array);
312
    }
313
}
314