1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace App; |
4
|
|
|
|
5
|
|
|
class User |
6
|
|
|
{ |
7
|
|
|
|
8
|
|
|
/** @var integer The ID of the public group. */ |
9
|
|
|
const GROUP_PUBLIC = 1; |
10
|
|
|
|
11
|
|
|
/** @var integer The ID of the admin group. */ |
12
|
|
|
const GROUP_ADMIN = 2; |
13
|
|
|
|
14
|
|
|
/** @var \App\Db */ |
15
|
|
|
protected $db; |
16
|
|
|
|
17
|
|
|
/** @var stdClass */ |
18
|
|
|
protected $data; |
19
|
|
|
|
20
|
15 |
|
public function __construct($database = null) |
21
|
|
|
{ |
22
|
15 |
|
$this->db = ($database) ? $database : new Db(); |
23
|
15 |
|
} |
24
|
|
|
|
25
|
14 |
|
public function register($name, $email = null, $password = null) |
26
|
|
|
{ |
27
|
|
|
$params = [ |
28
|
14 |
|
'email' => $email, |
29
|
14 |
|
'password' => password_hash($password, PASSWORD_DEFAULT), |
30
|
|
|
]; |
31
|
|
|
|
32
|
|
|
// Add the user. |
33
|
14 |
|
$userCount = 'SELECT COUNT(*) FROM `users` WHERE `name` LIKE :name'; |
34
|
14 |
|
$userNum = $this->db->query($userCount, ['name' => "$name%"])->fetchColumn(); |
35
|
14 |
|
$userName = ($userNum > 0) ? $name . ' ' . ($userNum + 1) : $name; |
36
|
14 |
|
$params['name'] = $userName; |
37
|
14 |
|
$this->db->query("INSERT INTO users SET name=:name, email=:email, password=:password", $params); |
38
|
14 |
|
$userId = $this->db->lastInsertId(); |
39
|
|
|
|
40
|
|
|
// Add the new user to a group of their own. |
41
|
14 |
|
$groupCountSql = 'SELECT COUNT(*) FROM `groups` WHERE `name` LIKE :name'; |
42
|
14 |
|
$groupNum = $this->db->query($groupCountSql, ['name' => "$name%"])->fetchColumn(); |
43
|
14 |
|
$groupName = ($groupNum > 0) ? $name . ' ' . ($groupNum + 1) : $name; |
44
|
14 |
|
$this->db->query('INSERT INTO `groups` SET `name`=:name', ['name' => $groupName]); |
45
|
14 |
|
$personalGroupId = $this->db->lastInsertId(); |
46
|
14 |
|
$groupMemberSql = 'INSERT INTO `user_groups` SET `user`=:u, `group`=:g'; |
47
|
14 |
|
$this->db->query($groupMemberSql, ['u' => $userId, 'g' => $personalGroupId]); |
48
|
|
|
// Make it their default group. |
49
|
14 |
|
$defaultGroupSql = "UPDATE `users` SET `default_group` = :g WHERE `id`=:u"; |
50
|
14 |
|
$this->db->query($defaultGroupSql, ['g' => $personalGroupId, 'u' => $userId]); |
51
|
|
|
|
52
|
|
|
// Also add them to the public group. |
53
|
14 |
|
$groupMemberSql = 'INSERT INTO `user_groups` SET `user`=:u, `group`=:g'; |
54
|
14 |
|
$this->db->query($groupMemberSql, ['u' => $userId, 'g' => self::GROUP_PUBLIC]); |
55
|
|
|
|
56
|
|
|
// Reload the user's data. |
57
|
14 |
|
$this->load($userId); |
58
|
14 |
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Get a list of all groups that this user belongs to. |
62
|
|
|
* @return string[] Each array item is an array with 'id' and 'name' properties. |
63
|
|
|
*/ |
64
|
7 |
|
public function getGroups() |
65
|
|
|
{ |
66
|
7 |
|
if ($this->getId() === false) { |
67
|
1 |
|
$sql = "SELECT `id`, `name` FROM `groups` WHERE `id` = " . self::GROUP_PUBLIC; |
68
|
|
|
} else { |
69
|
|
|
$sql = "SELECT g.id, g.name FROM users u " |
70
|
|
|
. " JOIN user_groups ug ON ug.user = u.id " |
71
|
|
|
. " JOIN `groups` g ON ug.group = g.id" |
72
|
6 |
|
. " WHERE u.id = :id"; |
73
|
|
|
} |
74
|
7 |
|
$groups = []; |
75
|
7 |
|
$results = $this->db->query($sql, ['id' => $this->getId()])->fetchAll(); |
76
|
7 |
|
foreach ($results as $res) { |
77
|
7 |
|
$groups[] = ['id' => (int) $res->id, 'name' => $res->name]; |
78
|
|
|
} |
79
|
7 |
|
return $groups; |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Get an array of the IDs of all the groups that this user belongs to. |
84
|
|
|
* @return integer[] The group IDs. |
85
|
|
|
*/ |
86
|
|
|
public function getGroupIds() |
87
|
|
|
{ |
88
|
|
|
$ids = []; |
89
|
|
|
foreach ($this->getGroups() as $group) { |
90
|
|
|
$ids[] = $group['id']; |
91
|
|
|
} |
92
|
|
|
return $ids; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
public function getReminder() |
96
|
|
|
{ |
97
|
|
|
if ($this->getId() === false) { |
98
|
|
|
return false; |
99
|
|
|
} |
100
|
|
|
$sql = "UPDATE users SET reminder_token=:t, reminder_time=NOW() WHERE id=:id"; |
101
|
|
|
$unhashedToken = md5(time()); |
102
|
|
|
$params = [ |
103
|
|
|
't' => password_hash($unhashedToken, PASSWORD_DEFAULT), |
104
|
|
|
'id' => $this->getId(), |
105
|
|
|
]; |
106
|
|
|
$this->db->query($sql, $params); |
107
|
|
|
return $unhashedToken; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
public function checkReminderToken($token) |
111
|
|
|
{ |
112
|
|
|
return password_verify($token, $this->data->reminder_token); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
public function changePassword($password) |
116
|
|
|
{ |
117
|
|
|
if ($this->getId() === false) { |
118
|
|
|
return false; |
119
|
|
|
} |
120
|
|
|
$sql = "UPDATE users SET password=:pwd, reminder_token=NULL, reminder_time=NULL WHERE id=:id"; |
121
|
|
|
$params = [ |
122
|
|
|
'pwd' => password_hash($password, PASSWORD_DEFAULT), |
123
|
|
|
'id' => $this->getId(), |
124
|
|
|
]; |
125
|
|
|
$this->db->query($sql, $params); |
126
|
|
|
} |
127
|
|
|
|
128
|
14 |
|
public function load($id) |
129
|
|
|
{ |
130
|
14 |
|
$sql = "SELECT * FROM users WHERE id = :id"; |
131
|
14 |
|
$this->data = $this->db->query($sql, ['id' => $id])->fetch(); |
132
|
14 |
|
} |
133
|
|
|
|
134
|
|
|
public function loadByName($name) |
135
|
|
|
{ |
136
|
|
|
$sql = "SELECT * FROM users WHERE name = :name"; |
137
|
|
|
$this->data = $this->db->query($sql, ['name' => $name])->fetch(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Whether this user is loaded or not (i.e. has a database ID). |
142
|
|
|
* @return boolean |
143
|
|
|
*/ |
144
|
|
|
public function loaded() |
145
|
|
|
{ |
146
|
|
|
return $this->getId() !== false; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Get the user's ID, or false if the user isn't loaded yet. |
151
|
|
|
* @return bool|integer |
152
|
|
|
*/ |
153
|
13 |
|
public function getId() |
154
|
|
|
{ |
155
|
13 |
|
return (isset($this->data->id)) ? (int) $this->data->id : false; |
156
|
|
|
} |
157
|
|
|
|
158
|
2 |
|
public function getName() |
159
|
|
|
{ |
160
|
2 |
|
return isset($this->data->name) ? $this->data->name : false; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
public function getEmail() |
164
|
|
|
{ |
165
|
|
|
return isset($this->data->email) ? $this->data->email : false; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Get this user's default group. |
170
|
|
|
* |
171
|
|
|
* @return StdClass with attributes: 'id', 'name'. |
172
|
|
|
*/ |
173
|
13 |
View Code Duplication |
public function getDefaultGroup() |
|
|
|
|
174
|
|
|
{ |
175
|
13 |
|
$defaultGroupId = isset($this->data->default_group) ? $this->data->default_group : self::GROUP_PUBLIC; |
176
|
13 |
|
$sql = "SELECT * FROM groups WHERE id = :id"; |
177
|
13 |
|
$group = $this->db->query($sql, ['id' => $defaultGroupId])->fetch(); |
178
|
13 |
|
return $group; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.