Passed
Push — master ( 23707e...d837db )
by MusikAnimal
03:38
created

MetaController::resultAction()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 61
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 61
ccs 0
cts 0
cp 0
rs 8.6806
c 0
b 0
f 0
cc 6
eloc 41
nc 24
nop 3
crap 42

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file contains only the MetaController class.
4
 */
5
6
namespace AppBundle\Controller;
7
8
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
9
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10
use Symfony\Component\HttpFoundation\Request;
11
use DateTime;
12
use Symfony\Component\HttpFoundation\Response;
13
14
/**
15
 * This controller serves everything for the Meta tool.
16
 */
17
class MetaController extends XtoolsController
18
{
19
    /**
20
     * Display the form.
21
     * @Route("/meta", name="meta")
22
     * @Route("/meta", name="Meta")
23
     * @Route("/meta/", name="MetaSlash")
24
     * @Route("/meta/index.php", name="MetaIndexPhp")
25
     * @param Request $request
26
     * @return Response
27
     */
28 1 View Code Duplication
    public function indexAction(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
29
    {
30 1
        $params = $this->parseQueryParams($request);
31
32 1
        if (isset($params['start']) && isset($params['end'])) {
33
            return $this->redirectToRoute('MetaResult', $params);
34
        }
35
36 1
        return $this->render('meta/index.html.twig', [
37 1
            'xtPage' => 'meta',
38
            'xtPageTitle' => 'tool-meta',
39
            'xtSubtitle' => 'tool-meta-desc',
40
        ]);
41
    }
42
43
    /**
44
     * Display the results.
45
     * @Route("/meta/{start}/{end}/{legacy}", name="MetaResult")
46
     * @param string $start    Start date
47
     * @param string $end      End date
48
     * @param string [$legacy] Non-blank value indicates to show stats for legacy XTools
49
     * @return Response
50
     * @codeCoverageIgnore
51
     */
52
    public function resultAction($start, $end, $legacy = false)
53
    {
54
        $db = $legacy ? 'toolsdb' : 'default';
55
        $table = $legacy ? 's51187__metadata.xtools_timeline' : 'usage_timeline';
56
57
        $client = $this->container
58
            ->get('doctrine')
59
            ->getManager($db)
60
            ->getConnection();
61
62
        $query = $client->prepare("SELECT * FROM $table
63
                                 WHERE date >= :start AND date <= :end");
64
        $query->bindParam('start', $start);
65
        $query->bindParam('end', $end);
66
        $query->execute();
67
68
        $data = $query->fetchAll();
69
70
        // Create array of totals, along with formatted timeline data as needed by Chart.js
71
        $totals = [];
72
        $dateLabels = [];
73
        $timeline = [];
74
        $startObj = new DateTime($start);
75
        $endObj = new DateTime($end);
76
        $numDays = (int) $endObj->diff($startObj)->format("%a");
77
        $grandSum = 0;
78
79
        // Generate array of date labels
80
        for ($dateObj = new DateTime($start); $dateObj <= $endObj; $dateObj->modify('+1 day')) {
81
            $dateLabels[] = $dateObj->format('Y-m-d');
82
        }
83
84
        foreach ($data as $entry) {
85
            if (!isset($totals[$entry['tool']])) {
86
                $totals[$entry['tool']] = (int) $entry['count'];
87
88
                // Create arrays for each tool, filled with zeros for each date in the timeline
89
                $timeline[$entry['tool']] = array_fill(0, $numDays, 0);
90
            } else {
91
                $totals[$entry['tool']] += (int) $entry['count'];
92
            }
93
94
            $date = new DateTime($entry['date']);
95
            $dateIndex = (int) $date->diff($startObj)->format("%a");
96
            $timeline[$entry['tool']][$dateIndex] = (int) $entry['count'];
97
98
            $grandSum += $entry['count'];
99
        }
100
        arsort($totals);
101
102
        return $this->render('meta/result.html.twig', [
103
            'xtPage' => 'meta',
104
            'start' => $start,
105
            'end' => $end,
106
            'data' => $data,
107
            'totals' => $totals,
108
            'grandSum' => $grandSum,
109
            'dateLabels' => $dateLabels,
110
            'timeline' => $timeline,
111
        ]);
112
    }
113
114
    /**
115
     * Record usage of a particular XTools tool. This is called automatically
116
     *   in base.html.twig via JavaScript so that it is done asynchronously
117
     * @Route("/meta/usage/{tool}/{project}/{token}")
118
     * @param  $request Request
119
     * @param  string $tool    Internal name of tool
120
     * @param  string $project Project domain such as en.wikipedia.org
121
     * @param  string $token   Unique token for this request, so we don't have people
122
     *                         meddling with these statistics
123
     * @return Response
124
     * @codeCoverageIgnore
125
     */
126
    public function recordUsage(Request $request, $tool, $project, $token)
127
    {
128
        // Validate method and token.
129
        if ($request->getMethod() !== 'PUT' || !$this->isCsrfTokenValid('intention', $token)) {
130
            throw $this->createAccessDeniedException('This endpoint is for internal use only.');
131
        }
132
133
        // Ready the response object.
134
        $response = new Response();
135
        $response->headers->set('Content-Type', 'application/json');
136
137
        // Don't update counts for tools that aren't enabled
138
        if (!$this->container->getParameter("enable.$tool")) {
139
            $response->setStatusCode(Response::HTTP_FORBIDDEN);
140
            $response->setContent(json_encode([
141
                'error' => 'This tool is disabled'
142
            ]));
143
            return $response;
144
        }
145
146
        $conn = $this->container->get('doctrine')->getManager('default')->getConnection();
147
        $date =  date('Y-m-d');
148
149
        // Increment count in timeline
150
        $existsSql = "SELECT 1 FROM usage_timeline
151
                      WHERE date = '$date'
152
                      AND tool = '$tool'";
153
154 View Code Duplication
        if (count($conn->query($existsSql)->fetchAll()) === 0) {
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...
155
            $createSql = "INSERT INTO usage_timeline
156
                          VALUES(NULL, '$date', '$tool', 1)";
157
            $conn->query($createSql);
158
        } else {
159
            $updateSql = "UPDATE usage_timeline
160
                          SET count = count + 1
161
                          WHERE tool = '$tool'
162
                          AND date = '$date'";
163
            $conn->query($updateSql);
164
        }
165
166
        // Update per-project usage, if applicable
167
        if (!$this->container->getParameter('app.single_wiki')) {
168
            $existsSql = "SELECT 1 FROM usage_projects
169
                          WHERE tool = '$tool'
170
                          AND project = '$project'";
171
172 View Code Duplication
            if (count($conn->query($existsSql)->fetchAll()) === 0) {
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...
173
                $createSql = "INSERT INTO usage_projects
174
                              VALUES(NULL, '$tool', '$project', 1)";
175
                $conn->query($createSql);
176
            } else {
177
                $updateSql = "UPDATE usage_projects
178
                              SET count = count + 1
179
                              WHERE tool = '$tool'
180
                              AND project = '$project'";
181
                $conn->query($updateSql);
182
            }
183
        }
184
185
        $response->setStatusCode(Response::HTTP_NO_CONTENT);
186
        $response->setContent(json_encode([]));
187
        return $response;
188
    }
189
}
190