Completed
Push — master ( 6912d9...b5da35 )
by Sam
03:24
created

EditCounter::automatedRevisionsSummary()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Xtools;
4
5
use \DateTime;
6
7
/**
8
 * An EditCounter provides statistics about a user's edits on a project.
9
 */
10
class EditCounter extends Model
11
{
12
    
13
    /** @var Project */
14
    protected $project;
15
    
16
    /** @var User */
17
    protected $user;
18
19
    /** @var int[] */
20
    protected $revisionCounts;
21
22
    /** @var string[] */
23
    protected $revisionDates;
24
25
    /** @var int[] */
26
    protected $pageCounts;
27
    
28
    /** @var int[] */
29
    protected $logCounts;
30
31
    public function __construct(Project $project, User $user)
32
    {
33
        $this->project = $project;
34
        $this->user = $user;
35
    }
36
37
    /**
38
     * Get revision count data.
39
     * @return int[]
40
     */
41
    protected function getRevisionCounts()
42
    {
43
        if (! is_array($this->revisionCounts)) {
44
            $this->revisionCounts = $this->getRepository()
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 getRevisionCounts() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
45
                ->getRevisionCounts($this->project, $this->user);
46
        }
47
        return $this->revisionCounts;
48
    }
49
50
    /**
51
     * Get revision dates.
52
     * @return int[]
53
     */
54
    protected function getRevisionDates()
55
    {
56
        if (! is_array($this->revisionDates)) {
57
            $this->revisionDates = $this->getRepository()
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 getRevisionDates() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
58
                ->getRevisionDates($this->project, $this->user);
59
        }
60
        return $this->revisionDates;
61
    }
62
63
    /**
64
     * Get page count data.
65
     * @return int[]
66
     */
67
    protected function getPageCounts()
68
    {
69
        if (! is_array($this->pageCounts)) {
70
            $this->pageCounts = $this->getRepository()
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 getPageCounts() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
71
                ->getPageCounts($this->project, $this->user);
72
        }
73
        return $this->pageCounts;
74
    }
75
76
    /**
77
     * Get revision dates.
78
     * @return int[]
79
     */
80
    protected function getLogCounts()
81
    {
82
        if (! is_array($this->logCounts)) {
83
            $this->logCounts = $this->getRepository()
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 getLogCounts() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
84
                ->getLogCounts($this->project, $this->user);
85
        }
86
        return $this->logCounts;
87
    }
88
89
    public function countLiveRevisions()
90
    {
91
        $revCounts = $this->getRevisionCounts();
92
        return isset($revCounts['live']) ? $revCounts['live'] : 0;
93
    }
94
95
    /**
96
     * Get the total number of revisions that have been deleted.
97
     * @return int
98
     */
99
    public function countDeletedRevisions()
100
    {
101
        $revCounts = $this->getRevisionCounts();
102
        return isset($revCounts['deleted']) ? $revCounts['deleted'] : 0;
103
    }
104
105
    /**
106
     * Get the total edit count (live + deleted).
107
     * @return int
108
     */
109
    public function countAllRevisions()
110
    {
111
        return $this->countLiveRevisions() + $this->countDeletedRevisions();
112
    }
113
114
    /**
115
     * Get the total number of revisions with comments.
116
     * @return int
117
     */
118
    public function countRevisionsWithComments()
119
    {
120
        $revCounts = $this->getRevisionCounts();
121
        return isset($revCounts['with_comments']) ? $revCounts['with_comments'] : 0;
122
    }
123
124
    /**
125
     * Get the total number of revisions without comments.
126
     * @return int
127
     */
128
    public function countRevisionsWithoutComments()
129
    {
130
        return $this->countAllRevisions() - $this->countRevisionsWithComments();
131
    }
132
133
    /**
134
     * Get the total number of revisions marked as 'minor' by the user.
135
     * @return int
136
     */
137
    public function countMinorRevisions()
138
    {
139
        $revCounts = $this->getRevisionCounts();
140
        return isset($revCounts['minor']) ? $revCounts['minor'] : 0;
141
    }
142
143
    /**
144
     * Get the total number of revisions under 20 bytes.
145
     */
146
    public function countSmallRevisions()
147
    {
148
        $revCounts = $this->getRevisionCounts();
149
        return isset($revCounts['small']) ? $revCounts['small'] : 0;
150
    }
151
152
    /**
153
     * Get the total number of revisions over 1000 bytes.
154
     */
155
    public function countLargeRevisions()
156
    {
157
        $revCounts = $this->getRevisionCounts();
158
        return isset($revCounts['large']) ? $revCounts['large'] : 0;
159
    }
160
161
    /**
162
     * Get the average revision size for the user.
163
     * @return float Size in bytes.
164
     */
165
    public function averageRevisionSize()
166
    {
167
        $revisionCounts = $this->getRevisionCounts();
168
        return round($revisionCounts['average_size'], 3);
169
    }
170
171
    /**
172
     * Get the total number of non-deleted pages edited by the user.
173
     * @return int
174
     */
175
    public function countLivePagesEdited()
176
    {
177
        $pageCounts = $this->getPageCounts();
178
        return isset($pageCounts['edited-live']) ? $pageCounts['edited-live'] : 0;
179
    }
180
181
    /**
182
     * Get the total number of deleted pages ever edited by the user.
183
     * @return int
184
     */
185
    public function countDeletedPagesEdited()
186
    {
187
        $pageCounts = $this->getPageCounts();
188
        return isset($pageCounts['edited-deleted']) ? $pageCounts['edited-deleted'] : 0;
189
    }
190
191
    /**
192
     * Get the total number of pages ever edited by this user (both live and deleted).
193
     * @return int
194
     */
195
    public function countAllPagesEdited()
196
    {
197
        return $this->countLivePagesEdited() + $this->countDeletedPagesEdited();
198
    }
199
200
    /**
201
     * Get the total number of semi-automated edits.
202
     * @return int
203
     */
204
    public function countAutomatedEdits()
205
    {
206
    }
207
208
    /**
209
     * Get the total number of pages (both still live and those that have been deleted) created
210
     * by the user.
211
     * @return int
212
     */
213
    public function countPagesCreated()
214
    {
215
        return $this->countCreatedPagesLive() + $this->countPagesCreatedDeleted();
216
    }
217
218
    /**
219
     * Get the total number of pages created by the user, that have not been deleted.
220
     * @return int
221
     */
222
    public function countCreatedPagesLive()
223
    {
224
        $pageCounts = $this->getPageCounts();
225
        return isset($pageCounts['created-live']) ? (int)$pageCounts['created-live'] : 0;
226
    }
227
228
    /**
229
     * Get the total number of pages created by the user, that have since been deleted.
230
     * @return int
231
     */
232
    public function countPagesCreatedDeleted()
233
    {
234
        $pageCounts = $this->getPageCounts();
235
        return isset($pageCounts['created-deleted']) ? (int)$pageCounts['created-deleted'] : 0;
236
    }
237
238
    /**
239
     * Get the total number of pages that have been deleted by the user.
240
     * @return int
241
     */
242
    public function countPagesDeleted()
243
    {
244
        $logCounts = $this->getLogCounts();
245
        return isset($logCounts['delete-delete']) ? (int)$logCounts['delete-delete'] : 0;
246
    }
247
248
    /**
249
     * Get the total number of pages moved by the user.
250
     * @return int
251
     */
252
    public function countPagesMoved()
253
    {
254
        $logCounts = $this->getLogCounts();
255
        return isset($logCounts['move-move']) ? (int)$logCounts['move-move'] : 0;
256
    }
257
258
    /**
259
     * Get the average number of edits per page (including deleted revisions and pages).
260
     * @return float
261
     */
262
    public function averageRevisionsPerPage()
263
    {
264
        if ($this->countAllPagesEdited() == 0) {
265
            return 0;
266
        }
267
        return round($this->countAllRevisions() / $this->countAllPagesEdited(), 3);
268
    }
269
270
    /**
271
     * Average number of edits made per day.
272
     * @return float
273
     */
274
    public function averageRevisionsPerDay()
275
    {
276
        if ($this->getDays() == 0) {
277
            return 0;
278
        }
279
        return round($this->countAllRevisions() / $this->getDays(), 3);
280
    }
281
282
    /**
283
     * Get the total number of edits made by the user with semi-automating tools.
284
     */
285
    public function countAutomatedRevisions()
286
    {
287
        $autoSummary = $this->automatedRevisionsSummary();
288
        $count = 0;
289
        foreach ($autoSummary as $summary) {
290
            $count += $summary;
291
        }
292
        return $count;
293
    }
294
295
    /**
296
     * Get a summary of the numbers of edits made by the user with semi-automating tools.
297
     */
298
    public function automatedRevisionsSummary()
299
    {
300
        return $this->getRepository()->countAutomatedRevisions($this->project, $this->user);
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 countAutomatedRevisions() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
301
    }
302
303
    /**
304
     * Get the count of (non-deleted) edits made in the given timeframe to now.
305
     * @param string $time One of 'day', 'week', 'month', or 'year'.
306
     * @return int The total number of live edits.
307
     */
308
    public function countRevisionsInLast($time)
309
    {
310
        $revCounts = $this->getRevisionCounts();
311
        return isset($revCounts[$time]) ? $revCounts[$time] : 0;
312
    }
313
314
    /**
315
     * Get the date and time of the user's first edit.
316
     */
317
    public function datetimeFirstRevision()
318
    {
319
        $first = $this->getRevisionDates()['first'];
320
        return new DateTime($first);
321
    }
322
323
    /**
324
     * Get the date and time of the user's first edit.
325
     * @return DateTime
326
     */
327
    public function datetimeLastRevision()
328
    {
329
        $last = $this->getRevisionDates()['last'];
330
        return new DateTime($last);
331
    }
332
333
    /**
334
     * Get the number of days between the first and last edits.
335
     * If there's only one edit, this is counted as one day.
336
     * @return int
337
     */
338
    public function getDays()
339
    {
340
        $days = $this->datetimeLastRevision()->diff($this->datetimeFirstRevision())->days;
341
        return $days > 0 ? $days : 1;
342
    }
343
344
    public function countFilesUploaded()
345
    {
346
        $logCounts = $this->getLogCounts();
347
        return $logCounts['upload-upload'] ?: 0;
348
    }
349
350
    public function countFilesUploadedCommons()
351
    {
352
        $logCounts = $this->getLogCounts();
353
        return $logCounts['files_uploaded_commons'] ?: 0;
354
    }
355
356
    /**
357
     * Get the total number of revisions the user has sent thanks for.
358
     * @return int
359
     */
360
    public function thanks()
361
    {
362
        $logCounts = $this->getLogCounts();
363
        return $logCounts['thanks-thank'] ?: 0;
364
    }
365
366
    /**
367
     * Get the total number of approvals
368
     * @return int
369
     */
370
    public function approvals()
371
    {
372
        $logCounts = $this->getLogCounts();
373
        $total = $logCounts['review-approve'] +
374
        (!empty($logCounts['review-approve-a']) ? $logCounts['review-approve-a'] : 0) +
375
        (!empty($logCounts['review-approve-i']) ? $logCounts['review-approve-i'] : 0) +
376
        (!empty($logCounts['review-approve-ia']) ? $logCounts['review-approve-ia'] : 0);
377
        return $total;
378
    }
379
380
    /**
381
     * @return int
382
     */
383
    public function patrols()
384
    {
385
        $logCounts = $this->getLogCounts();
386
        return $logCounts['patrol-patrol'] ?: 0;
387
    }
388
389
    /**
390
     * Get the total edit counts for the top n projects of this user.
391
     * @param User $user
392
     * @param Project $project
393
     * @param int $numProjects
394
     * @return mixed[] Each element has 'total' and 'project' keys.
395
     */
396
    public function topProjectsEditCounts(User $user, Project $project, $numProjects = 10)
397
    {
398
        // Get counts.
399
        $editCounts = $this->getRepository()->getRevisionCountsAllProjects($user, $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 getRevisionCountsAllProjects() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
400
        // Sort.
401
        uasort($editCounts, function ($a, $b) {
402
            return $b['total'] - $a['total'];
403
        });
404
        // Truncate, and return.
1 ignored issue
show
Unused Code Comprehensibility introduced by
38% 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...
405
        return array_slice($editCounts, 0, $numProjects);
406
    }
407
408
    /**
409
     * Get the given user's total edit counts per namespace.
410
     */
411
    public function namespaceTotals()
412
    {
413
        $counts = $this->getRepository()->getNamespaceTotals($this->project, $this->user);
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 getNamespaceTotals() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
414
        arsort($counts);
415
        return $counts;
416
    }
417
418
    /**
419
     * Get a summary of the times of day and the days of the week that the user has edited.
420
     */
421
    public function timeCard()
422
    {
423
        return $this->getRepository()->getTimeCard($this->project, $this->user);
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 getTimeCard() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
424
    }
425
426
    /**
427
     *
428
     */
429
    public function yearCounts()
430
    {
431
        $totals = $this->getRepository()->getYearCounts($this->project, $this->user);
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 getYearCounts() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
432
        $out = [
433
            'years' => [],
434
            'namespaces' => [],
435
            'totals' => [],
436
        ];
437
        foreach ($totals as $total) {
438
            $out['years'][$total['year']] = $total['year'];
439
            $out['namespaces'][$total['page_namespace']] = $total['page_namespace'];
440
            if (!isset($out['totals'][$total['page_namespace']])) {
441
                $out['totals'][$total['page_namespace']] = [];
442
            }
443
            $out['totals'][$total['page_namespace']][$total['year']] = $total['count'];
444
        }
445
446
        return $out;
447
    }
448
449
    /**
450
     *
451
     */
452
    public function monthCounts()
453
    {
454
        $totals = $this->getRepository()->getMonthCounts($this->project, $this->user);
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 getMonthCounts() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
455
        $out = [
456
            'years' => [],
457
            'namespaces' => [],
458
            'totals' => [],
459
        ];
460
        $out['max_year'] = 0;
461
        $out['min_year'] = date('Y');
462
        foreach ($totals as $total) {
463
            // Collect all applicable years and namespaces.
464
            $out['max_year'] = max($out['max_year'], $total['year']);
465
            $out['min_year'] = min($out['min_year'], $total['year']);
466
            // Collate the counts by namespace, and then year and month.
467
            $ns = $total['page_namespace'];
468
            if (!isset($out['totals'][$ns])) {
469
                $out['totals'][$ns] = [];
470
            }
471
            $out['totals'][$ns][$total['year'] . $total['month']] = $total['count'];
472
        }
473
        // Fill in the blanks (where no edits were made in a given month for a namespace).
474
        for ($y = $out['min_year']; $y <= $out['max_year']; $y++) {
475
            for ($m = 1; $m <= 12; $m++) {
476
                foreach ($out['totals'] as $nsId => &$total) {
477
                    if (!isset($total[$y . $m])) {
478
                        $total[$y . $m] = 0;
479
                    }
480
                }
481
            }
482
        }
483
        return $out;
484
    }
485
486
    public function latestGlobalRevisions($max = 40)
487
    {
488
        // Re-use the list of active projects from all-project revision counting.
489
        $editCounts = $this->getRepository()->getRevisionCountsAllProjects($this->user, $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 getRevisionCountsAllProjects() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository. 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...
490
        // Go through each project that has any edits.
491
        $globalRevisions = [];
492
        $oldest = null;
493
        foreach ($editCounts as $editCount) {
494
            // Don't query revisions if there aren't any.
495
            if ($editCount['total'] == 0) {
496
                continue;
497
            }
498
            // Get this project's revisions.
499
            $revisions = $this->getRepository()
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 getRevisions() does only exist in the following sub-classes of Xtools\Repository: Xtools\EditCounterRepository, Xtools\PagesRepository. 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...
500
                ->getRevisions($editCount['project'], $this->user, $oldest);
501
            foreach ($revisions as &$revision) {
502
                $revision['project'] = $editCount['project'];
503
                $revision['timestamp'] = DateTime::createFromFormat('U', $revision['unix_timestamp']);
504
                // If we've already got enough, only check for those newer than the current oldest.
505
                $enough = (count($globalRevisions) >= $max);
506
                $isOlder = ($oldest === null
507
                            || ($oldest !== null && $revision['unix_timestamp'] < $oldest));
508
                if ($enough && $isOlder) {
509
                    $oldest = $revision['unix_timestamp'];
510
                }
511
                $globalRevisions[$revision['unix_timestamp']] = $revision;
512
            }
513
            // Sort and prune, before adding more.
514
            krsort($globalRevisions);
515
            $globalRevisions = array_slice($globalRevisions, 0, $max);
516
        }
517
        return $globalRevisions;
518
    }
519
}
520