Passed
Branch feature-validator (55f4e3)
by Thomas
03:27
created

Namer::setOption()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 14
cts 14
cp 1
rs 8.6737
c 0
b 0
f 0
cc 5
eloc 15
nc 5
nop 2
crap 5
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 56
    public function __construct($options = [])
39
    {
40 56
        foreach ($options as $option => $value) {
41 4
            $this->setOption($option, $value);
42
        }
43 56
    }
44
45
    /**
46
     * Set $option to $value
47
     *
48
     * @param string $option
49
     * @param mixed $value
50
     * @return self
51
     */
52 4
    public function setOption($option, $value)
53
    {
54
        switch ($option) {
55 4
            case EntityManager::OPT_TABLE_NAME_TEMPLATE:
56 1
                $this->tableNameTemplate = $value;
57 1
                break;
58
59 3
            case EntityManager::OPT_NAMING_SCHEME_TABLE:
60 1
                $this->tableNameScheme = $value;
61 1
                break;
62
63 2
            case EntityManager::OPT_NAMING_SCHEME_COLUMN:
64 1
                $this->columnNameScheme = $value;
65 1
                break;
66
67 1
            case EntityManager::OPT_NAMING_SCHEME_METHODS:
68 1
                $this->methodNameScheme = $value;
69 1
                break;
70
        }
71
72 4
        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->name),
97 129
        ], '_');
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 138
    public function getColumnName($field, $namingScheme = null)
110
    {
111 138
        if (!$namingScheme) {
112 2
            $namingScheme = $this->columnNameScheme;
113
        }
114
115 138
        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 88
    public function getMethodName($name, $namingScheme = null)
126
    {
127 88
        if (!$namingScheme) {
128 2
            $namingScheme = $this->methodNameScheme;
129
        }
130
131 88
        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 148
    public function substitute($template, $values = [], $arrayGlue = ', ')
145
    {
146 148
        return preg_replace_callback(
147 148
            '/%(.*?)%/',
148
            function ($match) use ($values, $arrayGlue) {
149
                // escape % with another % ( %% => % )
150 148
                if ($match[0] === '%%') {
151 1
                    return '%';
152
                }
153
154 148
                return $this->getValue(trim($match[1]), $values, $arrayGlue);
155 148
            },
156
            $template
157
        );
158
    }
159
160
    /**
161
     * Enforce $namingScheme to $name
162
     *
163
     * Supported naming schemes: snake_case, snake_lower, SNAKE_UPPER, Snake_Ucfirst, camelCase, StudlyCaps, lower
164
     * and UPPER.
165
     *
166
     * @param string $name         The name of the var / column
167
     * @param string $namingScheme The naming scheme to use
168
     * @return string
169
     * @throws InvalidConfiguration
170
     */
171 225
    public function forceNamingScheme($name, $namingScheme)
172
    {
173 225
        $words = explode('_', preg_replace(
174 225
            '/([a-z0-9])([A-Z])/',
175 225
            '$1_$2',
176 225
            preg_replace_callback('/([a-z0-9])?([A-Z]+)([A-Z][a-z])/', function ($d) {
177 24
                return ($d[1] ? $d[1] . '_' : '') . $d[2] . '_' . $d[3];
178 225
            }, $name)
179
        ));
180
181
        switch ($namingScheme) {
182 225
            case 'snake_case':
183 25
                $newName = implode('_', $words);
184 25
                break;
185
186 200
            case 'snake_lower':
187 167
                $newName = implode('_', array_map('strtolower', $words));
188 167
                break;
189
190 116
            case 'SNAKE_UPPER':
191 4
                $newName = implode('_', array_map('strtoupper', $words));
192 4
                break;
193
194 112
            case 'Snake_Ucfirst':
195 4
                $newName = implode('_', array_map('ucfirst', $words));
196 4
                break;
197
198 108
            case 'camelCase':
199 90
                $newName = lcfirst(implode('', array_map('ucfirst', array_map('strtolower', $words))));
200 90
                break;
201
202 18
            case 'StudlyCaps':
203 9
                $newName = implode('', array_map('ucfirst', array_map('strtolower', $words)));
204 9
                break;
205
206 9
            case 'lower':
207 4
                $newName = implode('', array_map('strtolower', $words));
208 4
                break;
209
210 5
            case 'UPPER':
211 4
                $newName = implode('', array_map('strtoupper', $words));
212 4
                break;
213
214
            default:
215 1
                throw new InvalidConfiguration('Naming scheme ' . $namingScheme . ' unknown');
216
        }
217
218 224
        return $newName;
219
    }
220
221 148
    protected function getValue($var, $values, $arrayGlue)
222
    {
223 148
        $placeholder = '%' . $var . '%';
224 148
        if (preg_match('/\[(-?\d+\*?)\]$/', $var, $arrayAccessor)) {
225 11
            $var = substr($var, 0, strpos($var, '['));
226 11
            $arrayAccessor = $arrayAccessor[1];
227
        }
228
229
        // throw when the variable is unknown
230 148
        if (!array_key_exists($var, $values)) {
231 1
            throw new InvalidConfiguration(
232 1
                'Template invalid: Placeholder ' . $placeholder . ' is not allowed'
233
            );
234
        }
235
236 147
        if (is_scalar($values[$var]) || is_null($values[$var])) {
237 131
            return (string)$values[$var];
238
        }
239
240
        // otherwise we assume it is an array
241 16
        $array = $values[$var];
242
243 16
        if (isset($arrayAccessor[0])) {
244 11
            $from = $arrayAccessor[0] === '-' ?
245 11
                count($array) - abs($arrayAccessor) : (int)$arrayAccessor;
246
247 11
            if ($from >= count($array)) {
248 2
                return '';
249
            }
250
251 9
            $array = substr($arrayAccessor, -1) === '*' ?
252 9
                array_slice($array, $from) : [$array[$from]];
253
        }
254
255 14
        return implode($arrayGlue, $array);
256
    }
257
}
258