| Total Complexity | 43 |
| Total Lines | 327 |
| Duplicated Lines | 3.06 % |
| Coverage | 41.49% |
| Changes | 0 | ||
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 XtoolsController 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 XtoolsController, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 23 | abstract class XtoolsController extends Controller |
||
| 24 | { |
||
| 25 | /** |
||
| 26 | * Given the request object, parse out common parameters. These include the |
||
| 27 | * 'project', 'username', 'namespace' and 'article', along with their legacy |
||
| 28 | * counterparts (e.g. 'lang' and 'wiki'). |
||
| 29 | * @param Request $request |
||
| 30 | * @return string[] Normalized parameters (no legacy params). |
||
| 31 | */ |
||
| 32 | 9 | public function parseQueryParams(Request $request) |
|
| 33 | { |
||
| 34 | /** @var string[] Each parameter and value that was detected. */ |
||
| 35 | 9 | $params = $this->getParams($request); |
|
| 36 | |||
| 37 | // Covert any legacy parameters, if present. |
||
| 38 | 9 | $params = $this->convertLegacyParams($params); |
|
| 39 | |||
| 40 | // Remove blank values. |
||
| 41 | 9 | return array_filter($params, function ($param) { |
|
| 42 | // 'namespace' or 'username' could be '0'. |
||
| 43 | 2 | return $param !== null && $param !== ''; |
|
| 44 | 9 | }); |
|
| 45 | } |
||
| 46 | |||
| 47 | /** |
||
| 48 | * Get a Project instance from the project string, using defaults if the |
||
| 49 | * given project string is invalid. |
||
| 50 | * @param string[] $params Query params. |
||
| 51 | * @return Project |
||
| 52 | */ |
||
| 53 | 7 | public function getProjectFromQuery($params) |
|
| 54 | { |
||
| 55 | // Set default project so we can populate the namespace selector |
||
| 56 | // on index pages. |
||
| 57 | 7 | if (empty($params['project'])) { |
|
| 58 | 5 | $project = $this->container->getParameter('default_project'); |
|
| 59 | } else { |
||
| 60 | 2 | $project = $params['project']; |
|
| 61 | } |
||
| 62 | |||
| 63 | 7 | $projectData = ProjectRepository::getProject($project, $this->container); |
|
| 64 | |||
| 65 | // Revert back to defaults if we've established the given project was invalid. |
||
| 66 | 7 | if (!$projectData->exists()) { |
|
| 67 | $projectData = ProjectRepository::getProject( |
||
| 68 | $this->container->getParameter('default_project'), |
||
| 69 | $this->container |
||
| 70 | ); |
||
| 71 | } |
||
| 72 | |||
| 73 | 7 | return $projectData; |
|
| 74 | } |
||
| 75 | |||
| 76 | /** |
||
| 77 | * If the project and username in the given params hash are valid, Project and User instances |
||
| 78 | * are returned. User validation only occurs if 'username' is in the params. |
||
| 79 | * Otherwise a redirect is returned that goes back to the index page. |
||
| 80 | * @param Request $request The HTTP request. |
||
| 81 | * @param string $tooHighEditCountAction If the requested user has more than the configured |
||
| 82 | * max edit count, they will be redirect to this route, passing in available params. |
||
| 83 | * @return RedirectResponse|array Array contains [Project|null, User|null] |
||
| 84 | */ |
||
| 85 | public function validateProjectAndUser(Request $request, $tooHighEditCountAction = null) |
||
| 86 | { |
||
| 87 | $params = $this->getParams($request); |
||
| 88 | |||
| 89 | $projectData = $this->validateProject($params); |
||
| 90 | if ($projectData instanceof RedirectResponse) { |
||
| 91 | return $projectData; |
||
| 92 | } |
||
| 93 | |||
| 94 | $userData = null; |
||
| 95 | |||
| 96 | if (isset($params['username'])) { |
||
| 97 | $userData = $this->validateUser($params, $projectData, $tooHighEditCountAction); |
||
| 98 | if ($userData instanceof RedirectResponse) { |
||
| 99 | return $userData; |
||
| 100 | } |
||
| 101 | } |
||
| 102 | |||
| 103 | return [$projectData, $userData]; |
||
| 104 | } |
||
| 105 | |||
| 106 | /** |
||
| 107 | * Validate the given project, returning a Project if it is valid or false otherwise. |
||
| 108 | * @param string|string[] $params Project domain or database name, or params hash as |
||
| 109 | * retrieved by self::getParams(). |
||
| 110 | * @return Project|false |
||
| 111 | */ |
||
| 112 | public function validateProject($params) |
||
| 127 | } |
||
| 128 | |||
| 129 | /** |
||
| 130 | * Validate the given user, returning a User or Redirect if they don't exist. |
||
| 131 | * @param string|string[] $params Username or params hash as retrieved by self::getParams(). |
||
| 132 | * @param Project $project Project to get check against. |
||
| 133 | * @param string $tooHighEditCountAction If the requested user has more than the configured |
||
| 134 | * max edit count, they will be redirect to this route, passing in available params. |
||
| 135 | * @return RedirectResponse|User |
||
| 136 | */ |
||
| 137 | public function validateUser($params, Project $project, $tooHighEditCountAction = null) |
||
| 170 | } |
||
| 171 | |||
| 172 | /** |
||
| 173 | * Get a Page instance from the given page title, and validate that it exists. |
||
| 174 | * @param Project $project |
||
| 175 | * @param string $pageTitle |
||
| 176 | * @return Page|RedirectResponse Page or redirect back to index if page doesn't exist. |
||
| 177 | */ |
||
| 178 | public function getAndValidatePage($project, $pageTitle) |
||
| 192 | } |
||
| 193 | |||
| 194 | /** |
||
| 195 | * Get all standardized parameters from the Request, either via URL query string or routing. |
||
| 196 | * @param Request $request |
||
| 197 | * @return string[] |
||
| 198 | */ |
||
| 199 | 10 | public function getParams(Request $request) |
|
| 236 | } |
||
| 237 | |||
| 238 | /** |
||
| 239 | * Get UTC timestamps from given start and end string parameters. |
||
| 240 | * This also makes $start on month before $end if not present, |
||
| 241 | * and makes $end the current time if not present. |
||
| 242 | * @param string $start |
||
| 243 | * @param string $end |
||
| 244 | * @param bool $useDefaults Whether to use defaults if the values |
||
| 245 | * are blank. The start date is set to one month before the end date, |
||
| 246 | * and the end date is set to the present. |
||
| 247 | * @return mixed[] Start and end date as UTC timestamps or 'false' if empty. |
||
| 248 | */ |
||
| 249 | 1 | public function getUTCFromDateParams($start, $end, $useDefaults = true) |
|
| 250 | { |
||
| 251 | 1 | $start = strtotime($start); |
|
| 252 | 1 | $end = strtotime($end); |
|
| 253 | |||
| 254 | // Use current time if end is not present (and is required), |
||
| 255 | // or if it exceeds the current time. |
||
| 256 | 1 | if (($useDefaults && $end === false) || $end > time()) { |
|
| 257 | $end = time(); |
||
| 258 | } |
||
| 259 | |||
| 260 | // Default to one month before end time if start is not present, |
||
| 261 | // as is not optional. |
||
| 262 | 1 | if ($useDefaults && $start === false) { |
|
| 263 | 1 | $start = strtotime('-1 month', $end); |
|
| 264 | } |
||
| 265 | |||
| 266 | // Reverse if start date is after end date. |
||
| 267 | 1 | if ($start > $end && $start !== false && $end !== false) { |
|
| 268 | 1 | $newEnd = $start; |
|
| 269 | 1 | $start = $end; |
|
| 270 | 1 | $end = $newEnd; |
|
| 271 | } |
||
| 272 | |||
| 273 | 1 | return [$start, $end]; |
|
| 274 | } |
||
| 275 | |||
| 276 | /** |
||
| 277 | * Given the params hash, normalize any legacy parameters to thier modern equivalent. |
||
| 278 | * @param string[] $params |
||
| 279 | * @return string[] |
||
| 280 | */ |
||
| 281 | 9 | private function convertLegacyParams($params) |
|
| 321 | } |
||
| 322 | |||
| 323 | /** |
||
| 324 | * Record usage of an API endpoint. |
||
| 325 | * @param string $endpoint |
||
| 326 | * @codeCoverageIgnore |
||
| 327 | */ |
||
| 328 | public function recordApiUsage($endpoint) |
||
| 353 |