| Total Complexity | 42 |
| Total Lines | 300 |
| Duplicated Lines | 0 % |
| Changes | 27 | ||
| Bugs | 1 | Features | 2 |
Complex classes like StubParser 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 StubParser, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 12 | class StubParser |
||
| 13 | { |
||
| 14 | use Translatable; |
||
| 15 | |||
| 16 | private $inputName; |
||
| 17 | private $parsedModel; |
||
| 18 | |||
| 19 | private $fields; |
||
| 20 | private $inputs; |
||
| 21 | private $validationRules; |
||
| 22 | private $hasAuth; |
||
| 23 | private $store; |
||
| 24 | |||
| 25 | public function __construct($inputName, $parsedModel) |
||
| 26 | { |
||
| 27 | $this->inputName = $inputName; |
||
| 28 | $this->parsedModel = $parsedModel; |
||
| 29 | } |
||
| 30 | |||
| 31 | public function setValidationRules($rules) |
||
| 32 | { |
||
| 33 | $this->validationRules = $rules; |
||
| 34 | } |
||
| 35 | |||
| 36 | public function setStore($store) |
||
| 37 | { |
||
| 38 | $this->store = $store; |
||
| 39 | } |
||
| 40 | |||
| 41 | public function setAuthType(bool $hasAuth){ |
||
| 42 | $this->hasAuth = $hasAuth; |
||
| 43 | } |
||
| 44 | |||
| 45 | public function setFields(array $fields){ |
||
| 46 | $this->fields = $fields; |
||
| 47 | } |
||
| 48 | |||
| 49 | public function setInputs(array $inputs){ |
||
| 50 | $this->inputs = $inputs; |
||
| 51 | } |
||
| 52 | |||
| 53 | public function replaceModel($stub) |
||
| 54 | { |
||
| 55 | $modelNamespace = $this->parsedModel; |
||
| 56 | $modelName = $this->getModelName($modelNamespace); |
||
| 57 | |||
| 58 | $array = [ |
||
| 59 | '{{ modelName }}' => ucfirst($modelName), |
||
| 60 | '{{ modelNamespace }}' => $modelNamespace, |
||
| 61 | '{{ uploadFile }}' => $this->uploadCodeParser(), |
||
| 62 | '{{ model }}' => strtolower($modelName), |
||
| 63 | '{{ properties }}' => $this->parseProperties(), |
||
| 64 | '{{ rules }}' => $this->parseValidationRules(), |
||
| 65 | '{{ fields }}' => $this->parseActionInComponent(), |
||
| 66 | '{{ setProperties }}' => $this->parseSetPropertiesValue(), |
||
| 67 | ]; |
||
| 68 | |||
| 69 | return str_replace(array_keys($array), array_values($array), $stub); |
||
| 70 | } |
||
| 71 | |||
| 72 | /** |
||
| 73 | * Make Locale files |
||
| 74 | */ |
||
| 75 | public function setLocaleTexts() |
||
| 76 | { |
||
| 77 | $this->addText(ucfirst($this->inputName)); |
||
| 78 | $this->addText(ucfirst(Str::plural($this->inputName))); |
||
| 79 | |||
| 80 | $this->translate(); |
||
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Get model name from namespace |
||
| 85 | */ |
||
| 86 | public function getModelName($modelNamespace) |
||
| 91 | } |
||
| 92 | |||
| 93 | /** |
||
| 94 | * Parse properties in Livewire component |
||
| 95 | */ |
||
| 96 | public function parseProperties() |
||
| 111 | } |
||
| 112 | |||
| 113 | /** |
||
| 114 | * Parse Uploading Code |
||
| 115 | */ |
||
| 116 | public function uploadCodeParser() |
||
| 117 | { |
||
| 118 | $str = ''; |
||
| 119 | foreach ($this->inputs as $key => $input) { |
||
| 120 | $inputObject = $this->normalizeInput($key, $input); |
||
| 121 | if (! $inputObject instanceof File){ |
||
| 122 | continue; |
||
| 123 | } |
||
| 124 | // We get store path which has been defined in crud's config file |
||
| 125 | $storePath = $this->store[$key] ?? "{$key}"; |
||
| 126 | |||
| 127 | // We get property value then store file in $storePath |
||
| 128 | // A PHP Code for upload as a string will be created here |
||
| 129 | $str .= $this->makeTab(2).'if($this->getPropertyValue(\''.$key.'\') and is_object($this->'.$key.')) {'.$this->makeTab(3); |
||
| 130 | $str .= '$this->'.$key.' = $this->getPropertyValue(\''.$key.'\')->store(\''.$storePath.'\');'.$this->makeTab(2); |
||
| 131 | $str .= '}'.PHP_EOL; |
||
| 132 | } |
||
| 133 | |||
| 134 | return $str; |
||
| 135 | } |
||
| 136 | |||
| 137 | /** |
||
| 138 | * parse values for mount method in Livewire |
||
| 139 | */ |
||
| 140 | public function parseSetPropertiesValue() |
||
| 151 | } |
||
| 152 | |||
| 153 | /** |
||
| 154 | * Parse Validation rules |
||
| 155 | */ |
||
| 156 | public function parseValidationRules() |
||
| 157 | { |
||
| 158 | $str = ''; |
||
| 159 | |||
| 160 | foreach ($this->validationRules as $key => $rule) { |
||
| 161 | $str .= "'$key' => '$rule',"; |
||
| 162 | $str .= $this->makeTab(2, $key != array_key_last($this->validationRules)); |
||
| 163 | } |
||
| 164 | |||
| 165 | return $str; |
||
| 166 | } |
||
| 167 | |||
| 168 | /** |
||
| 169 | * Create an array of properties in Livewire component for actions |
||
| 170 | */ |
||
| 171 | public function parseActionInComponent() |
||
| 172 | { |
||
| 173 | $str = ''; |
||
| 174 | |||
| 175 | foreach ($this->inputs as $key => $field) { |
||
| 176 | $newLine = ($field != end($this->inputs) or $this->hasAuth); |
||
| 177 | $str .= "'$key' => " . '$this' . "->$key,".$this->makeTab(3, $newLine); |
||
| 178 | } |
||
| 179 | |||
| 180 | if($this->hasAuth){ |
||
| 181 | $str .= "'user_id' => auth()->id(),"; |
||
| 182 | } |
||
| 183 | |||
| 184 | return $str; |
||
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * Create Blade from stub |
||
| 189 | */ |
||
| 190 | public function parseBlade($stub){ |
||
| 191 | $modelName = $this->getModelName($this->parsedModel); |
||
| 192 | |||
| 193 | $crud = crud(strtolower($modelName)); |
||
| 194 | |||
| 195 | $array = [ |
||
| 196 | '{{ model }}' => strtolower($modelName), |
||
| 197 | '{{ modelName }}' => ucfirst($modelName), |
||
| 198 | '{{ data }}' => $this->parseDataInBlade(), |
||
| 199 | '{{ titles }}' => $this->parseTitlesInBlade(), |
||
| 200 | '{{ inputs }}' => $this->parseInputsInBlade(), |
||
| 201 | '{{ routeName }}' => $crud->route, |
||
| 202 | '{{ with_acl }}' => $crud->with_acl, |
||
| 203 | '{{ with_policy }}' => $crud->with_policy, |
||
| 204 | ]; |
||
| 205 | |||
| 206 | $this->setLocaleTexts(); |
||
| 207 | |||
| 208 | return str_replace(array_keys($array), array_values($array), $stub); |
||
| 209 | } |
||
| 210 | |||
| 211 | /** |
||
| 212 | * Parse <td> tags for data |
||
| 213 | */ |
||
| 214 | public function parseDataInBlade() |
||
| 215 | { |
||
| 216 | $fields = $this->fields; |
||
| 217 | $str = ''; |
||
| 218 | $modelName = strtolower($this->getModelName($this->parsedModel)); |
||
| 219 | foreach ($fields as $key => $field) { |
||
| 220 | $normalizedField = $this->normalizeField($field); |
||
| 221 | $key = is_string($field) ? $field : $key; |
||
| 222 | $str .= $normalizedField->setModel($modelName)->setKey($key)->renderData(); |
||
| 223 | |||
| 224 | $str .= $this->makeTab(1, false); |
||
| 225 | } |
||
| 226 | |||
| 227 | return $str; |
||
| 228 | } |
||
| 229 | |||
| 230 | /** |
||
| 231 | * Parse <td> tags for head |
||
| 232 | */ |
||
| 233 | public function parseTitlesInBlade() |
||
| 234 | { |
||
| 235 | $fields = $this->fields; |
||
| 236 | $modelName = $this->getModelNameInLowerCase(); |
||
| 237 | |||
| 238 | $str = ''; |
||
| 239 | foreach ($fields as $key => $field) { |
||
| 240 | // We will normalize the field value because most of users prefer to use simple mode |
||
| 241 | // And they pass string and we will change it to a Field class object |
||
| 242 | $normalizedField = $this->normalizeField($field); |
||
| 243 | |||
| 244 | // Then we set the model and key to render the stub and get the string |
||
| 245 | // The returned string concatenates with previous rendered fields |
||
| 246 | $key = is_string($field) ? $field : $key; |
||
| 247 | $str .= $normalizedField->setModel($modelName)->setKey($key)->renderTitle(); |
||
| 248 | |||
| 249 | // To show the rendered html tag more readable and cleaner in view we make some tab |
||
| 250 | $str .= $this->makeTab(7, false); |
||
| 251 | } |
||
| 252 | |||
| 253 | return $str; |
||
| 254 | } |
||
| 255 | |||
| 256 | /** |
||
| 257 | * Create inputs HTML |
||
| 258 | */ |
||
| 259 | public function parseInputsInBlade() |
||
| 260 | { |
||
| 261 | $str = ''; |
||
| 262 | foreach ($this->inputs as $key => $type) { |
||
| 263 | $inputObject = $this->normalizeInput($key, $type); |
||
| 264 | $str .= $inputObject->setKey($key)->setAction($this->inputName)->render(); |
||
| 265 | } |
||
| 266 | |||
| 267 | return $str; |
||
| 268 | } |
||
| 269 | |||
| 270 | /** |
||
| 271 | * Tab Maker (Each tabs mean 4 space) |
||
| 272 | */ |
||
| 273 | public function makeTab($count, $newLine = true){ |
||
| 274 | $count = $count * 4; |
||
| 275 | $tabs = str_repeat(' ', $count); |
||
| 276 | |||
| 277 | return $newLine ? "\n".$tabs : $tabs; |
||
| 278 | } |
||
| 279 | |||
| 280 | public function getInputClassNamespace($type) |
||
| 285 | } |
||
| 286 | |||
| 287 | public function normalizeField($field) |
||
| 288 | { |
||
| 289 | if($field instanceof Field){ |
||
| 290 | return $field; |
||
| 291 | } |
||
| 292 | |||
| 296 | } |
||
| 297 | |||
| 298 | public function normalizeInput($key, $input){ |
||
| 299 | if ($input instanceof BaseInput){ |
||
| 300 | return $input; |
||
| 301 | } |
||
| 302 | |||
| 303 | $type = is_array($input) ? array_key_first($input) : $input; |
||
| 304 | $title = ucwords($key); |
||
| 305 | |||
| 306 | return $this->getInputClassNamespace($type)::label($title); |
||
| 307 | } |
||
| 308 | |||
| 309 | private function getModelNameInLowerCase() |
||
| 312 | } |
||
| 313 | |||
| 315 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.