Completed
Push — master ( 458768...717411 )
by Sam
03:06
created

EditCounter::averageRevisionSize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
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-deleted'] : 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
        return round($this->countAllRevisions() / $this->countAllPagesEdited(), 3);
265
    }
266
267
    /**
268
     * Average number of edits made per day.
269
     * @return float
270
     */
271
    public function averageRevisionsPerDay()
272
    {
273
        return round($this->countAllRevisions() / $this->getDays(), 3);
274
    }
275
    
276
    /**
277
     * Get the total number of edits made by the user with semi-automating tools.
278
     * @TODO
279
     */
280
    public function countAutomatedRevisions()
281
    {
282
        return 0;
283
    }
284
    
285
    /**
286
     * Get the count of (non-deleted) edits made in the given timeframe to now.
287
     * @param string $time One of 'day', 'week', 'month', or 'year'.
288
     * @return int The total number of live edits.
289
     */
290
    public function countRevisionsInLast($time)
291
    {
292
        $revCounts = $this->getRevisionCounts();
293
        return isset($revCounts[$time]) ? $revCounts[$time] : 0;
294
    }
295
296
    /**
297
     * Get the date and time of the user's first edit.
298
     */
299
    public function datetimeFirstRevision()
300
    {
301
        $first = $this->getRevisionDates()['first'];
302
        return new DateTime($first);
303
    }
304
305
    /**
306
     * Get the date and time of the user's first edit.
307
     * @return DateTime
308
     */
309
    public function datetimeLastRevision()
310
    {
311
        $last = $this->getRevisionDates()['last'];
312
        return new DateTime($last);
313
    }
314
315
    /**
316
     * Get the number of days between the first and last edits.
317
     * If there's only one edit, this is counted as one day.
318
     * @return int
319
     */
320
    public function getDays()
321
    {
322
        $days = $this->datetimeLastRevision()->diff($this->datetimeFirstRevision())->days;
323
        return $days > 0 ? $days : 1;
324
    }
325
326
    public function countFilesUploaded()
327
    {
328
        $logCounts = $this->getLogCounts();
329
        return $logCounts['upload-upload'] ?: 0;
330
    }
331
332
    public function countFilesUploadedCommons()
333
    {
334
        $logCounts = $this->getLogCounts();
335
        return $logCounts['files_uploaded_commons'] ?: 0;
336
    }
337
338
    /**
339
     * Get the total number of revisions the user has sent thanks for.
340
     * @return int
341
     */
342
    public function thanks()
343
    {
344
        $logCounts = $this->getLogCounts();
345
        return $logCounts['thanks-thank'] ?: 0;
346
    }
347
348
    /**
349
     * Get the total number of approvals
350
     * @return int
351
     */
352
    public function approvals()
353
    {
354
        $logCounts = $this->getLogCounts();
355
        $total = $logCounts['review-approve'] +
356
        (!empty($logCounts['review-approve-a']) ? $logCounts['review-approve-a'] : 0) +
357
        (!empty($logCounts['review-approve-i']) ? $logCounts['review-approve-i'] : 0) +
358
        (!empty($logCounts['review-approve-ia']) ? $logCounts['review-approve-ia'] : 0);
359
        return $total;
360
    }
361
362
    /**
363
     * @return int
364
     */
365
    public function patrols()
366
    {
367
        $logCounts = $this->getLogCounts();
368
        return $logCounts['patrol-patrol'] ?: 0;
369
    }
370
}
371