| Total Complexity | 56 |
| Total Lines | 382 |
| Duplicated Lines | 0 % |
| Changes | 2 | ||
| Bugs | 0 | Features | 0 |
Complex classes like SeederController 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.
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 SeederController, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 23 | class SeederController extends Controller |
||
| 24 | { |
||
| 25 | /** @var string the default command action. */ |
||
| 26 | public $defaultAction = 'seed'; |
||
| 27 | |||
| 28 | /** @var string seeder path, support path alias */ |
||
| 29 | public $seederPath = '@console/seeder'; |
||
| 30 | |||
| 31 | /** @var string seeder namespace */ |
||
| 32 | public $seederNamespace = 'console\seeder'; |
||
| 33 | |||
| 34 | /** |
||
| 35 | * @var string this class look like `$this->seederNamespace\Seeder` |
||
| 36 | * default seeder class run if no class selected, |
||
| 37 | * must instance of `\diecoding\seeder\TableSeeder` |
||
| 38 | */ |
||
| 39 | public $defaultSeederClass = 'Seeder'; |
||
| 40 | |||
| 41 | /** @var string tables path, support path alias */ |
||
| 42 | public $tablesPath = '@console/seeder/tables'; |
||
| 43 | |||
| 44 | /** @var string seeder table namespace */ |
||
| 45 | public $tableSeederNamespace = 'console\seeder\tables'; |
||
| 46 | |||
| 47 | /** @var string model namespace */ |
||
| 48 | public $modelNamespace = 'common\models'; |
||
| 49 | |||
| 50 | /** @var string path view template table seeder, support path alias */ |
||
| 51 | public $templateSeederFile = '@diecoding/seeder/views/Seeder.php'; |
||
| 52 | |||
| 53 | /** @var string path view template seeder, support path alias */ |
||
| 54 | public $templateTableFile = '@diecoding/seeder/views/TableSeeder.php'; |
||
| 55 | |||
| 56 | /** @var bool run on production or Seeder on YII_ENV === 'prod' */ |
||
| 57 | public $runOnProd; |
||
| 58 | |||
| 59 | /** @var \yii\db\ActiveRecord */ |
||
| 60 | protected $model = null; |
||
| 61 | |||
| 62 | /** |
||
| 63 | * {@inheritdoc} |
||
| 64 | */ |
||
| 65 | public function options($actionID) |
||
| 66 | { |
||
| 67 | return ['runOnProd']; |
||
| 68 | } |
||
| 69 | |||
| 70 | /** |
||
| 71 | * @inheritdoc |
||
| 72 | */ |
||
| 73 | public function init() |
||
| 74 | { |
||
| 75 | parent::init(); |
||
| 76 | |||
| 77 | $this->seederPath = (string) Yii::getAlias($this->seederPath); |
||
| 78 | $this->tablesPath = (string) Yii::getAlias($this->tablesPath); |
||
| 79 | $this->templateSeederFile = (string) Yii::getAlias($this->templateSeederFile); |
||
| 80 | $this->templateTableFile = (string) Yii::getAlias($this->templateTableFile); |
||
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Seed action |
||
| 85 | * |
||
| 86 | * @param string $name |
||
| 87 | * @return int ExitCode::OK |
||
| 88 | */ |
||
| 89 | public function actionSeed($name = "") |
||
| 90 | { |
||
| 91 | if (YII_ENV_PROD && !$this->runOnProd) { |
||
| 92 | $this->stdout("YII_ENV is set to 'prod'.\nUse seeder is not possible on production systems. use '--runOnProd' to ignore it.\n"); |
||
| 93 | return ExitCode::OK; |
||
| 94 | } |
||
| 95 | |||
| 96 | $explode = explode(':', $name); |
||
| 97 | $name = $explode[0]; |
||
| 98 | $function = $explode[1] ?? null; |
||
| 99 | |||
| 100 | if ($name) { |
||
| 101 | $func = $function ?? 'run'; |
||
| 102 | |||
| 103 | $seederClasses = [ |
||
| 104 | $name, |
||
| 105 | "{$name}TableSeeder", |
||
| 106 | "{$this->seederNamespace}\\{$name}", |
||
| 107 | "{$this->seederNamespace}\\{$name}TableSeeder", |
||
| 108 | "{$this->tableSeederNamespace}\\{$name}", |
||
| 109 | "{$this->tableSeederNamespace}\\{$name}TableSeeder", |
||
| 110 | ]; |
||
| 111 | |||
| 112 | foreach ($seederClasses as $seederClass) { |
||
| 113 | if ($seeder = $this->getClass($seederClass)) { |
||
| 114 | $seeder->{$func}(); |
||
| 115 | break; |
||
| 116 | } |
||
| 117 | } |
||
| 118 | } else if (($defaultSeeder = $this->getDefaultSeeder()) !== null) { |
||
| 119 | $defaultSeeder->run(); |
||
| 120 | } |
||
| 121 | |||
| 122 | return ExitCode::OK; |
||
| 123 | } |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Create a new seeder. |
||
| 127 | * |
||
| 128 | * This command create a new seeder using the available seeder template. |
||
| 129 | * After using this command, developers should modify the created seeder |
||
| 130 | * skeleton by filling up the actual seeder logic. |
||
| 131 | * |
||
| 132 | * ```shell |
||
| 133 | * yii seeder/create model_name |
||
| 134 | * ``` |
||
| 135 | * or |
||
| 136 | * ```shell |
||
| 137 | * yii seeder/create modelName |
||
| 138 | * ``` |
||
| 139 | * or |
||
| 140 | * ```shell |
||
| 141 | * yii seeder/create model-name |
||
| 142 | * ``` |
||
| 143 | * |
||
| 144 | * @see https://www.yiiframework.com/doc/api/2.0/yii-helpers-inflector#camelize()-detail |
||
| 145 | * |
||
| 146 | * For example: |
||
| 147 | * |
||
| 148 | * ```shell |
||
| 149 | * yii seeder/create user |
||
| 150 | * ``` |
||
| 151 | * or |
||
| 152 | * ```shell |
||
| 153 | * yii seeder/create example/user |
||
| 154 | * ``` |
||
| 155 | * if User's Model directory is "common\models\example\User", this default use `$modelNamespace` configuration |
||
| 156 | * |
||
| 157 | * or you can use full path of your class name |
||
| 158 | * |
||
| 159 | * ```shell |
||
| 160 | * yii seeder/create \app\models\User |
||
| 161 | * ``` |
||
| 162 | * or |
||
| 163 | * ```shell |
||
| 164 | * yii seeder/create \backend\modules\example\models\User |
||
| 165 | * ``` |
||
| 166 | * |
||
| 167 | * @param string $modelName the name of the new seeder or class |
||
| 168 | * |
||
| 169 | * @return int ExitCode::OK |
||
| 170 | */ |
||
| 171 | public function actionCreate($modelName) |
||
| 224 | } |
||
| 225 | |||
| 226 | /** |
||
| 227 | * @param string $path |
||
| 228 | * @param string $eol |
||
| 229 | * @return \yii\db\ActiveRecord|null |
||
| 230 | */ |
||
| 231 | protected function getClass($path, $eol = PHP_EOL) |
||
| 232 | { |
||
| 233 | if (class_exists($path)) { |
||
| 234 | return new $path; |
||
| 235 | } |
||
| 236 | |||
| 237 | $this->stdout("Class {$path} not exists. {$eol}"); |
||
| 238 | return null; |
||
| 239 | } |
||
| 240 | |||
| 241 | /** |
||
| 242 | * Generate fields for views template |
||
| 243 | * |
||
| 244 | * @return object |
||
| 245 | */ |
||
| 246 | protected function generateFields() |
||
| 247 | { |
||
| 248 | $modelClass = $this->model::class; |
||
| 249 | $modelNamespace = str_replace('/', '\\', StringHelper::dirname($modelClass)); |
||
| 250 | |||
| 251 | $schema = $this->model->tableSchema; |
||
| 252 | $columns = $schema->columns; |
||
| 253 | $foreignKeys = $schema->foreignKeys; |
||
| 254 | $fields = []; |
||
| 255 | |||
| 256 | foreach ($foreignKeys as $fk_str => $foreignKey) { |
||
| 257 | unset($foreignKeys[$fk_str]); |
||
| 258 | $table = array_shift($foreignKey); |
||
| 259 | $column = array_keys($foreignKey)[0]; |
||
| 260 | |||
| 261 | $errorMsg = "Foreign Key for '$column' column will be ignored and a common column will be generated.\n"; |
||
| 262 | |||
| 263 | $model = $this->getClass($modelNamespace . '\\' . Inflector::camelize($table), $errorMsg); |
||
| 264 | $foreignKeys[$column] = $model; |
||
| 265 | } |
||
| 266 | |||
| 267 | foreach ($columns as $column => $data) { |
||
| 268 | /** @var ColumnSchema $data */ |
||
| 269 | if ($data->autoIncrement) { |
||
| 270 | continue; |
||
| 271 | } |
||
| 272 | |||
| 273 | $foreign = $ref_table_id = $faker = null; |
||
| 274 | |||
| 275 | if (isset($foreignKeys[$column])) { |
||
| 276 | $foreign = $foreignKeys[$column]; |
||
| 277 | $ref_table_id = $foreign->tableSchema->primaryKey[0]; |
||
| 278 | } |
||
| 279 | |||
| 280 | $faker = $this->generateFakerName($data); |
||
| 281 | if (empty($faker)) { |
||
| 282 | $faker = $this->generateFakerType($data); |
||
| 283 | } |
||
| 284 | |||
| 285 | $fields[$column] = (object) [ |
||
| 286 | 'faker' => $faker, |
||
| 287 | 'foreign' => $foreign, |
||
| 288 | 'ref_table_id' => $ref_table_id |
||
| 289 | ]; |
||
| 290 | } |
||
| 291 | |||
| 292 | return (object) $fields; |
||
| 293 | } |
||
| 294 | |||
| 295 | /** |
||
| 296 | * Generate Faker Field Name |
||
| 297 | * |
||
| 298 | * @param ColumnSchema $data |
||
| 299 | * @return string |
||
| 300 | */ |
||
| 301 | protected function generateFakerName(ColumnSchema $data) |
||
| 302 | { |
||
| 303 | switch ($data->name) { |
||
| 304 | case 'full_name': |
||
| 305 | case 'name': |
||
| 306 | $faker = 'name'; |
||
| 307 | break; |
||
| 308 | case 'short_name': |
||
| 309 | case 'first_name': |
||
| 310 | case 'nickname': |
||
| 311 | $faker = 'firstName'; |
||
| 312 | break; |
||
| 313 | case 'last_name': |
||
| 314 | $faker = 'lastName'; |
||
| 315 | break; |
||
| 316 | case 'description': |
||
| 317 | $faker = 'realText()'; |
||
| 318 | break; |
||
| 319 | case 'company': |
||
| 320 | case 'business_name': |
||
| 321 | $faker = 'company'; |
||
| 322 | break; |
||
| 323 | case 'email': |
||
| 324 | $faker = 'email'; |
||
| 325 | break; |
||
| 326 | case 'phone': |
||
| 327 | case 'hp': |
||
| 328 | $faker = 'phoneNumber'; |
||
| 329 | break; |
||
| 330 | } |
||
| 331 | |||
| 332 | return $faker; |
||
| 333 | } |
||
| 334 | |||
| 335 | /** |
||
| 336 | * Generate Faker Field Type |
||
| 337 | * |
||
| 338 | * @param ColumnSchema $data |
||
| 339 | * @return string |
||
| 340 | */ |
||
| 341 | protected function generateFakerType(ColumnSchema $data) |
||
| 342 | { |
||
| 343 | switch ($data->type) { |
||
| 344 | case 'integer': |
||
| 345 | case 'smallint': |
||
| 346 | case 'tinyint': |
||
| 347 | $faker = 'numberBetween(0, 10)'; |
||
| 348 | if ($data->dbType === 'tinyint(1)') { |
||
| 349 | $faker = 'boolean'; |
||
| 350 | break; |
||
| 351 | } |
||
| 352 | case 'mediumint': |
||
| 353 | case 'int': |
||
| 354 | case 'bigint': |
||
| 355 | $faker = 'numberBetween(0, 10)'; |
||
| 356 | break; |
||
| 357 | case 'date': |
||
| 358 | $faker = 'date()'; |
||
| 359 | break; |
||
| 360 | case 'datetime': |
||
| 361 | case 'timestamp': |
||
| 362 | $faker = 'dateTime()'; |
||
| 363 | break; |
||
| 364 | case 'year': |
||
| 365 | $faker = 'year()'; |
||
| 366 | break; |
||
| 367 | case 'time': |
||
| 368 | $faker = 'time()'; |
||
| 369 | break; |
||
| 370 | default: |
||
| 371 | $faker = 'text'; |
||
| 372 | } |
||
| 373 | |||
| 374 | return $faker; |
||
| 375 | } |
||
| 376 | |||
| 377 | /** |
||
| 378 | * Get Default Seeder Class if no class selected |
||
| 379 | * |
||
| 380 | * @return TableSeeder|null |
||
| 381 | */ |
||
| 382 | protected function getDefaultSeeder() |
||
| 405 | } |
||
| 406 | } |
||
| 407 |
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
The method
getObject()can return nothing but null, so it makes no sense to assign that value to a variable.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.