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