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 DoctrineFieldGuesser 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 DoctrineFieldGuesser, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 10 | abstract class DoctrineFieldGuesser |
||
| 11 | { |
||
| 12 | /** |
||
| 13 | * @var ManagerRegistry |
||
| 14 | */ |
||
| 15 | private $registry; |
||
| 16 | |||
| 17 | /** |
||
| 18 | * @var boolean |
||
| 19 | */ |
||
| 20 | private $guessRequired; |
||
| 21 | |||
| 22 | /** |
||
| 23 | * @var boolean |
||
| 24 | */ |
||
| 25 | private $defaultRequired; |
||
| 26 | |||
| 27 | /** |
||
| 28 | * @var array |
||
| 29 | */ |
||
| 30 | private $formTypes; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * @var array |
||
| 34 | */ |
||
| 35 | private $filterTypes; |
||
| 36 | |||
| 37 | public function __construct(ManagerRegistry $registry, $objectModel, array $formTypes, array $filterTypes, $guessRequired, $defaultRequired) |
||
| 50 | |||
| 51 | protected function getMetadatas($class) |
||
| 56 | |||
| 57 | public function getAllFields($class) |
||
| 61 | |||
| 62 | public function getManyToMany($model, $fieldPath) |
||
| 68 | |||
| 69 | /** |
||
| 70 | * Find out the database type for given model field path. |
||
| 71 | * |
||
| 72 | * @param string $model The starting model. |
||
| 73 | * @param string $fieldPath The field path. |
||
| 74 | * @return string The DB type for given model field path. |
||
| 75 | */ |
||
| 76 | View Code Duplication | public function getDbType($model, $fieldPath) |
|
| 98 | |||
| 99 | View Code Duplication | public function getModelType($model, $fieldPath) |
|
| 118 | |||
| 119 | public function getSortType($dbType) |
||
| 148 | |||
| 149 | /** |
||
| 150 | * @param $dbType |
||
| 151 | * @param $class: for debug only |
||
| 152 | * @param $columnName: for debug only |
||
| 153 | * @return string |
||
| 154 | */ |
||
| 155 | View Code Duplication | public function getFormType($dbType, $class, $columnName) |
|
| 170 | |||
| 171 | /** |
||
| 172 | * @param $dbType |
||
| 173 | * @param $class: for debug only |
||
| 174 | * @param $columnName: for debug only |
||
| 175 | * @return string |
||
| 176 | */ |
||
| 177 | View Code Duplication | public function getFilterType($dbType, $class, $columnName) |
|
| 192 | |||
| 193 | /** |
||
| 194 | * @param $formType |
||
| 195 | * @param $dbType |
||
| 196 | * @param $model |
||
| 197 | * @param $fieldPath |
||
| 198 | * @return array |
||
| 199 | * @throws \Exception |
||
| 200 | */ |
||
| 201 | public function getFormOptions($formType, $dbType, $model, $fieldPath) |
||
| 205 | |||
| 206 | /** |
||
| 207 | * @param $filterType |
||
| 208 | * @param $dbType |
||
| 209 | * @param $model |
||
| 210 | * @param $fieldPath |
||
| 211 | * @return array |
||
| 212 | * @throws \Exception |
||
| 213 | */ |
||
| 214 | public function getFilterOptions($filterType, $dbType, $model, $fieldPath) |
||
| 218 | |||
| 219 | /** |
||
| 220 | * @param $type |
||
| 221 | * @param $dbType |
||
| 222 | * @param $model |
||
| 223 | * @param $fieldPath |
||
| 224 | * @param bool $filter |
||
| 225 | * @return array |
||
| 226 | * @throws \Exception |
||
| 227 | */ |
||
| 228 | protected function getOptions($type, $dbType, $model, $fieldPath, $filter = false) |
||
| 312 | |||
| 313 | protected function isRequired($class, $fieldName) |
||
| 331 | |||
| 332 | /** |
||
| 333 | * Find the pk name for given class |
||
| 334 | * |
||
| 335 | * @param string $class The class name. |
||
| 336 | * @return string Primary key field name. |
||
| 337 | */ |
||
| 338 | public function getModelPrimaryKeyName($class) |
||
| 344 | |||
| 345 | /** |
||
| 346 | * Find out the primary key for given model field path. |
||
| 347 | * |
||
| 348 | * @param string $model The starting model. |
||
| 349 | * @param string $fieldPath The field path. |
||
| 350 | * @return string The leaf field's primary key. |
||
| 351 | */ |
||
| 352 | public function getPrimaryKeyFor($model, $fieldPath) |
||
| 372 | |||
| 373 | /** |
||
| 374 | * Resolve field path for given model to class and field name. |
||
| 375 | * |
||
| 376 | * @param string $model The starting model. |
||
| 377 | * @param string $fieldPath The field path. |
||
| 378 | * @return array An array containing field and class information. |
||
| 379 | */ |
||
| 380 | protected function resolveRelatedField($model, $fieldPath) |
||
| 401 | |||
| 402 | /** |
||
| 403 | * Retrieve Doctrine EntityManager name for class $className |
||
| 404 | * |
||
| 405 | * @param $className |
||
| 406 | * @return int|string |
||
| 407 | * @throws \Exception |
||
| 408 | */ |
||
| 409 | protected function getObjectManagerName($className) |
||
| 423 | } |
||
| 424 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: