Passed
Pull Request — master (#176)
by
unknown
04:40
created

getResultIteratorClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
declare(strict_types=1);
3
4
5
namespace TheCodingMachine\TDBM\Utils;
6
7
use Doctrine\Common\Inflector\Inflector;
8
use Doctrine\DBAL\Schema\AbstractSchemaManager;
9
use Doctrine\DBAL\Schema\Column;
10
use Doctrine\DBAL\Schema\ForeignKeyConstraint;
11
use Doctrine\DBAL\Schema\Schema;
12
use TheCodingMachine\TDBM\TDBMException;
13
use TheCodingMachine\TDBM\Utils\Annotation\AnnotationParser;
14
use TheCodingMachine\TDBM\Utils\Annotation\Bean;
15
16
class DefaultNamingStrategy extends AbstractNamingStrategy
17
{
18
    private $beanPrefix = '';
19
    private $beanSuffix = '';
20
    private $baseBeanPrefix = 'Abstract';
21
    private $baseBeanSuffix = '';
22
    private $daoPrefix = '';
23
    private $daoSuffix = 'Dao';
24
    private $baseDaoPrefix = 'Abstract';
25
    private $baseDaoSuffix = 'Dao';
26
    private $resultIteratorPrefix = '';
27
    private $resultIteratorSuffix = 'ResultIterator';
28
    private $baseResultIteratorPrefix = 'Abstract';
29
    private $baseResultIteratorSuffix = 'ResultIterator';
30
    private $exceptions = [];
31
    /**
32
     * @var AnnotationParser
33
     */
34
    private $annotationParser;
35
    /**
36
     * @var AbstractSchemaManager
37
     */
38
    private $schemaManager;
39
    /**
40
     * @var Schema
41
     */
42
    private $schema;
43
44
    public function __construct(AnnotationParser $annotationParser, AbstractSchemaManager $schemaManager)
45
    {
46
        $this->annotationParser = $annotationParser;
47
        $this->schemaManager = $schemaManager;
48
    }
49
50
    /**
51
     * Sets the string prefix to any bean class name.
52
     *
53
     * @param string $beanPrefix
54
     */
55
    public function setBeanPrefix(string $beanPrefix): void
56
    {
57
        $this->beanPrefix = $beanPrefix;
58
    }
59
60
    /**
61
     * Sets the string suffix to any bean class name.
62
     *
63
     * @param string $beanSuffix
64
     */
65
    public function setBeanSuffix(string $beanSuffix): void
66
    {
67
        $this->beanSuffix = $beanSuffix;
68
    }
69
70
    /**
71
     * Sets the string prefix to any base bean class name.
72
     *
73
     * @param string $baseBeanPrefix
74
     */
75
    public function setBaseBeanPrefix(string $baseBeanPrefix): void
76
    {
77
        $this->baseBeanPrefix = $baseBeanPrefix;
78
    }
79
80
    /**
81
     * Sets the string suffix to any base bean class name.
82
     *
83
     * @param string $baseBeanSuffix
84
     */
85
    public function setBaseBeanSuffix(string $baseBeanSuffix): void
86
    {
87
        $this->baseBeanSuffix = $baseBeanSuffix;
88
    }
89
90
    /**
91
     * Sets the string prefix to any DAO class name.
92
     *
93
     * @param string $daoPrefix
94
     */
95
    public function setDaoPrefix(string $daoPrefix): void
96
    {
97
        $this->daoPrefix = $daoPrefix;
98
    }
99
100
    /**
101
     * Sets the string suffix to any DAO class name.
102
     *
103
     * @param string $daoSuffix
104
     */
105
    public function setDaoSuffix(string $daoSuffix): void
106
    {
107
        $this->daoSuffix = $daoSuffix;
108
    }
109
110
    /**
111
     * Sets the string prefix to any base DAO class name.
112
     *
113
     * @param string $baseDaoPrefix
114
     */
115
    public function setBaseDaoPrefix(string $baseDaoPrefix): void
116
    {
117
        $this->baseDaoPrefix = $baseDaoPrefix;
118
    }
119
120
    /**
121
     * Sets the string suffix to any base DAO class name.
122
     *
123
     * @param string $baseDaoSuffix
124
     */
125
    public function setBaseDaoSuffix(string $baseDaoSuffix): void
126
    {
127
        $this->baseDaoSuffix = $baseDaoSuffix;
128
    }
129
130
131
    /**
132
     * Returns the bean class name from the table name (excluding the namespace).
133
     *
134
     * @param string $tableName
135
     * @return string
136
     */
137
    public function getBeanClassName(string $tableName): string
138
    {
139
        return $this->beanPrefix.$this->tableNameToSingularCamelCase($tableName).$this->beanSuffix;
140
    }
141
142
    /**
143
     * Returns the base bean class name from the table name (excluding the namespace).
144
     *
145
     * @param string $tableName
146
     * @return string
147
     */
148
    public function getBaseBeanClassName(string $tableName): string
149
    {
150
        return $this->baseBeanPrefix.$this->tableNameToSingularCamelCase($tableName).$this->baseBeanSuffix;
151
    }
152
153
    /**
154
     * Returns the name of the DAO class from the table name (excluding the namespace).
155
     *
156
     * @param string $tableName
157
     * @return string
158
     */
159
    public function getDaoClassName(string $tableName): string
160
    {
161
        return $this->daoPrefix.$this->tableNameToSingularCamelCase($tableName).$this->daoSuffix;
162
    }
163
164
    /**
165
     * Returns the name of the base DAO class from the table name (excluding the namespace).
166
     *
167
     * @param string $tableName
168
     * @return string
169
     */
170
    public function getBaseDaoClassName(string $tableName): string
171
    {
172
        return $this->baseDaoPrefix.$this->tableNameToSingularCamelCase($tableName).$this->baseDaoSuffix;
173
    }
174
175
    /**
176
     * Returns the name of the ResultIterator class from the table name (excluding the namespace).
177
     *
178
     * @param string $tableName
179
     * @return string
180
     */
181
    public function getResultIteratorClassName(string $tableName): string
182
    {
183
        return $this->resultIteratorPrefix.$this->tableNameToSingularCamelCase($tableName).$this->resultIteratorSuffix;
184
    }
185
186
    /**
187
     * Returns the name of the base ResultIterator class from the table name (excluding the namespace).
188
     *
189
     * @param string $tableName
190
     * @return string
191
     */
192
    public function getBaseResultIteratorClassName(string $tableName): string
193
    {
194
        return $this->baseResultIteratorPrefix.$this->tableNameToSingularCamelCase($tableName).$this->baseResultIteratorSuffix;
195
    }
196
197
    private function tableNameToSingularCamelCase(string $tableName): string
198
    {
199
        // Now, let's check if we have a @Bean annotation on it.
200
        /** @var Bean $beanAnnotation */
201
        $beanAnnotation = $this->annotationParser->getTableAnnotations($this->getSchema()->getTable($tableName))->findAnnotation(Bean::class);
202
        if ($beanAnnotation !== null) {
203
            return $beanAnnotation->name;
204
        }
205
206
        return $this->toSingularCamelCase($tableName);
207
    }
208
209
    /**
210
     * Tries to put string to the singular form (if it is plural) and camel case form.
211
     * We assume the table names are in english.
212
     *
213
     * @param string $str
214
     *
215
     * @return string
216
     */
217
    private function toSingularCamelCase(string $str): string
218
    {
219
        // Let's first check if this is not in the exceptions directory.
220
        if (isset($this->exceptions[$str])) {
221
            return $this->exceptions[$str];
222
        }
223
224
        // If everything is in uppercase (Oracle), let's lowercase everything
225
        if (strtoupper($str) === $str) {
226
            $str = strtolower($str);
227
        }
228
229
        $tokens = preg_split("/[_ ]+/", $str);
230
        if ($tokens === false) {
231
            throw new \RuntimeException('Unexpected preg_split error'); // @codeCoverageIgnore
232
        }
233
234
        $str = '';
235
        foreach ($tokens as $token) {
236
            $str .= ucfirst(Inflector::singularize($token));
237
        }
238
239
        return $str;
240
    }
241
242
    /**
243
     * Put string to camel case form.
244
     *
245
     * @param string $str
246
     *
247
     * @return string
248
     */
249
    private function toCamelCase(string $str): string
250
    {
251
        // Let's first check if this is not in the exceptions directory.
252
        if (isset($this->exceptions[$str])) {
253
            return $this->exceptions[$str];
254
        }
255
256
        // If everything is in uppercase (Oracle), let's lowercase everything
257
        if (strtoupper($str) === $str) {
258
            $str = strtolower($str);
259
        }
260
261
        $tokens = preg_split("/[_ ]+/", $str);
262
        if ($tokens === false) {
263
            throw new \RuntimeException('Unexpected preg_split error'); // @codeCoverageIgnore
264
        }
265
266
        $str = '';
267
        foreach ($tokens as $token) {
268
            $str .= ucfirst($token);
269
        }
270
271
        return $str;
272
    }
273
274
    /**
275
     * Returns the class name for the DAO factory.
276
     *
277
     * @return string
278
     */
279
    public function getDaoFactoryClassName(): string
280
    {
281
        return 'DaoFactory';
282
    }
283
284
    /**
285
     * Sets exceptions in the naming of classes.
286
     * The key is the name of the table, the value the "base" name of beans and DAOs.
287
     *
288
     * This is very useful for dealing with plural to singular translations in non english table names.
289
     *
290
     * For instance if you are dealing with a table containing horses in French ("chevaux" that has a singular "cheval"):
291
     *
292
     * [
293
     *     "chevaux" => "Cheval"
294
     * ]
295
     *
296
     * @param array<string,string> $exceptions
297
     */
298
    public function setExceptions(array $exceptions): void
299
    {
300
        $this->exceptions = $exceptions;
301
    }
302
303
    protected function getForeignKeyUpperCamelCaseName(ForeignKeyConstraint $foreignKey, bool $alternativeName): string
304
    {
305
        // First, are there many column or only one?
306
        // If one column, we name the setter after it. Otherwise, we name the setter after the table name
307
        if (count($foreignKey->getUnquotedLocalColumns()) > 1) {
308
            $name = $this->tableNameToSingularCamelCase($foreignKey->getForeignTableName());
309
            if ($alternativeName) {
310
                $camelizedColumns = array_map(['TheCodingMachine\\TDBM\\Utils\\TDBMDaoGenerator', 'toCamelCase'], $foreignKey->getUnquotedLocalColumns());
311
312
                $name .= 'By'.implode('And', $camelizedColumns);
313
            }
314
        } else {
315
            $column = $foreignKey->getUnquotedLocalColumns()[0];
316
            // Let's remove any _id or id_.
317
            if (strpos(strtolower($column), 'id_') === 0) {
318
                $column = substr($column, 3);
319
            }
320
            if (strrpos(strtolower($column), '_id') === strlen($column) - 3) {
321
                $column = substr($column, 0, strlen($column) - 3);
322
            }
323
            $name = $this->toCamelCase($column);
324
            if ($alternativeName) {
325
                $name .= 'Object';
326
            }
327
        }
328
329
        return $name;
330
    }
331
332
    protected function getScalarColumnUpperCamelCaseName(string $columnName, bool $alternativeName): string
0 ignored issues
show
Unused Code introduced by
The parameter $alternativeName is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

332
    protected function getScalarColumnUpperCamelCaseName(string $columnName, /** @scrutinizer ignore-unused */ bool $alternativeName): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
333
    {
334
        return $this->toCamelCase($columnName);
335
    }
336
337
    protected function getUpperCamelCaseName(AbstractBeanPropertyDescriptor $property): string
338
    {
339
        if ($property instanceof ObjectBeanPropertyDescriptor) {
340
            return $this->getForeignKeyUpperCamelCaseName($property->getForeignKey(), $property->isAlternativeName());
341
        } elseif ($property instanceof ScalarBeanPropertyDescriptor) {
342
            return $this->getScalarColumnUpperCamelCaseName($property->getColumnName(), $property->isAlternativeName());
343
        } else {
344
            throw new TDBMException('Unexpected property type. Should be either ObjectBeanPropertyDescriptor or ScalarBeanPropertyDescriptor'); // @codeCoverageIgnore
345
        }
346
    }
347
348
    private function getSchema(): Schema
349
    {
350
        if ($this->schema === null) {
351
            $this->schema = $this->schemaManager->createSchema();
352
        }
353
        return $this->schema;
354
    }
355
356
    public function getAutoPivotEntityName(ForeignKeyConstraint $constraint, bool $useAlternativeName): string
357
    {
358
        return $this->getForeignKeyUpperCamelCaseName($constraint, $useAlternativeName);
359
    }
360
}
361