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 DataTableAPI 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 DataTableAPI, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 9 | class DataTableAPI extends RestAPI |
||
| 10 | { |
||
| 11 | protected $dataSetName; |
||
| 12 | protected $dataTableName; |
||
| 13 | protected $primaryKeyName; |
||
| 14 | |||
| 15 | /** |
||
| 16 | * Create the DataTableAPI for the given DataTable info |
||
| 17 | * |
||
| 18 | * @param string $datSetName The name of the DataSet used in the Settings |
||
|
|
|||
| 19 | * @param string $dataTableName The name of the table in the DataSet |
||
| 20 | * @param string|false $primaryKeyName The table primary key. Must be specified for update/delete capable tables |
||
| 21 | */ |
||
| 22 | public function __construct($dataSetName, $dataTableName, $primaryKeyName = false) |
||
| 28 | |||
| 29 | public function setup($app) |
||
| 40 | |||
| 41 | protected function getDataTable() |
||
| 45 | |||
| 46 | protected function canRead($request) |
||
| 52 | |||
| 53 | protected function canCreate($request) |
||
| 58 | |||
| 59 | protected function canUpdate($request, $entity) |
||
| 64 | |||
| 65 | protected function canDelete($request, $entity) |
||
| 70 | |||
| 71 | protected function getFilterForPrimaryKey($value) |
||
| 75 | |||
| 76 | protected function manipulateParameters($request, &$odata) |
||
| 80 | |||
| 81 | protected function validateCreate(&$obj, $request) |
||
| 85 | |||
| 86 | protected function validateUpdate(&$newObj, $request, $oldObj) |
||
| 90 | |||
| 91 | protected function postUpdateAction($newObj, $request, $oldObj) |
||
| 95 | |||
| 96 | protected function postDeleteAction($entry) |
||
| 100 | |||
| 101 | public function readEntries($request, $response, $args) |
||
| 131 | |||
| 132 | public function createEntry($request, $response, $args) |
||
| 151 | |||
| 152 | public function readEntry($request, $response, $args) |
||
| 173 | |||
| 174 | public function updateEntry($request, $response, $args) |
||
| 175 | { |
||
| 176 | if($this->canRead($request) === false) |
||
| 177 | { |
||
| 178 | return $response->withStatus(401); |
||
| 179 | } |
||
| 180 | $filter = $this->getFilterForPrimaryKey($args['name']); |
||
| 181 | $dataTable = $this->getDataTable(); |
||
| 182 | $entry = $dataTable->read($filter); |
||
| 183 | if(empty($entry)) |
||
| 184 | { |
||
| 185 | return $response->withStatus(404); |
||
| 186 | } |
||
| 187 | if(count($entry) === 1 && isset($entry[0])) |
||
| 188 | { |
||
| 189 | $entry = $entry[0]; |
||
| 190 | } |
||
| 191 | if($this->canUpdate($request, $entry) === false) |
||
| 192 | { |
||
| 193 | return $response->withStatus(401); |
||
| 194 | } |
||
| 195 | $obj = $request->getParsedBody(); |
||
| 196 | View Code Duplication | if($obj === null) |
|
| 197 | { |
||
| 198 | $request->getBody()->rewind(); |
||
| 199 | $obj = $request->getBody()->getContents(); |
||
| 200 | $tmp = json_decode($obj, true); |
||
| 201 | if($tmp !== null) |
||
| 202 | { |
||
| 203 | $obj = $tmp; |
||
| 204 | } |
||
| 205 | } |
||
| 206 | if($this->validateUpdate($obj, $request, $entry) === false) |
||
| 207 | { |
||
| 208 | return $response->withStatus(400); |
||
| 209 | } |
||
| 210 | $ret = $dataTable->update($filter, $obj); |
||
| 211 | if($ret) |
||
| 212 | { |
||
| 213 | $ret = $this->postUpdateAction($obj, $request, $entry); |
||
| 214 | } |
||
| 215 | return $response->withJson($ret); |
||
| 216 | } |
||
| 217 | |||
| 218 | public function deleteEntry($request, $response, $args) |
||
| 246 | } |
||
| 247 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.
Consider the following example. The parameter
$irelandis not defined by the methodfinale(...).The most likely cause is that the parameter was changed, but the annotation was not.