Failed Conditions
Push — master ( 2b3b32...674f38 )
by Adrien
03:18
created

StatusMapper::getGraph()   B

Complexity

Conditions 8
Paths 72

Size

Total Lines 61
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
eloc 33
c 0
b 0
f 0
dl 0
loc 61
rs 8.1475
ccs 0
cts 34
cp 0
cc 8
nc 72
nop 2
crap 72

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
namespace mQueue\Model;
4
5
use DateTime;
6
use DateTimeZone;
7
8
abstract class StatusMapper extends AbstractMapper
9
{
10
    /**
11
     * Define the status for a movie-user tuple. If an existing satus exists and
12
     * is very recent, it will be updated, otherwise a new status will be created.
13
     * IMPORTANT: This is the only allowed way to modify status.
14
     *
15
     * @param \mQueue\Model\Movie $movie
16
     * @param \mQueue\Model\User $user
17
     * @param int $rating @see \mQueue\Model\Status
18
     *
19
     * @return \mQueue\Model\Status
20
     */
21
    public static function set(Movie $movie, User $user, $rating)
22
    {
23
        $db = self::getDbTable()->getAdapter();
24
        $db->beginTransaction();
25
26
        // Find out if a very recent status exist to be replaced, so user can change their mind "quickly"
27
        $select = self::getDbTable()->select()
28
                ->where('idUser = ?', $user->id)
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on mQueue\Model\User. Since you implemented __get, consider adding a @property annotation.
Loading history...
29
                ->where('idMovie = ?', $movie->id)
30
                ->where('dateUpdate > DATE_SUB(NOW(), INTERVAL 5 MINUTE)');
31
32
        $status = self::getDbTable()->fetchRow($select);
33
34
        // Otherwise create a brand new one and set all existing one as "old"
35
        if (!$status) {
36
            $status = self::getDbTable()->createRow();
37
            $status->idUser = $user->id;
38
            $status->idMovie = $movie->id;
39
            $status->isLatest = true;
40
41
            // Here we must set dateUpdate to itself to avoid auto-update of the timestamp field by MySql
42
            $db->query('UPDATE `status` SET isLatest = 0, dateUpdate = dateUpdate WHERE idUser = ? AND idMovie = ?', [$user->id, $movie->id]);
43
        }
44
45
        $status->rating = $rating;
46
        $status->save();
47
48
        $db->commit();
49
50
        return $status;
51
    }
52
53
    /**
54
     * Find a status by its user and movie. If not found it will be created (but not saved).
55
     *
56
     * @param int $idMovie
57
     * @param null|\mQueue\Model\User $user
58
     *
59
     * @return \mQueue\Model\Status
60
     */
61
    public static function find($idMovie, User $user = null)
62
    {
63
        $statuses = self::findAll([$idMovie], $user);
64
65
        return reset($statuses);
66
    }
67
68
    /**
69
     * Returns an array of Status containing all statuses for specified ids
70
     * (if they don't exist in database, they will be created with default values but not saved)
71
     *
72
     * @param array $idMovies
73
     * @param null|\mQueue\Model\User $user
74
     *
75
     * @return array of \mQueue\Model\Status
76
     */
77
    public static function findAll(array $idMovies, User $user = null)
78
    {
79
        $statuses = [];
80
        if (!count($idMovies)) {
81
            return $statuses;
82
        }
83
84
        // Do not hit database if we know there won't be any result anyway
85
        if ($user) {
86
            $select = self::getDbTable()->select()
87
                    ->where('idUser = ?', $user->id)
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on mQueue\Model\User. Since you implemented __get, consider adding a @property annotation.
Loading history...
88
                    ->where('idMovie IN (?)', $idMovies)
89
                    ->where('isLatest = 1');
90
91
            $records = self::getDbTable()->fetchAll($select);
92
93
            foreach ($records as $record) {
94
                $statuses[$record->idMovie] = $record;
95
            }
96
        }
97
98
        // Fill non existing statuses in databases
99
        foreach ($idMovies as $id) {
100
            if (!array_key_exists($id, $statuses)) {
101
                $status = self::getDbTable()->createRow();
102
                if ($user) {
103
                    $status->idUser = $user->id;
104
                }
105
                $status->idMovie = $id;
106
                $statuses[$status->idMovie] = $status;
107
            }
108
        }
109
110
        return $statuses;
111
    }
112
113
    /**
114
     * Build statistic for the given user.
115
     *
116
     * @param \mQueue\Model\User $user
117
     *
118
     * @return array statistics
119
     */
120 1
    public static function getStatistics(User $user)
121
    {
122 1
        $select = self::getDbTable()->select()->setIntegrityCheck(false)
123 1
                ->from('status', [
124 1
                    'rating' => 'IFNULL(rating, 0)',
125
                    'count' => 'COUNT(IFNULL(rating, 0))', ])
126 1
                ->joinRight('movie', 'movie.id = status.idMovie AND status.idUser = ' . $user->id, [])
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on mQueue\Model\User. Since you implemented __get, consider adding a @property annotation.
Loading history...
127 1
                ->where('isLatest = 1 OR isLatest IS NULL')
128 1
                ->group('IFNULL(rating, 0)');
129
130 1
        $records = self::getDbTable()->fetchAll($select);
131
132
        // Set all count to 0
133 1
        $result = ['total' => 0, 'rated' => 0, Status::Nothing => 0];
134 1
        foreach (Status::$ratings as $val => $name) {
135 1
            $result[$val] = 0;
136
        }
137
138
        // Fetch real counts
139 1
        foreach ($records->toArray() as $row) {
140 1
            $result[$row['rating']] = $row['count'];
141 1
            if ($row['rating'] != Status::Nothing) {
142
                $result['rated'] += $row['count'];
143
            }
144 1
            $result['total'] += $row['count'];
145
        }
146
147 1
        return $result;
148
    }
149
150
    /**
151
     * Build statistic for the given user.
152
     *
153
     * @param \mQueue\Model\User $user
154
     * @param bool $percent
155
     *
156
     * @return array statistics
157
     */
158
    public static function getGraph(User $user = null, $percent = false)
159
    {
160
        $select = self::getDbTable()->select()
161
                ->order('dateUpdate');
162
163
        if ($user) {
164
            $select->where('idUser = ?', $user->id);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on mQueue\Model\User. Since you implemented __get, consider adding a @property annotation.
Loading history...
165
        }
166
167
        $records = self::getDbTable()->fetchAll($select);
168
169
        // Set all count to 0
170
        $cumulatedStatuses = [Status::Nothing => 0];
171
        $graphData = [];
172
        foreach (Status::$ratings as $val => $name) {
173
            $cumulatedStatuses[$val] = 0;
174
            $graphData[$val] = [];
175
        }
176
177
        // Fetch real counts
178
        $lastStatuses = [];
179
        foreach ($records as $row) {
180
            // Add new status
181
            ++$cumulatedStatuses[$row->rating];
182
            $changed = [$row->rating];
183
184
            // Substract old status
185
            if (isset($lastStatuses[$row->idUser][$row->idMovie])) {
186
                --$cumulatedStatuses[$lastStatuses[$row->idUser][$row->idMovie]];
187
                $changed[] = $lastStatuses[$row->idUser][$row->idMovie];
188
            }
189
            $lastStatuses[$row->idUser][$row->idMovie] = $row->rating;
190
191
            $time = new DateTime($row->dateUpdate);
192
            $time->setTimezone(new DateTimeZone('GMT'));
193
            $epoch = (int) $time->format('U') * 1000;
194
195
            // If we are in percent mode, we need all status for each timestamp
196
            if ($percent) {
197
                $changed = array_keys(Status::$ratings);
198
            }
199
200
            // Keep for the graph only the changed values (and overwrite previous value if it happened at exactly the same time)
201
            foreach ($changed as $val) {
202
                $graphData[$val][$epoch] = [
203
                    $epoch,
204
                    $cumulatedStatuses[$val],
205
                ];
206
            }
207
        }
208
209
        // Format everything in a more output friendly way
210
        $result = [];
211
        foreach (Status::$ratings as $val => $name) {
212
            $result[] = [
213
                'name' => $name,
214
                'data' => array_values($graphData[$val]),
215
            ];
216
        }
217
218
        return $result;
219
    }
220
221
    /**
222
     * Returns the query to get activity for either the whole system, or a specific user, or a specific movie
223
     *
224
     * @param null|\mQueue\Model\Movie|\mQueue\Model\User $item
225
     *
226
     * @return \Zend_Db_Table_Select
227
     */
228 3
    public static function getActivityQuery($item = null)
229
    {
230 3
        $select = self::getDbTable()->select()
231 3
                ->from('status')
232 3
                ->order('dateUpdate DESC');
233
234 3
        if ($item instanceof User) {
235 1
            $select->where('idUser = ?', $item->id);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on mQueue\Model\User. Since you implemented __get, consider adding a @property annotation.
Loading history...
236 2
        } elseif ($item instanceof Movie) {
237 1
            $select->where('idMovie = ?', $item->id);
238
        }
239
240 3
        return $select;
241
    }
242
}
243