Completed
Push — master ( ca1336...ce2897 )
by Adrien
07:43
created

StatusMapper::findAll()   C

Complexity

Conditions 7
Paths 10

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 7

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 7
eloc 20
c 2
b 1
f 0
nc 10
nop 2
dl 0
loc 35
ccs 11
cts 11
cp 1
crap 7
rs 6.7272
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
     * @param \mQueue\Model\Movie $movie
15
     * @param \mQueue\Model\User $user
16
     * @param int $rating @see \mQueue\Model\Status
17
     * @return \mQueue\Model\Status
18
     */
19
    public static function set(Movie $movie, User $user, $rating)
0 ignored issues
show
Coding Style introduced by
This method's name is shorter than the configured minimum length of 4 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
20
    {
21
        $db = self::getDbTable()->getAdapter();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $db. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
22
        $db->beginTransaction();
23
24
        // Find out if a very recent status exist to be replaced, so user can change their mind "quickly"
25
        $select = self::getDbTable()->select()
26
                ->where('idUser = ?', $user->id)
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
27
                ->where('idMovie = ?', $movie->id)
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\Movie>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
28
                ->where('dateUpdate > DATE_SUB(NOW(), INTERVAL 5 MINUTE)');
29
30
        $status = self::getDbTable()->fetchRow($select);
31
32
        // Otherwise create a brand new one and set all existing one as "old"
33
        if (!$status) {
34
            $status = self::getDbTable()->createRow();
35
            $status->idUser = $user->id;
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
36
            $status->idMovie = $movie->id;
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\Movie>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
37
            $status->isLatest = true;
38
39
            // Here we must set dateUpdate to itself to avoid auto-update of the timestamp field by MySql
40
            $db->query('UPDATE `status` SET isLatest = 0, dateUpdate = dateUpdate WHERE idUser = ? AND idMovie = ?', [$user->id, $movie->id]);
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property id does not exist on object<mQueue\Model\Movie>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
41
        }
42
43
        $status->rating = $rating;
44
        $status->save();
45
46
        $db->commit();
47
48
        return $status;
49
    }
50
51
    /**
52
     * Find a status by its user and movie. If not found it will be created (but not saved).
53
     * @param int $idMovie
54
     * @param \mQueue\Model\User|null $user
55
     * @return \mQueue\Model\Status
56
     */
57 1
    public static function find($idMovie, User $user = null)
58
    {
59 1
        $statuses = self::findAll([$idMovie], $user);
60
61 1
        return reset($statuses);
62
    }
63
64
    /**
65
     * Returns an array of Status containing all statuses for specified ids
66
     * (if they don't exist in database, they will be created with default values but not saved)
67
     *
68
     * @param array $idMovies
69
     * @param \mQueue\Model\User|null $user
70
     * @return array of \mQueue\Model\Status
71
     */
72 1
    public static function findAll(array $idMovies, User $user = null)
73
    {
74 1
        $statuses = [];
75 1
        if (!count($idMovies)) {
76
            return $statuses;
77
        }
78
79
        // Do not hit database if we know there won't be any result anyway
80 1
        if ($user) {
81
            $select = self::getDbTable()->select()
82
                    ->where('idUser = ?', $user->id)
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
83
                    ->where('idMovie IN (?)', $idMovies)
84
                    ->where('isLatest = 1');
85
86
            $records = self::getDbTable()->fetchAll($select);
87
88
            foreach ($records as $record) {
89
                $statuses[$record->idMovie] = $record;
90
            }
91
        }
92
93
        // Fill non existing statuses in databases
94 1
        foreach ($idMovies as $id) {
95 1
            if (!array_key_exists($id, $statuses)) {
96 1
                $status = self::getDbTable()->createRow();
97 1
                if ($user) {
98
                    $status->idUser = $user->id;
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
99
                }
100 1
                $status->idMovie = $id;
101 1
                $statuses[$status->idMovie] = $status;
102
            }
103
        }
104
105 1
        return $statuses;
106
    }
107
108
    /**
109
     * Build statistic for the given user.
110
     * @param \mQueue\Model\User $user
111
     * @return array statistics
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<*,integer>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
112
     */
113 1
    public static function getStatistics(User $user)
114
    {
115 1
        $select = self::getDbTable()->select()->setIntegrityCheck(false)
116 1
                ->from('status', [
117 1
                    'rating' => 'IFNULL(rating, 0)',
118
                    'count' => 'COUNT(IFNULL(rating, 0))', ])
119 1
                ->joinRight('movie', 'movie.id = status.idMovie AND status.idUser = ' . $user->id, [])
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
120 1
                ->where('isLatest = 1 OR isLatest IS NULL')
121 1
                ->group('IFNULL(rating, 0)');
122
123 1
        $records = self::getDbTable()->fetchAll($select);
124
125
        // Set all count to 0
126 1
        $result = ['total' => 0, 'rated' => 0, Status::Nothing => 0];
127 1
        foreach (Status::$ratings as $val => $name) {
128 1
            $result[$val] = 0;
129
        }
130
131
        // Fetch real counts
132 1
        foreach ($records->toArray() as $row) {
133 1
            $result[$row['rating']] = $row['count'];
134 1
            if ($row['rating'] != Status::Nothing) {
135
                $result['rated'] += $row['count'];
136
            }
137 1
            $result['total'] += $row['count'];
138
        }
139
140 1
        return $result;
141
    }
142
143
    /**
144
     * Build statistic for the given user.
145
     * @param \mQueue\Model\User $user
0 ignored issues
show
Documentation introduced by
Should the type for parameter $user not be null|User?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
146
     * @return array statistics
147
     */
148
    public static function getGraph(User $user = null, $percent = false)
149
    {
150
        $select = self::getDbTable()->select()
151
                ->order('dateUpdate');
152
153
        if ($user) {
154
            $select->where('idUser = ?', $user->id);
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
155
        }
156
157
        $records = self::getDbTable()->fetchAll($select);
158
159
        // Set all count to 0
160
        $cumulatedStatuses = [Status::Nothing => 0];
161
        $graphData = [];
162
        foreach (Status::$ratings as $val => $name) {
163
            $cumulatedStatuses[$val] = 0;
164
            $graphData[$val] = [];
165
        }
166
167
        // Fetch real counts
168
        $lastStatuses = [];
169
        foreach ($records as $row) {
170
171
            // Add new status
172
            ++$cumulatedStatuses[$row->rating];
173
            $changed = [$row->rating];
174
175
            // Substract old status
176
            if (isset($lastStatuses[$row->idUser][$row->idMovie])) {
177
                --$cumulatedStatuses[$lastStatuses[$row->idUser][$row->idMovie]];
178
                $changed [] = $lastStatuses[$row->idUser][$row->idMovie];
179
            }
180
            $lastStatuses[$row->idUser][$row->idMovie] = $row->rating;
181
182
            $time = new DateTime($row->dateUpdate);
183
            $time->setTimezone(new DateTimeZone('GMT'));
184
            $epoch = (int) $time->format('U') * 1000;
185
186
            // If we are in percent mode, we need all status for each timestamp
187
            if ($percent) {
188
                $changed = array_keys(Status::$ratings);
189
            }
190
191
            // Keep for the graph only the changed values (and overwrite previous value if it happened at exactly the same time)
192
            foreach ($changed as $val) {
193
                $graphData[$val][$epoch] = [
194
                    $epoch,
195
                    $cumulatedStatuses[$val],
196
                ];
197
            }
198
        }
199
200
        // Format everything in a more output friendly way
201
        $result = [];
202
        foreach (Status::$ratings as $val => $name) {
203
            $result[] = [
204
                'name' => $name,
205
                'data' => array_values($graphData[$val]),
206
            ];
207
        }
208
209
        return $result;
210
    }
211
212
    /**
213
     * Returns the query to get activity for either the whole system, or a specific user, or a specific movie
214
     * @param \mQueue\Model\User|\mQueue\Model\Movie|null $item
215
     * @return Zend_Db_Table_Select
216
     */
217 3
    public static function getActivityQuery($item = null)
218
    {
219 3
        $select = self::getDbTable()->select()
220 3
                ->from('status')
221 3
                ->order('dateUpdate DESC');
222
223 3
        if ($item instanceof User) {
224 1
            $select->where('idUser = ?', $item->id);
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\User>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
225
        } elseif ($item instanceof Movie) {
226 1
            $select->where('idMovie = ?', $item->id);
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<mQueue\Model\Movie>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
227
        }
228
229 3
        return $select;
230
    }
231
}
232