We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.
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 CrudTrait 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 CrudTrait, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 12 | trait CrudTrait |
||
| 13 | { |
||
| 14 | use HasIdentifiableAttribute; |
||
| 15 | |||
| 16 | public static function hasCrudTrait() |
||
| 20 | |||
| 21 | /* |
||
| 22 | |-------------------------------------------------------------------------- |
||
| 23 | | Methods for ENUM and SELECT crud fields. |
||
| 24 | |-------------------------------------------------------------------------- |
||
| 25 | */ |
||
| 26 | |||
| 27 | public static function getPossibleEnumValues($field_name) |
||
| 43 | |||
| 44 | public static function getEnumValuesAsAssociativeArray($field_name) |
||
| 57 | |||
| 58 | /** |
||
| 59 | * Register aditional types in doctrine schema manager for the current connection. |
||
| 60 | * |
||
| 61 | * @return DB |
||
| 62 | */ |
||
| 63 | public function getConnectionWithExtraTypeMappings() |
||
| 64 | { |
||
| 65 | $instance = new self; |
||
| 66 | |||
| 67 | $conn = DB::connection($instance->getConnectionName()); |
||
| 68 | |||
| 69 | // register the enum, json and jsonb column type, because Doctrine doesn't support it |
||
| 70 | $conn->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string'); |
||
| 71 | $conn->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('json', 'json_array'); |
||
| 72 | $conn->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('jsonb', 'json_array'); |
||
| 73 | |||
| 74 | return $conn; |
||
| 75 | } |
||
| 76 | |||
| 77 | /** |
||
| 78 | * Get the model's table name, with the prefix added from the configuration file. |
||
| 79 | * |
||
| 80 | * @return string Table name with prefix |
||
| 81 | */ |
||
| 82 | public function getTableWithPrefix() |
||
| 83 | { |
||
| 84 | $prefix = Config::get('database.connections.'.$this->getConnectionName().'.prefix'); |
||
| 85 | $tableName = $this->getTable(); |
||
| 86 | |||
| 87 | return $prefix.$tableName; |
||
| 88 | } |
||
| 89 | |||
| 90 | /** |
||
| 91 | * Get the column type for a certain db column. |
||
| 92 | * |
||
| 93 | * @param string $columnName Name of the column in the db table. |
||
| 94 | * @return string Db column type. |
||
| 95 | */ |
||
| 96 | public function getColumnType($columnName) |
||
| 103 | |||
| 104 | /** |
||
| 105 | * Checks if the given column name is nullable. |
||
| 106 | * |
||
| 107 | * @param string $column_name The name of the db column. |
||
| 108 | * @return bool |
||
| 109 | */ |
||
| 110 | public static function isColumnNullable($column_name) |
||
| 134 | |||
| 135 | /* |
||
| 136 | |-------------------------------------------------------------------------- |
||
| 137 | | Methods for Fake Fields functionality (used in PageManager). |
||
| 138 | |-------------------------------------------------------------------------- |
||
| 139 | */ |
||
| 140 | |||
| 141 | /** |
||
| 142 | * Add fake fields as regular attributes, even though they are stored as JSON. |
||
| 143 | * |
||
| 144 | * @param array $columns - the database columns that contain the JSONs |
||
| 145 | */ |
||
| 146 | public function addFakes($columns = ['extras']) |
||
| 166 | |||
| 167 | /** |
||
| 168 | * Return the entity with fake fields as attributes. |
||
| 169 | * |
||
| 170 | * @param array $columns - the database columns that contain the JSONs |
||
| 171 | * |
||
| 172 | * @return Model |
||
| 173 | */ |
||
| 174 | public function withFakes($columns = []) |
||
| 188 | |||
| 189 | /** |
||
| 190 | * Determine if this fake column should be json_decoded. |
||
| 191 | * |
||
| 192 | * @param $column string fake column name |
||
| 193 | * |
||
| 194 | * @return bool |
||
| 195 | */ |
||
| 196 | public function shouldDecodeFake($column) |
||
| 200 | |||
| 201 | /** |
||
| 202 | * Determine if this fake column should get json_encoded or not. |
||
| 203 | * |
||
| 204 | * @param $column string fake column name |
||
| 205 | * |
||
| 206 | * @return bool |
||
| 207 | */ |
||
| 208 | public function shouldEncodeFake($column) |
||
| 212 | |||
| 213 | /* |
||
| 214 | |-------------------------------------------------------------------------- |
||
| 215 | | Methods for storing uploaded files (used in CRUD). |
||
| 216 | |-------------------------------------------------------------------------- |
||
| 217 | */ |
||
| 218 | |||
| 219 | /** |
||
| 220 | * Handle file upload and DB storage for a file: |
||
| 221 | * - on CREATE |
||
| 222 | * - stores the file at the destination path |
||
| 223 | * - generates a name |
||
| 224 | * - stores the full path in the DB; |
||
| 225 | * - on UPDATE |
||
| 226 | * - if the value is null, deletes the file and sets null in the DB |
||
| 227 | * - if the value is different, stores the different file and updates DB value. |
||
| 228 | * |
||
| 229 | * @param string $value Value for that column sent from the input. |
||
| 230 | * @param string $attribute_name Model attribute name (and column in the db). |
||
| 231 | * @param string $disk Filesystem disk used to store files. |
||
| 232 | * @param string $destination_path Path in disk where to store the files. |
||
| 233 | */ |
||
| 234 | public function uploadFileToDisk($value, $attribute_name, $disk, $destination_path) |
||
| 263 | |||
| 264 | /** |
||
| 265 | * Handle multiple file upload and DB storage: |
||
| 266 | * - if files are sent |
||
| 267 | * - stores the files at the destination path |
||
| 268 | * - generates random names |
||
| 269 | * - stores the full path in the DB, as JSON array; |
||
| 270 | * - if a hidden input is sent to clear one or more files |
||
| 271 | * - deletes the file |
||
| 272 | * - removes that file from the DB. |
||
| 273 | * |
||
| 274 | * @param string $value Value for that column sent from the input. |
||
| 275 | * @param string $attribute_name Model attribute name (and column in the db). |
||
| 276 | * @param string $disk Filesystem disk used to store files. |
||
| 277 | * @param string $destination_path Path in disk where to store the files. |
||
| 278 | */ |
||
| 279 | public function uploadMultipleFilesToDisk($value, $attribute_name, $disk, $destination_path) |
||
| 317 | |||
| 318 | /* |
||
| 319 | |-------------------------------------------------------------------------- |
||
| 320 | | Methods for working with translatable models. |
||
| 321 | |-------------------------------------------------------------------------- |
||
| 322 | */ |
||
| 323 | |||
| 324 | /** |
||
| 325 | * Get the attributes that were casted in the model. |
||
| 326 | * Used for translations because Spatie/Laravel-Translatable |
||
| 327 | * overwrites the getCasts() method. |
||
| 328 | * |
||
| 329 | * @return self |
||
| 330 | */ |
||
| 331 | public function getCastedAttributes() |
||
| 335 | |||
| 336 | /** |
||
| 337 | * Check if a model is translatable. |
||
| 338 | * All translation adaptors must have the translationEnabledForModel() method. |
||
| 339 | * |
||
| 340 | * @return bool |
||
| 341 | */ |
||
| 342 | public function translationEnabled() |
||
| 350 | } |
||
| 351 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idableprovides a methodequalsIdthat in turn relies on the methodgetId(). If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()as an abstract method to the trait will make sure it is available.