Completed
Push — master ( c9d0e3...458768 )
by Sam
08:17
created

EditCounter::countAutomatedRevisions()   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 total number of non-deleted pages edited by the user.
163
     * @return int
164
     */
165
    public function countLivePagesEdited()
166
    {
167
        $pageCounts = $this->getPageCounts();
168
        return isset($pageCounts['edited-total']) ? $pageCounts['edited-total'] : 0;
169
    }
170
171
    public function countDeletedPagesEdited()
172
    {
173
        $pageCounts = $this->getPageCounts();
174
        return isset($pageCounts['edited-total']) ? $pageCounts['edited-total'] : 0;
175
    }
176
177
    /**
178
     * Get the total number of pages ever edited by this user (both live and deleted).
179
     * @return int
180
     */
181
    public function countAllPagesEdited()
182
    {
183
        return $this->countLivePagesEdited() + $this->countDeletedPagesEdited();
184
    }
185
186
    /**
187
     * Get the total number of semi-automated edits.
188
     * @return int
189
     */
190
    public function countAutomatedEdits()
191
    {
192
    }
193
194
    /**
195
     * Get the total number of pages (both still live and those that have been deleted) created
196
     * by the user.
197
     * @return int
198
     */
199
    public function countPagesCreated()
200
    {
201
        return $this->countCreatedPagesLive() + $this->countPagesCreatedDeleted();
202
    }
203
204
    /**
205
     * Get the total number of pages created by the user, that have not been deleted.
206
     * @return int
207
     */
208
    public function countCreatedPagesLive()
209
    {
210
        $pageCounts = $this->getPageCounts();
211
        return isset($pageCounts['created-live']) ? (int)$pageCounts['created-live'] : 0;
212
    }
213
    
214
    /**
215
     * Get the total number of pages created by the user, that have since been deleted.
216
     * @return int
217
     */
218
    public function countPagesCreatedDeleted()
219
    {
220
        $pageCounts = $this->getPageCounts();
221
        return isset($pageCounts['created-deleted']) ? (int)$pageCounts['created-deleted'] : 0;
222
    }
223
224
    /**
225
     * Get the total number of pages moved by the user.
226
     * @return int
227
     */
228
    public function countPagesMoved()
229
    {
230
        $pageCounts = $this->getPageCounts();
231
        return isset($pageCounts['moved']) ? (int)$pageCounts['moved'] : 0;
232
    }
233
234
    /**
235
     * Get the average number of edits per page (including deleted revisions and pages).
236
     * @return float
237
     */
238
    public function averageRevisionsPerPage()
239
    {
240
        return round($this->countAllRevisions() / $this->countAllPagesEdited(), 2);
241
    }
242
243
    /**
244
     * Average number of edits made per day.
245
     * @return float
246
     */
247
    public function averageRevisionsPerDay()
248
    {
249
        return round($this->countAllRevisions() / $this->getDays(), 2);
250
    }
251
    
252
    /**
253
     * Get the total number of edits made by the user with semi-automating tools.
254
     * @TODO
255
     */
256
    public function countAutomatedRevisions()
257
    {
258
        return 0;
259
    }
260
    
261
    /**
262
     * Get the count of (non-deleted) edits made in the given timeframe to now.
263
     * @param string $time One of 'day', 'week', 'month', or 'year'.
264
     * @return int The total number of live edits.
265
     */
266
    public function countRevisionsInLast($time)
267
    {
268
        $revCounts = $this->getRevisionCounts();
269
        return isset($revCounts[$time]) ? $revCounts[$time] : 0;
270
    }
271
272
    /**
273
     * Get the date and time of the user's first edit.
274
     */
275
    public function datetimeFirstRevision()
276
    {
277
        $first = $this->getRevisionDates()['first'];
278
        return new DateTime($first);
279
    }
280
281
    /**
282
     * Get the date and time of the user's first edit.
283
     * @return DateTime
284
     */
285
    public function datetimeLastRevision()
286
    {
287
        $last = $this->getRevisionDates()['last'];
288
        return new DateTime($last);
289
    }
290
291
    /**
292
     * Get the number of days between the first and last edits.
293
     * If there's only one edit, this is counted as one day.
294
     * @return int
295
     */
296
    public function getDays()
297
    {
298
        $days = $this->datetimeLastRevision()->diff($this->datetimeFirstRevision())->days;
299
        return $days > 0 ? $days : 1;
300
    }
301
302
    public function countFilesUploaded()
303
    {
304
        $logCounts = $this->getLogCounts();
305
        return $logCounts['upload-upload'] ?: 0;
306
    }
307
308
    public function countFilesUploadedCommons()
309
    {
310
        $logCounts = $this->getLogCounts();
311
        return $logCounts['files_uploaded_commons'] ?: 0;
312
    }
313
314
    /**
315
     * Get the total number of revisions the user has sent thanks for.
316
     * @return int
317
     */
318
    public function thanks()
319
    {
320
        $logCounts = $this->getLogCounts();
321
        return $logCounts['thanks-thank'] ?: 0;
322
    }
323
324
    /**
325
     * Get the total number of approvals
326
     * @return int
327
     */
328
    public function approvals()
329
    {
330
        $logCounts = $this->getLogCounts();
331
        $total = $logCounts['review-approve'] +
332
        (!empty($logCounts['review-approve-a']) ? $logCounts['review-approve-a'] : 0) +
333
        (!empty($logCounts['review-approve-i']) ? $logCounts['review-approve-i'] : 0) +
334
        (!empty($logCounts['review-approve-ia']) ? $logCounts['review-approve-ia'] : 0);
335
        return $total;
336
    }
337
338
    /**
339
     * @return int
340
     */
341
    public function patrols()
342
    {
343
        $logCounts = $this->getLogCounts();
344
        return $logCounts['patrol-patrol'] ?: 0;
345
    }
346
}
347