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

EditCounterController::monthcountsAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 15

Duplication

Lines 18
Ratio 100 %

Importance

Changes 0
Metric Value
dl 18
loc 18
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 15
nc 1
nop 2
1
<?php
2
/**
3
 * This file contains only the EditCounterController 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\RedirectResponse;
11
use Symfony\Component\HttpFoundation\Request;
12
use Symfony\Component\HttpFoundation\Response;
13
use Xtools\EditCounter;
14
use Xtools\EditCounterRepository;
15
use Xtools\Page;
16
use Xtools\Project;
17
use Xtools\ProjectRepository;
18
use Xtools\User;
19
use Xtools\UserRepository;
20
21
/**
22
 * Class EditCounterController
23
 */
24
class EditCounterController extends Controller
25
{
26
27
    /** @var User The user being queried. */
28
    protected $user;
29
    
30
    /** @var Project The project being queried. */
31
    protected $project;
32
    
33
    /** @var EditCounter The edit-counter, that does all the work. */
34
    protected $editCounter;
35
36
    /**
37
     * Get the tool's shortname.
38
     * @return string
39
     */
40
    public function getToolShortname()
41
    {
42
        return 'ec';
43
    }
44
45
    /**
46
     * Every action in this controller (other than 'index') calls this first.
47
     * @param string|bool $project The project name.
48
     * @param string|bool $username The username.
49
     */
50
    protected function setUpEditCounter($project = false, $username = false)
51
    {
52
        $this->project = ProjectRepository::getProject($project, $this->container);
0 ignored issues
show
Bug introduced by
It seems like $project defined by parameter $project on line 50 can also be of type boolean; however, Xtools\ProjectRepository::getProject() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
53
        $this->user = UserRepository::getUser($username, $this->container);
1 ignored issue
show
Bug introduced by
It seems like $username defined by parameter $username on line 50 can also be of type boolean; however, Xtools\UserRepository::getUser() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Compatibility introduced by
$this->container of type object<Symfony\Component...ion\ContainerInterface> is not a sub-type of object<Symfony\Component...ncyInjection\Container>. It seems like you assume a concrete implementation of the interface Symfony\Component\Depend...tion\ContainerInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
54
55
        // Get an edit-counter.
56
        $editCounterRepo = new EditCounterRepository();
57
        $editCounterRepo->setContainer($this->container);
1 ignored issue
show
Compatibility introduced by
$this->container of type object<Symfony\Component...ion\ContainerInterface> is not a sub-type of object<Symfony\Component...ncyInjection\Container>. It seems like you assume a concrete implementation of the interface Symfony\Component\Depend...tion\ContainerInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
58
        $this->editCounter = new EditCounter($this->project, $this->user);
59
        $this->editCounter->setRepository($editCounterRepo);
60
61
        // Don't continue if the user doesn't exist.
62
        if (!$this->user->existsOnProject($this->project)) {
63
            $this->addFlash('notice', 'user-not-found');
64
        }
65
    }
66
67
    /**
68
     * The initial GET request that displays the search form.
69
     *
70
     * @Route("/ec", name="ec")
71
     * @Route("/ec", name="EditCounter")
72
     * @Route("/ec/", name="EditCounterSlash")
73
     * @Route("/ec/index.php", name="EditCounterIndexPhp")
74
     * @Route("/ec/{project}", name="EditCounterProject")
75
     *
76
     * @param Request $request
77
     * @param string|null $project
78
     * @return RedirectResponse|Response
79
     */
80
    public function indexAction(Request $request, $project = null)
81
    {
82
        $queryProject = $request->query->get('project');
83
        $username = $request->query->get('username', $request->query->get('user'));
84
85
        if (($project || $queryProject) && $username) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $project of type string|null is loosely compared to true; 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...
86
            $routeParams = [ 'project'=>($project ?: $queryProject), 'username' => $username ];
87
            return $this->redirectToRoute("EditCounterResult", $routeParams);
88
        } elseif (!$project && $queryProject) {
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...
89
            return $this->redirectToRoute("EditCounterProject", [ 'project'=>$queryProject ]);
90
        }
91
92
        $project = ProjectRepository::getProject($queryProject, $this->container);
93
        if (!$project->exists()) {
94
            $project = ProjectRepository::getDefaultProject($this->container);
95
        }
96
97
        // Otherwise fall through.
98
        return $this->render('editCounter/index.html.twig', [
99
            "xtPageTitle" => "tool-ec",
100
            "xtSubtitle" => "tool-ec-desc",
101
            'xtPage' => "ec",
102
            'project' => $project,
103
        ]);
104
    }
105
106
    /**
107
     * Display all results.
108
     * @Route("/ec/{project}/{username}", name="EditCounterResult")
109
     * @param Request $request
110
     * @param string $project
111
     * @param string $username
112
     * @return Response
113
     */
114
    public function resultAction(Request $request, $project, $username)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
115
    {
116
        $this->setUpEditCounter($project, $username);
117
        $isSubRequest = $this->container->get('request_stack')->getParentRequest() !== null;
118
        return $this->render('editCounter/result.html.twig', [
119
            'xtTitle' => $this->user->getUsername() . ' - ' . $this->project->getTitle(),
120
            'xtPage' => 'ec',
121
            'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..'),
122
            'is_labs' => $this->project->getRepository()->isLabs(),
123
            'is_sub_request' => $isSubRequest,
124
            'user' => $this->user,
125
            'project' => $this->project,
126
            'ec' => $this->editCounter,
127
        ]);
128
    }
129
130
    /**
131
     * Display the general statistics section.
132
     * @Route("/ec-generalstats/{project}/{username}", name="EditCounterGeneralStats")
133
     * @param string $project
134
     * @param string $username
135
     * @return Response
136
     */
137 View Code Duplication
    public function generalStatsAction($project, $username)
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...
138
    {
139
        $this->setUpEditCounter($project, $username);
140
        $isSubRequest = $this->get('request_stack')->getParentRequest() !== null;
141
        return $this->render('editCounter/general_stats.html.twig', [
142
            'xtTitle' => 'general-stats',
143
            'xtPage' => 'ec',
144
            'is_sub_request' => $isSubRequest,
145
            'is_labs' => $this->project->getRepository()->isLabs(),
146
            'user' => $this->user,
147
            'project' => $this->project,
148
            'ec' => $this->editCounter,
149
        ]);
150
    }
151
152
    /**
153
     * Display the namespace totals section.
154
     * @Route("/ec-namespacetotals/{project}/{username}", name="EditCounterNamespaceTotals")
155
     * @param string $project
156
     * @param string $username
157
     * @return Response
158
     */
159 View Code Duplication
    public function namespaceTotalsAction($project, $username)
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...
160
    {
161
        $this->setUpEditCounter($project, $username);
162
        $isSubRequest = $this->get('request_stack')->getParentRequest() !== null;
163
        return $this->render('editCounter/namespace_totals.html.twig', [
164
            'xtTitle' => 'namespace-totals',
165
            'xtPage' => 'ec',
166
            'is_sub_request' => $isSubRequest,
167
            'is_labs' => $this->project->getRepository()->isLabs(),
168
            'user' => $this->user,
169
            'project' => $this->project,
170
            'ec' => $this->editCounter,
171
        ]);
172
    }
173
174
    /**
175
     * Display the timecard section.
176
     * @Route("/ec-timecard/{project}/{username}", name="EditCounterTimecard")
177
     * @param string $project
178
     * @param string $username
179
     * @return Response
180
     */
181 View Code Duplication
    public function timecardAction($project, $username)
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...
182
    {
183
        $this->setUpEditCounter($project, $username);
184
        $isSubRequest = $this->get('request_stack')->getParentRequest() !== null;
185
        $optedInPage = $this->project
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xtools\Repository as the method getPage() does only exist in the following sub-classes of Xtools\Repository: Xtools\ProjectRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
186
            ->getRepository()
187
            ->getPage($this->project, $this->project->userOptInPage($this->user));
188
        return $this->render('editCounter/timecard.html.twig', [
189
            'xtTitle' => 'timecard',
190
            'xtPage' => 'ec',
191
            'is_sub_request' => $isSubRequest,
192
            'is_labs' => $this->project->getRepository()->isLabs(),
193
            'user' => $this->user,
194
            'project' => $this->project,
195
            'ec' => $this->editCounter,
196
            'opted_in_page' => $optedInPage,
197
        ]);
198
    }
199
200
    /**
201
     * Display the year counts section.
202
     * @Route("/ec-yearcounts/{project}/{username}", name="EditCounterYearCounts")
203
     * @param string $project
204
     * @param string $username
205
     * @return Response
206
     */
207 View Code Duplication
    public function yearcountsAction($project, $username)
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...
208
    {
209
        $this->setUpEditCounter($project, $username);
210
        $isSubRequest = $this->container->get('request_stack')->getParentRequest() !== null;
211
        //$yearcounts = $this->editCounterHelper->getYearCounts($username);
1 ignored issue
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
212
        return $this->render('editCounter/yearcounts.html.twig', [
213
            'xtTitle' => 'year-counts',
214
            'xtPage' => 'ec',
215
            'is_sub_request' => $isSubRequest,
216
            //'namespaces' => $this->apiHelper->namespaces($project),
1 ignored issue
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
217
            //'yearcounts' => $yearcounts,
1 ignored issue
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
218
            'is_labs' => $this->project->getRepository()->isLabs(),
219
            'user' => $this->user,
220
            'project' => $this->project,
221
            'ec' => $this->editCounter,
222
        ]);
223
    }
224
225
    /**
226
     * Display the month counts section.
227
     * @Route("/ec-monthcounts/{project}/{username}", name="EditCounterMonthCounts")
228
     * @param string $project
229
     * @param string $username
230
     * @return Response
231
     */
232 View Code Duplication
    public function monthcountsAction($project, $username)
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...
233
    {
234
        $this->setUpEditCounter($project, $username);
235
        $isSubRequest = $this->container->get('request_stack')->getParentRequest() !== null;
236
        $optedInPage = $this->project
1 ignored issue
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xtools\Repository as the method getPage() does only exist in the following sub-classes of Xtools\Repository: Xtools\ProjectRepository. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
237
            ->getRepository()
238
            ->getPage($this->project, $this->project->userOptInPage($this->user));
239
        return $this->render('editCounter/monthcounts.html.twig', [
240
            'xtTitle' => 'month-counts',
241
            'xtPage' => 'ec',
242
            'is_sub_request' => $isSubRequest,
243
            'is_labs' => $this->project->getRepository()->isLabs(),
244
            'user' => $this->user,
245
            'project' => $this->project,
246
            'ec' => $this->editCounter,
247
            'opted_in_page' => $optedInPage,
248
        ]);
249
    }
250
251
    /**
252
     * Display the latest global edits section.
253
     * @Route("/ec-latestglobal/{project}/{username}", name="EditCounterLatestGlobal")
254
     * @param string $project
255
     * @param string $username
256
     * @return Response
257
     */
258 View Code Duplication
    public function latestglobalAction($project, $username)
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...
259
    {
260
        $this->setUpEditCounter($project, $username);
261
        $isSubRequest = $this->container->get('request_stack')->getParentRequest() !== null;
262
        return $this->render('editCounter/latest_global.html.twig', [
263
            'xtTitle' => 'latest-global-edits',
264
            'xtPage' => 'ec',
265
            'is_sub_request' => $isSubRequest,
266
            'user' => $this->user,
267
            'project' => $this->project,
268
            'ec' => $this->editCounter,
269
        ]);
270
    }
271
}
272