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 exportAvailableBalancesCls 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 exportAvailableBalancesCls, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 28 | class exportAvailableBalancesCls extends absences_Csv |
||
| 29 | { |
||
| 30 | private $resYears; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * |
||
| 34 | * @var array |
||
| 35 | */ |
||
| 36 | private $rights; |
||
| 37 | |||
| 38 | |||
| 39 | /** |
||
| 40 | * @var array |
||
| 41 | */ |
||
| 42 | private $recoveries; |
||
| 43 | |||
| 44 | |||
| 45 | /** |
||
| 46 | * @var string YYYY-MM-DD |
||
| 47 | */ |
||
| 48 | private $date = null; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * @var array |
||
| 52 | */ |
||
| 53 | private $dirfields; |
||
| 54 | |||
| 55 | |||
| 56 | public function getHtml() |
||
| 90 | |||
| 91 | /** |
||
| 92 | * template method to list available years |
||
| 93 | */ |
||
| 94 | View Code Duplication | public function getnextyear() |
|
| 95 | { |
||
| 96 | global $babDB; |
||
| 97 | |||
| 98 | if ($arr = $babDB->db_fetch_assoc($this->resYears)) |
||
| 99 | { |
||
| 100 | $this->year = bab_toHtml($arr['year']); |
||
| 101 | return true; |
||
| 102 | } |
||
| 103 | |||
| 104 | return false; |
||
| 105 | } |
||
| 106 | |||
| 107 | |||
| 108 | View Code Duplication | public function getnextfield() |
|
| 118 | |||
| 119 | /** |
||
| 120 | * template method to list available organization |
||
| 121 | */ |
||
| 122 | View Code Duplication | public function getnextorganization() |
|
| 123 | { |
||
| 124 | global $babDB; |
||
| 125 | |||
| 126 | if ($arr = $babDB->db_fetch_assoc($this->resOrganization)) |
||
| 127 | { |
||
| 128 | $this->organization = bab_toHtml($arr['name']); |
||
| 129 | $this->id_organization = bab_toHtml($arr['id']); |
||
| 130 | return true; |
||
| 131 | } |
||
| 132 | |||
| 133 | return false; |
||
| 134 | } |
||
| 135 | |||
| 136 | |||
| 137 | |||
| 138 | private function query($year, $groupby = '', $organization = '', $user = '') |
||
| 180 | |||
| 181 | |||
| 182 | |||
| 183 | |||
| 184 | |||
| 185 | |||
| 186 | /** |
||
| 187 | * New row for the user |
||
| 188 | * |
||
| 189 | * @param absences_AgentRight $agentRight |
||
| 190 | * @param array $remain |
||
| 191 | * |
||
| 192 | * @return Array |
||
| 193 | */ |
||
| 194 | private function getNewCurrentRow(absences_AgentRight $agentRight, Array $remain) |
||
| 195 | { |
||
| 196 | $arr = bab_getUserName($agentRight->id_user, false); |
||
| 197 | |||
| 198 | $currentRow = array( |
||
| 199 | $arr['lastname'], |
||
| 200 | $arr['firstname'], |
||
| 201 | (float) $remain['D'], // total days |
||
| 202 | (float) $remain['H'] // total hours |
||
| 203 | ); |
||
| 204 | |||
| 205 | foreach($this->rights as $initcol) { |
||
| 206 | $currentRow[$initcol] = 0.0; |
||
| 207 | } |
||
| 208 | |||
| 209 | foreach($this->recoveries as $quantity_unit => $initcol) { |
||
| 210 | if (isset($initcol)) { |
||
| 211 | $currentRow[$initcol] = 0.0; |
||
| 212 | } |
||
| 213 | } |
||
| 214 | |||
| 215 | return $currentRow; |
||
| 216 | } |
||
| 217 | |||
| 218 | |||
| 219 | /** |
||
| 220 | * Process one row |
||
| 221 | * if user row exists, add remain to the correct right column |
||
| 222 | * if the user row does not exists, create it |
||
| 223 | * |
||
| 224 | * return the row only if it is the first user row |
||
| 225 | * else return null |
||
| 226 | * |
||
| 227 | * @return array | null |
||
| 228 | */ |
||
| 229 | private function processRow($arr) |
||
| 230 | { |
||
| 231 | static $currentUser = null; |
||
| 232 | static $currentRow = null; |
||
| 233 | |||
| 234 | $return = null; |
||
| 235 | |||
| 236 | if (null === $arr) { |
||
| 237 | |||
| 238 | if (!isset($currentRow)) { |
||
| 239 | return array(); |
||
| 240 | } |
||
| 241 | |||
| 242 | $currentRow = null; |
||
| 243 | $currentUser = null; |
||
| 244 | |||
| 245 | return $currentRow; |
||
| 246 | } |
||
| 247 | |||
| 248 | $agentRight = new absences_AgentRight(); |
||
| 249 | $agentRight->setRow($arr); |
||
| 250 | |||
| 251 | $right = $agentRight->getRight(); |
||
| 252 | |||
| 253 | $remain = array('D' => 0.0, 'H' => 0.0); |
||
| 254 | |||
| 255 | $remain_line = $remain[$right->quantity_unit] = $agentRight->getAvailableQuantity($this->date); |
||
| 256 | |||
| 257 | |||
| 258 | if ($currentUser !== $agentRight->id_user) { |
||
| 259 | $currentUser = $agentRight->id_user; |
||
| 260 | |||
| 261 | if (null !== $currentRow && !$this->isRowEmpty($currentRow)) { |
||
| 262 | $return = $currentRow; |
||
| 263 | } |
||
| 264 | |||
| 265 | $currentRow = $this->getNewCurrentRow($agentRight, $remain); |
||
| 266 | |||
| 267 | $this->addDirValues($arr['id_user'], $currentRow); |
||
| 268 | |||
| 269 | } else { |
||
| 270 | |||
| 271 | $currentRow[2] += (float) $remain['D']; // total days |
||
| 272 | $currentRow[3] += (float) $remain['H']; // total hours |
||
| 273 | } |
||
| 274 | |||
| 275 | |||
| 276 | $this->setRightColumn($right, $currentRow, $remain, $remain_line); |
||
| 277 | |||
| 278 | |||
| 279 | return $return; |
||
| 280 | } |
||
| 281 | |||
| 282 | |||
| 283 | /** |
||
| 284 | * Complete current row with right value |
||
| 285 | * @param absences_Right $right |
||
| 286 | * @param array &$currentRow |
||
| 287 | */ |
||
| 288 | private function setRightColumn(absences_Right $right, Array &$currentRow, Array $remain, $remain_line) |
||
| 311 | |||
| 312 | /** |
||
| 313 | * Complete current row with directory entry values |
||
| 314 | * @param int $id_user |
||
| 315 | * @param array &$currentRow |
||
| 316 | */ |
||
| 317 | private function addDirValues($id_user, Array &$currentRow) |
||
| 325 | |||
| 326 | |||
| 327 | |||
| 328 | |||
| 329 | /** |
||
| 330 | * @return string |
||
| 331 | */ |
||
| 332 | private function getSeparator() |
||
| 342 | |||
| 343 | |||
| 344 | |||
| 345 | protected function getDate() |
||
| 350 | |||
| 351 | |||
| 352 | /** |
||
| 353 | * @return array |
||
| 354 | */ |
||
| 355 | private function getHeader($year = '', $organization = '') |
||
| 419 | |||
| 420 | |||
| 421 | |||
| 422 | public function csv() |
||
| 445 | |||
| 446 | |||
| 447 | |||
| 448 | |||
| 449 | |||
| 450 | private function echoCsv($header) |
||
| 474 | |||
| 475 | |||
| 476 | /** |
||
| 477 | * @return array |
||
| 478 | */ |
||
| 479 | private function getUserRow($id_user) |
||
| 495 | |||
| 496 | |||
| 497 | |||
| 498 | /** |
||
| 499 | * @return Widget_Displayable_Interface |
||
| 500 | */ |
||
| 501 | public function compareDateForOneUser($id_user) |
||
| 558 | } |
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.