Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like TDBMDaoGenerator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use TDBMDaoGenerator, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class TDBMDaoGenerator |
||
19 | { |
||
20 | /** |
||
21 | * @var SchemaAnalyzer |
||
22 | */ |
||
23 | private $schemaAnalyzer; |
||
24 | |||
25 | /** |
||
26 | * @var Schema |
||
27 | */ |
||
28 | private $schema; |
||
29 | |||
30 | /** |
||
31 | * The root directory of the project. |
||
32 | * |
||
33 | * @var string |
||
34 | */ |
||
35 | private $rootPath; |
||
36 | |||
37 | /** |
||
38 | * Name of composer file. |
||
39 | * |
||
40 | * @var string |
||
41 | */ |
||
42 | private $composerFile; |
||
43 | |||
44 | /** |
||
45 | * @var TDBMSchemaAnalyzer |
||
46 | */ |
||
47 | private $tdbmSchemaAnalyzer; |
||
48 | |||
49 | /** |
||
50 | * Constructor. |
||
51 | * |
||
52 | * @param SchemaAnalyzer $schemaAnalyzer |
||
53 | * @param Schema $schema |
||
54 | * @param TDBMSchemaAnalyzer $tdbmSchemaAnalyzer |
||
55 | */ |
||
56 | public function __construct(SchemaAnalyzer $schemaAnalyzer, Schema $schema, TDBMSchemaAnalyzer $tdbmSchemaAnalyzer) |
||
64 | |||
65 | /** |
||
66 | * Generates all the daos and beans. |
||
67 | * |
||
68 | * @param string $daoFactoryClassName The classe name of the DAO factory |
||
69 | * @param string $daonamespace The namespace for the DAOs, without trailing \ |
||
70 | * @param string $beannamespace The Namespace for the beans, without trailing \ |
||
71 | * @param bool $storeInUtc If the generated daos should store the date in UTC timezone instead of user's timezone. |
||
72 | * |
||
73 | * @return \string[] the list of tables |
||
74 | * |
||
75 | * @throws TDBMException |
||
76 | */ |
||
77 | public function generateAllDaosAndBeans($daoFactoryClassName, $daonamespace, $beannamespace, $storeInUtc) |
||
106 | |||
107 | /** |
||
108 | * Generates in one method call the daos and the beans for one table. |
||
109 | * |
||
110 | * @param Table $table |
||
111 | * @param string $daonamespace |
||
112 | * @param string $beannamespace |
||
113 | * @param ClassNameMapper $classNameMapper |
||
114 | * @param bool $storeInUtc |
||
115 | * |
||
116 | * @throws TDBMException |
||
117 | */ |
||
118 | public function generateDaoAndBean(Table $table, $daonamespace, $beannamespace, ClassNameMapper $classNameMapper, $storeInUtc) |
||
130 | |||
131 | /** |
||
132 | * Returns the name of the bean class from the table name. |
||
133 | * |
||
134 | * @param $tableName |
||
135 | * |
||
136 | * @return string |
||
137 | */ |
||
138 | public static function getBeanNameFromTableName($tableName) |
||
142 | |||
143 | /** |
||
144 | * Returns the name of the DAO class from the table name. |
||
145 | * |
||
146 | * @param $tableName |
||
147 | * |
||
148 | * @return string |
||
149 | */ |
||
150 | public static function getDaoNameFromTableName($tableName) |
||
154 | |||
155 | /** |
||
156 | * Returns the name of the base bean class from the table name. |
||
157 | * |
||
158 | * @param $tableName |
||
159 | * |
||
160 | * @return string |
||
161 | */ |
||
162 | public static function getBaseBeanNameFromTableName($tableName) |
||
166 | |||
167 | /** |
||
168 | * Returns the name of the base DAO class from the table name. |
||
169 | * |
||
170 | * @param $tableName |
||
171 | * |
||
172 | * @return string |
||
173 | */ |
||
174 | public static function getBaseDaoNameFromTableName($tableName) |
||
178 | |||
179 | /** |
||
180 | * Writes the PHP bean file with all getters and setters from the table passed in parameter. |
||
181 | * |
||
182 | * @param BeanDescriptor $beanDescriptor |
||
183 | * @param string $className The name of the class |
||
184 | * @param string $baseClassName The name of the base class which will be extended (name only, no directory) |
||
185 | * @param Table $table The table |
||
186 | * @param string $beannamespace The namespace of the bean |
||
187 | * @param ClassNameMapper $classNameMapper |
||
188 | * |
||
189 | * @throws TDBMException |
||
190 | */ |
||
191 | public function generateBean(BeanDescriptor $beanDescriptor, $className, $baseClassName, Table $table, $beannamespace, ClassNameMapper $classNameMapper, $storeInUtc) |
||
|
|||
192 | { |
||
193 | $str = $beanDescriptor->generatePhpCode($beannamespace); |
||
194 | |||
195 | $possibleBaseFileNames = $classNameMapper->getPossibleFileNames($beannamespace.'\\'.$baseClassName); |
||
196 | if (empty($possibleBaseFileNames)) { |
||
197 | throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace.'\\'.$baseClassName.'" is not autoloadable.'); |
||
198 | } |
||
199 | $possibleBaseFileName = $this->rootPath.$possibleBaseFileNames[0]; |
||
200 | |||
201 | $this->ensureDirectoryExist($possibleBaseFileName); |
||
202 | file_put_contents($possibleBaseFileName, $str); |
||
203 | @chmod($possibleBaseFileName, 0664); |
||
204 | |||
205 | $possibleFileNames = $classNameMapper->getPossibleFileNames($beannamespace.'\\'.$className); |
||
206 | if (empty($possibleFileNames)) { |
||
207 | // @codeCoverageIgnoreStart |
||
208 | throw new TDBMException('Sorry, autoload namespace issue. The class "'.$beannamespace.'\\'.$className.'" is not autoloadable.'); |
||
209 | // @codeCoverageIgnoreEnd |
||
210 | } |
||
211 | $possibleFileName = $this->rootPath.$possibleFileNames[0]; |
||
212 | View Code Duplication | if (!file_exists($possibleFileName)) { |
|
213 | $tableName = $table->getName(); |
||
214 | $str = "<?php |
||
215 | /* |
||
216 | * This file has been automatically generated by TDBM. |
||
217 | * You can edit this file as it will not be overwritten. |
||
218 | */ |
||
219 | |||
220 | namespace {$beannamespace}; |
||
221 | |||
222 | /** |
||
223 | * The $className class maps the '$tableName' table in database. |
||
224 | */ |
||
225 | class $className extends $baseClassName |
||
226 | { |
||
227 | |||
228 | }"; |
||
229 | $this->ensureDirectoryExist($possibleFileName); |
||
230 | file_put_contents($possibleFileName, $str); |
||
231 | @chmod($possibleFileName, 0664); |
||
232 | } |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Tries to find a @defaultSort annotation in one of the columns. |
||
237 | * |
||
238 | * @param Table $table |
||
239 | * |
||
240 | * @return array First item: column name, Second item: column order (asc/desc) |
||
241 | */ |
||
242 | private function getDefaultSortColumnFromAnnotation(Table $table) |
||
261 | |||
262 | /** |
||
263 | * Writes the PHP bean DAO with simple functions to create/get/save objects. |
||
264 | * |
||
265 | * @param BeanDescriptor $beanDescriptor |
||
266 | * @param string $className The name of the class |
||
267 | * @param string $baseClassName |
||
268 | * @param string $beanClassName |
||
269 | * @param Table $table |
||
270 | * @param string $daonamespace |
||
271 | * @param string $beannamespace |
||
272 | * @param ClassNameMapper $classNameMapper |
||
273 | * |
||
274 | * @throws TDBMException |
||
275 | */ |
||
276 | public function generateDao(BeanDescriptor $beanDescriptor, $className, $baseClassName, $beanClassName, Table $table, $daonamespace, $beannamespace, ClassNameMapper $classNameMapper) |
||
499 | |||
500 | /** |
||
501 | * Generates the factory bean. |
||
502 | * |
||
503 | * @param Table[] $tableList |
||
504 | */ |
||
505 | private function generateFactory(array $tableList, $daoFactoryClassName, $daoNamespace, ClassNameMapper $classNameMapper) |
||
572 | |||
573 | /** |
||
574 | * Transforms a string to camelCase (except the first letter will be uppercase too). |
||
575 | * Underscores and spaces are removed and the first letter after the underscore is uppercased. |
||
576 | * |
||
577 | * @param $str string |
||
578 | * |
||
579 | * @return string |
||
580 | */ |
||
581 | public static function toCamelCase($str) |
||
600 | |||
601 | /** |
||
602 | * Tries to put string to the singular form (if it is plural). |
||
603 | * We assume the table names are in english. |
||
604 | * |
||
605 | * @param $str string |
||
606 | * |
||
607 | * @return string |
||
608 | */ |
||
609 | public static function toSingular($str) |
||
613 | |||
614 | /** |
||
615 | * Put the first letter of the string in lower case. |
||
616 | * Very useful to transform a class name into a variable name. |
||
617 | * |
||
618 | * @param $str string |
||
619 | * |
||
620 | * @return string |
||
621 | */ |
||
622 | public static function toVariableName($str) |
||
626 | |||
627 | /** |
||
628 | * Ensures the file passed in parameter can be written in its directory. |
||
629 | * |
||
630 | * @param string $fileName |
||
631 | * |
||
632 | * @throws TDBMException |
||
633 | */ |
||
634 | private function ensureDirectoryExist($fileName) |
||
646 | |||
647 | /** |
||
648 | * Absolute path to composer json file. |
||
649 | * |
||
650 | * @param string $rootPath |
||
651 | */ |
||
652 | public function setComposerFile($composerFile) |
||
657 | |||
658 | /** |
||
659 | * Transforms a DBAL type into a PHP type (for PHPDoc purpose). |
||
660 | * |
||
661 | * @param Type $type The DBAL type |
||
662 | * |
||
663 | * @return string The PHP type |
||
664 | */ |
||
665 | public static function dbalTypeToPhpType(Type $type) |
||
691 | |||
692 | /** |
||
693 | * @param string $beanNamespace |
||
694 | * |
||
695 | * @return \string[] Returns a map mapping table name to beans name |
||
696 | */ |
||
697 | public function buildTableToBeanMap($beanNamespace) |
||
710 | } |
||
711 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.