Completed
Push — master ( 9fe0d2...0e0f1f )
by Sam
03:08
created

PagesController   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 314
Duplicated Lines 10.51 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 38
lcom 1
cbo 5
dl 33
loc 314
rs 8.3999
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getToolShortname() 0 4 1
C indexAction() 7 61 16
F resultAction() 26 220 21

How to fix   Duplicated Code   

Duplicated Code

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:

1
<?php
2
/**
3
 * This file contains only the PagesController class.
4
 */
5
6
namespace AppBundle\Controller;
7
8
use DateTime;
9
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
10
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
11
use Symfony\Component\HttpFoundation\RedirectResponse;
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\Response;
14
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
15
use Xtools\ProjectRepository;
16
17
/**
18
 * This controller serves the Pages tool.
19
 */
20
class PagesController extends Controller
21
{
22
23
    /**
24
     * Get the tool's shortname.
25
     * @return string
26
     */
27
    public function getToolShortname()
28
    {
29
        return 'pages';
30
    }
31
32
    /**
33
     * Display the form.
34
     * @Route("/pages", name="pages")
35
     * @Route("/pages", name="Pages")
36
     * @Route("/pages/", name="PagesSlash")
37
     * @Route("/pages/index.php", name="PagesIndexPhp")
38
     * @Route("/pages/{project}", name="PagesProject")
39
     * @param string $project The project domain name.
40
     * @return Response
41
     */
42
    public function indexAction($project = null)
43
    {
44
        // Grab the request object, grab the values out of it.
45
        $request = Request::createFromGlobals();
46
47
        $projectQuery = $request->query->get('project');
48
        $username = $request->query->get('username', $request->query->get('user'));
49
        $namespace = $request->query->get('namespace');
50
        $redirects = $request->query->get('redirects');
51
52
        // if values for required parameters are present, redirect to result action
53
        if ($projectQuery != "" && $username != "" && $namespace != "" && $redirects != "") {
54
            return $this->redirectToRoute("PagesResult", [
55
                'project'=>$projectQuery,
56
                'username' => $username,
57
                'namespace'=>$namespace,
58
                'redirects'=>$redirects,
59
            ]);
60 View Code Duplication
        } elseif ($projectQuery != "" && $username != "" && $namespace != "") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
61
            return $this->redirectToRoute("PagesResult", [
62
                'project'=>$projectQuery,
63
                'username' => $username,
64
                'namespace'=>$namespace,
65
            ]);
66
        } elseif ($projectQuery != "" && $username != "" && $redirects != "") {
67
            return $this->redirectToRoute("PagesResult", [
68
                'project'=>$projectQuery,
69
                'username' => $username,
70
                'redirects'=>$redirects,
71
            ]);
72
        } elseif ($projectQuery != "" && $username != "") {
73
            return $this->redirectToRoute("PagesResult", [
74
                'project'=>$projectQuery,
75
                'username' => $username,
76
            ]);
77
        } elseif ($projectQuery != "") {
78
            return $this->redirectToRoute("PagesProject", [ 'project'=>$projectQuery ]);
79
        }
80
81
        // set default wiki so we can populate the namespace selector
82
        if (!$project) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $project of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
83
            $project = $this->getParameter('default_project');
84
        }
85
86
        $projectData = ProjectRepository::getProject($project, $this->container);
87
88
        $namespaces = null;
89
90
        if ($projectData->exists()) {
91
            $namespaces = $projectData->getNamespaces();
92
        }
93
94
        // Otherwise fall through.
95
        return $this->render('pages/index.html.twig', [
96
            'xtPageTitle' => 'tool-pages',
97
            'xtSubtitle' => 'tool-pages-desc',
98
            'xtPage' => 'pages',
99
            'project' => $projectData,
100
            'namespaces' => $namespaces,
101
        ]);
102
    }
103
104
    /**
105
     * Display the results.
106
     * @Route("/pages/{project}/{username}/{namespace}/{redirects}", name="PagesResult")
107
     * @param string $project The project domain name.
108
     * @param string $username The username.
109
     * @param string $namespace The ID of the namespace.
110
     * @param string $redirects Whether to follow redirects or not.
111
     * @return RedirectResponse|Response
112
     */
113
    public function resultAction($project, $username, $namespace = "0", $redirects = "noredirects")
114
    {
115
        $lh = $this->get("app.labs_helper");
116
117
        $api = $this->get("app.api_helper");
118
119
        $username = ucfirst($username);
120
121
        $projectData = ProjectRepository::getProject($project, $this->container);
122
123
        // If the project exists, actually populate the values
124 View Code Duplication
        if (!$projectData->exists()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
125
            $this->addFlash("notice", ["invalid-project", $project]);
0 ignored issues
show
Documentation introduced by
array('invalid-project', $project) is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
126
            return $this->redirectToRoute("pages");
127
        }
128
129
        $dbName = $projectData->getDatabaseName();
130
        $projectUrl = $projectData->getUrl();
131
132
        $user_id = 0;
133
134
        $userTable = $lh->getTable("user", $dbName);
135
        $pageTable = $lh->getTable("page", $dbName);
136
        $pageAssessmentsTable = $lh->getTable("page_assessments", $dbName);
137
        $revisionTable = $lh->getTable("revision", $dbName);
138
        $archiveTable = $lh->getTable("archive", $dbName);
139
        $logTable = $lh->getTable("logging", $dbName, "userindex");
140
141
        // Grab the connection to the replica database (which is separate from the above)
142
        $conn = $this->get('doctrine')->getManager("replicas")->getConnection();
143
144
        // Prepare the query and execute
145
        $resultQuery = $conn->prepare("
146
			SELECT 'id' AS source, user_id AS value FROM $userTable WHERE user_name = :username
147
            ");
148
149
        $resultQuery->bindParam("username", $username);
150
        $resultQuery->execute();
151
152
        $result = $resultQuery->fetchAll();
153
154
        if (isset($result[0]["value"])) {
155
            $user_id = $result[0]["value"];
156
        }
157
158
        $namespaceConditionArc = "";
159
        $namespaceConditionRev = "";
160
161
        if ($namespace != "all") {
162
            $namespaceConditionRev = " AND page_namespace = '".intval($namespace)."' ";
163
            $namespaceConditionArc = " AND ar_namespace = '".intval($namespace)."' ";
164
        }
165
166
        $summaryColumns = ['namespace']; // what columns to show in namespace totals table
167
        $redirectCondition = "";
168
        if ($redirects == "onlyredirects") {
169
            // don't show redundant pages column if only getting data on redirects
170
            $summaryColumns[] = 'redirects';
171
172
            $redirectCondition = " AND page_is_redirect = '1' ";
173
        } elseif ($redirects == "noredirects") {
174
            // don't show redundant redirects column if only getting data on non-redirects
175
            $summaryColumns[] = 'pages';
176
177
            $redirectCondition = " AND page_is_redirect = '0' ";
178
        } else {
179
            // order is important here
180
            $summaryColumns[] = 'pages';
181
            $summaryColumns[] = 'redirects';
182
        }
183
        $summaryColumns[] = 'deleted'; // always show deleted column
184
185
        if ($user_id == 0) { // IP Editor or undefined username.
186
            $whereRev = " rev_user_text = '$username' AND rev_user = '0' ";
187
            $whereArc = " ar_user_text = '$username' AND ar_user = '0' ";
188
            $having = " rev_user_text = '$username' ";
189
        } else {
190
            $whereRev = " rev_user = '$user_id' AND rev_timestamp > 1 ";
191
            $whereArc = " ar_user = '$user_id' AND ar_timestamp > 1 ";
192
            $having = " rev_user = '$user_id' ";
193
        }
194
195
        $hasPageAssessments = $lh->isLabs() && $api->projectHasPageAssessments($project);
196
        $paSelects = $hasPageAssessments ? ', pa_class, pa_importance, pa_page_revision' : '';
197
        $paSelectsArchive = $hasPageAssessments ?
198
            ', NULL AS pa_class, NULL AS pa_page_id, NULL AS pa_page_revision'
199
            : '';
200
        $paJoin = $hasPageAssessments ? "LEFT JOIN $pageAssessmentsTable ON rev_page = pa_page_id" : '';
201
202
        $stmt = "
203
            (SELECT DISTINCT page_namespace AS namespace, 'rev' AS type, page_title AS page_title,
204
                page_len, page_is_redirect AS page_is_redirect, rev_timestamp AS timestamp,
205
                rev_user, rev_user_text, rev_len, rev_id $paSelects
206
            FROM $pageTable
207
            JOIN $revisionTable ON page_id = rev_page
208
            $paJoin
209
            WHERE $whereRev AND rev_parent_id = '0' $namespaceConditionRev $redirectCondition
210
            " . ($hasPageAssessments ? "GROUP BY rev_page" : "") . "
211
            )
212
213
            UNION
214
215
            (SELECT a.ar_namespace AS namespace, 'arc' AS type, a.ar_title AS page_title,
216
                0 AS page_len, '0' AS page_is_redirect, min(a.ar_timestamp) AS timestamp,
217
                a.ar_user AS rev_user, a.ar_user_text AS rev_user_text, a.ar_len AS rev_len,
218
                a.ar_rev_id AS rev_id $paSelectsArchive
219
            FROM $archiveTable a
220
            JOIN
221
            (
222
                SELECT b.ar_namespace, b.ar_title
223
                FROM $archiveTable AS b
224
                LEFT JOIN $logTable ON log_namespace = b.ar_namespace AND log_title = b.ar_title
225
                    AND log_user = b.ar_user AND (log_action = 'move' or log_action = 'move_redir')
226
                WHERE $whereArc AND b.ar_parent_id = '0' $namespaceConditionArc AND log_action IS NULL
227
            ) AS c ON c.ar_namespace= a.ar_namespace AND c.ar_title = a.ar_title
228
            GROUP BY a.ar_namespace, a.ar_title
229
            HAVING $having
230
            )
231
            ";
232
        $resultQuery = $conn->prepare($stmt);
233
        $resultQuery->execute();
234
235
        $result = $resultQuery->fetchAll();
236
237
        $pagesByNamespaceByDate = [];
238
        $pageTitles = [];
239
        $countsByNamespace = [];
240
        $total = 0;
241
        $redirectTotal = 0;
242
        $deletedTotal = 0;
243
244
        foreach ($result as $row) {
245
            $datetime = DateTime::createFromFormat('YmdHis', $row["timestamp"]);
246
            $datetimeKey = $datetime->format('Ymdhi');
247
            $datetimeHuman = $datetime->format('Y-m-d H:i');
248
249
            $pageData = array_merge($row, [
250
                "human_time" => $datetimeHuman,
251
                "page_title" => str_replace('_', ' ', $row["page_title"])
252
            ]);
253
254
            if ($hasPageAssessments) {
255
                $pageData["badge"] = $api->getAssessmentBadgeURL($project, $pageData["pa_class"]);
256
            }
257
258
            $pagesByNamespaceByDate[$row["namespace"]][$datetimeKey][] = $pageData;
259
260
            $pageTitles[] = $row["page_title"];
261
262
            // Totals
263
            if (isset($countsByNamespace[$row["namespace"]]["total"])) {
264
                $countsByNamespace[$row["namespace"]]["total"]++;
265
            } else {
266
                $countsByNamespace[$row["namespace"]]["total"] = 1;
267
                $countsByNamespace[$row["namespace"]]["redirect"] = 0;
268
                $countsByNamespace[$row["namespace"]]["deleted"] = 0;
269
            }
270
            $total++;
271
272 View Code Duplication
            if ($row["page_is_redirect"]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
273
                $redirectTotal++;
274
                // Redirects
275
                if (isset($countsByNamespace[$row["namespace"]]["redirect"])) {
276
                    $countsByNamespace[$row["namespace"]]["redirect"]++;
277
                } else {
278
                    $countsByNamespace[$row["namespace"]]["redirect"] = 1;
279
                }
280
            }
281
282 View Code Duplication
            if ($row["type"] === "arc") {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
                $deletedTotal++;
284
                // Deleted
285
                if (isset($countsByNamespace[$row["namespace"]]["deleted"])) {
286
                    $countsByNamespace[$row["namespace"]]["deleted"]++;
287
                } else {
288
                    $countsByNamespace[$row["namespace"]]["deleted"] = 1;
289
                }
290
            }
291
        }
292
293 View Code Duplication
        if ($total < 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
294
            $this->addFlash("notice", [ "no-result", $username ]);
0 ignored issues
show
Documentation introduced by
array('no-result', $username) is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
295
            return $this->redirectToRoute("PagesProject", [ "project"=>$project ]);
296
        }
297
298
        ksort($pagesByNamespaceByDate);
299
        ksort($countsByNamespace);
300
301
        foreach (array_keys($pagesByNamespaceByDate) as $key) {
302
            krsort($pagesByNamespaceByDate[$key]);
303
        }
304
305
        // Retrieve the namespaces
306
        $namespaces = $api->namespaces($project);
307
308
        // Assign the values and display the template
309
        return $this->render('pages/result.html.twig', [
310
            'xtPage' => 'pages',
311
            'xtTitle' => $username,
312
            'project' => $project,
313
            'project_url' => $projectUrl,
314
315
            'project' => $project,
316
            'username' => $username,
317
            'namespace' => $namespace,
318
            'redirect' => $redirects,
319
            'summaryColumns' => $summaryColumns,
320
321
            'namespaces' => $namespaces,
322
323
            'pages' => $pagesByNamespaceByDate,
324
            'count' => $countsByNamespace,
325
326
            'total' => $total,
327
            'redirectTotal' => $redirectTotal,
328
            'deletedTotal' => $deletedTotal,
329
330
            'hasPageAssessments' => $hasPageAssessments,
331
        ]);
332
    }
333
}
334