Completed
Push — master ( 0b6105...cc4c1e )
by Nazar
04:59
created

Profile::get_internal()   C

Complexity

Conditions 11
Paths 32

Size

Total Lines 39
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 11

Importance

Changes 0
Metric Value
cc 11
eloc 23
nc 32
nop 2
dl 0
loc 39
ccs 21
cts 21
cp 1
crap 11
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

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
 * @package   CleverStyle Framework
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2011-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs\User;
9
use
10
	cs\Config,
11
	cs\Event,
12
	cs\Language,
13
	cs\Session,
14
	cs\User,
15
	h;
16
17
/**
18
 * Trait that contains all methods for `cs\User` for working with user's profile
19
 *
20
 * @property \cs\Cache\Prefix $cache
21
 * @property int              $id
22
 *
23
 * @method \cs\DB\_Abstract db()
24
 * @method \cs\DB\_Abstract db_prime()
25
 * @method false|int[]      get_groups(false|int $user)
26
 */
27
trait Profile {
28
	/**
29
	 * Copy of columns list of users table for internal needs without Cache usage
30
	 * @var array
31
	 */
32
	protected $users_columns = [];
33
	/**
34
	 * Local cache of users data
35
	 * @var array
36
	 */
37
	protected $data = [];
38 26
	protected function initialize_data () {
39 26
		$this->users_columns = $this->cache->get(
40 26
			'columns',
41
			function () {
42 2
				return $this->db()->columns('[prefix]users');
43 26
			}
44
		);
45 26
	}
46
	/**
47
	 * Get data item of specified user
48
	 *
49
	 * @param string|string[] $item
50
	 * @param false|int       $user If not specified - current user assumed
51
	 *
52
	 * @return false|int|mixed[]|string|Properties If <i>$item</i> is integer - cs\User\Properties object will be returned
53
	 */
54 20
	function get ($item, $user = false) {
55 20
		if (is_scalar($item) && ctype_digit((string)$item)) {
56 2
			return new Properties($item);
57
		}
58 20
		return $this->get_internal($item, $user);
59
	}
60
	/**
61
	 * Get data item of specified user
62
	 *
63
	 * @param string|string[] $item
64
	 * @param false|int       $user If not specified - current user assumed
65
	 *
66
	 * @return false|int|string|mixed[]
67
	 */
68 20
	protected function get_internal ($item, $user = false) {
69 20
		$user = (int)$user ?: $this->id;
70 20
		if (isset($this->data[$user])) {
71 14
			$data = $this->data[$user];
72
		} else {
73 20
			$data = $this->cache->get(
74
				$user,
75
				function () use ($user) {
76 18
					return $this->db()->qf(
77
						"SELECT *
78
						FROM `[prefix]users`
79 18
						WHERE `id` = $user
80 18
						LIMIT 1"
81 18
					) ?: false;
82 20
				}
83
			);
84 20
			if (!$data) {
85 4
				return false;
86 20
			} elseif ($this->memory_cache || $user == User::GUEST_ID) {
87 20
				$this->data[$user] = $data;
88
			}
89
		}
90
		/**
91
		 * If get an array of values
92
		 */
93 20
		if (is_array($item)) {
94 18
			$result = [];
95
			/**
96
			 * Trying to get value from the local cache, or make up an array of missing values
97
			 */
98 18
			foreach ($item as $i) {
99 18
				if (in_array($i, $this->users_columns)) {
100 18
					$result[$i] = $data[$i];
101
				}
102
			}
103 18
			return $result;
104
		}
105 20
		return in_array($item, $this->users_columns) ? $data[$item] : false;
106
	}
107
	/**
108
	 * Set data item of specified user
109
	 *
110
	 * @param array|string    $item Item-value array may be specified for setting several items at once
111
	 * @param int|null|string $value
112
	 * @param false|int       $user If not specified - current user assumed
113
	 *
114
	 * @return bool
115
	 */
116 14
	function set ($item, $value = null, $user = false) {
117 14
		$user     = (int)$user ?: $this->id;
118 14
		$data_set = [];
119 14
		if (!$this->set_internal($item, $value, $user, $data_set)) {
120 4
			return false;
121
		}
122 14
		if (!$data_set) {
123 2
			return true;
124
		}
125 14
		$update = [];
126 14
		foreach (array_keys($data_set) as $column) {
127 14
			$update[] = "`$column` = '%s'";
128
		}
129 14
		$update = implode(', ', $update);
130 14
		$result = $this->db_prime()->q(
131
			"UPDATE `[prefix]users`
132 14
			SET $update
133 14
			WHERE `id` = '$user'",
134 14
			xap($data_set, false)
135
		);
136 14
		if ($result) {
137 14
			unset($this->data[$user], $this->cache->$user);
138
		}
139 14
		return (bool)$result;
140
	}
141
	/**
142
	 * Set data item of specified user
143
	 *
144
	 * @param array|string    $item Item-value array may be specified for setting several items at once
145
	 * @param int|null|string $value
146
	 * @param int             $user If not specified - current user assumed
147
	 * @param array           $data_set
148
	 *
149
	 * @return bool
150
	 */
151 14
	protected function set_internal ($item, $value, $user, &$data_set) {
152 14
		if (is_array($item)) {
153 2
			$result = true;
154 2
			foreach ($item as $i => $v) {
155 2
				$result = $result && $this->set_internal($i, $v, $user, $data_set);
156
			}
157 2
			return $result;
158
		}
159 14
		if (!$this->set_internal_allowed($user, $item, $value)) {
160 4
			return false;
161
		}
162 14
		$old_value = $this->get($item, $user);
163 14
		if ($value == $old_value) {
164 2
			return true;
165
		}
166 14
		if ($item == 'language') {
167 2
			$value = $value && Language::instance()->get('clanguage', $value) == $value ? $value : '';
168 14
		} elseif ($item == 'timezone') {
169 2
			$value = in_array($value, get_timezones_list(), true) ? $value : '';
170 14
		} elseif ($item == 'avatar') {
171
			if (
172 2
				strpos($value, 'http://') !== 0 &&
173 2
				strpos($value, 'https://') !== 0
174
			) {
175 2
				$value = '';
176
			}
177 2
			$Event = Event::instance();
178 2
			$Event->fire(
179 2
				'System/upload_files/del_tag',
180
				[
181 2
					'url' => $old_value,
182 2
					'tag' => "users/$user/avatar"
183
				]
184
			);
185 2
			$Event->fire(
186 2
				'System/upload_files/add_tag',
187
				[
188 2
					'url' => $value,
189 2
					'tag' => "users/$user/avatar"
190
				]
191
			);
192
		}
193
		/**
194
		 * @var string $item
195
		 */
196 14
		$data_set[$item] = $value;
197 14
		if (in_array($item, ['login', 'email'], true)) {
198 2
			$old_value               = $this->get($item.'_hash', $user);
199 2
			$data_set[$item.'_hash'] = hash('sha224', $value);
200 2
			unset($this->cache->$old_value);
201 14
		} elseif ($item == 'password_hash' || ($item == 'status' && $value != User::STATUS_ACTIVE)) {
202 14
			Session::instance()->del_all($user);
203
		}
204 14
		return true;
205
	}
206
	/**
207
	 * Check whether setting specified item to specified value for specified user is allowed
208
	 *
209
	 * @param int    $user
210
	 * @param string $item
211
	 * @param string $value
212
	 *
213
	 * @return bool
214
	 */
215 14
	protected function set_internal_allowed ($user, $item, $value) {
216
		if (
217 14
			$user == User::GUEST_ID ||
218 14
			$item == 'id' ||
219 14
			!in_array($item, $this->users_columns, true)
220
		) {
221 4
			return false;
222
		}
223 14
		if (in_array($item, ['login', 'email'], true)) {
224 2
			$value = mb_strtolower($value);
225
			if (
226 2
				$item == 'email' &&
227 2
				!filter_var($value, FILTER_VALIDATE_EMAIL)
228
			) {
229 2
				return false;
230
			}
231 2
			if ($value == $this->get($item, $user)) {
232 2
				return true;
233
			}
234 2
			return $value && !$this->get_id(hash('sha224', $value));
235
		}
236 14
		return true;
237
	}
238
	/**
239
	 * Get user id by login or email hash (sha224) (hash from lowercase string)
240
	 *
241
	 * @param  string $login_hash Login or email hash
242
	 *
243
	 * @return false|int User id if found and not guest, otherwise - boolean <i>false</i>
244
	 */
245 18
	function get_id ($login_hash) {
246 18
		if (!preg_match('/^[0-9a-z]{56}$/', $login_hash)) {
247 2
			return false;
248
		}
249 18
		$id = $this->cache->get(
250
			$login_hash,
251 18
			function () use ($login_hash) {
252 16
				return (int)$this->db()->qfs(
253
					"SELECT `id`
254
					FROM `[prefix]users`
255
					WHERE
256
						`login_hash`	= '%s' OR
257
						`email_hash`	= '%s'
258 16
					LIMIT 1",
259
					$login_hash,
260
					$login_hash
261 16
				) ?: false;
262 18
			}
263
		);
264 18
		return $id && $id != User::GUEST_ID ? $id : false;
265
	}
266
	/**
267
	 * Get user avatar, if no one present - uses Gravatar
268
	 *
269
	 * @param int|null  $size Avatar size, if not specified or resizing is not possible - original image is used
270
	 * @param false|int $user If not specified - current user assumed
271
	 *
272
	 * @return string
273
	 */
274 6
	function avatar ($size = null, $user = false) {
275 6
		$user         = (int)$user ?: $this->id;
276 6
		$avatar       = $this->get('avatar', $user);
277 6
		$Config       = Config::instance();
278 6
		$guest_avatar = $Config->core_url().'/includes/img/guest.svg';
279 6
		if (!$avatar && $this->id != User::GUEST_ID && $Config->core['gravatar_support']) {
280 4
			$email_hash = md5($this->get('email', $user));
281 4
			$avatar     = "https://www.gravatar.com/avatar/$email_hash?d=mm&s=$size&d=".urlencode($guest_avatar);
282
		}
283 6
		if (!$avatar) {
284 6
			$avatar = $guest_avatar;
285
		}
286 6
		return h::prepare_url($avatar, true);
287
	}
288
	/**
289
	 * Get user name or login or email, depending on existing information
290
	 *
291
	 * @param false|int $user If not specified - current user assumed
292
	 *
293
	 * @return string
294
	 */
295 4
	function username ($user = false) {
296 4
		$user = (int)$user ?: $this->id;
297 4
		if ($user == User::GUEST_ID) {
298 2
			return Language::instance()->system_profile_guest;
299
		}
300 2
		$username = $this->get('username', $user);
301 2
		if (!$username) {
302 2
			$username = $this->get('login', $user);
303
		}
304 2
		return $username;
305
	}
306
	/**
307
	 * Returns array of users columns, available for getting of data
308
	 *
309
	 * @return array
310
	 */
311 2
	function get_users_columns () {
312 2
		return $this->users_columns;
313
	}
314
}
315