You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

256 lines
8.1 KiB
PHP

<?php
namespace Isekai\UserPoints\Service;
use stdClass;
use User;
use MediaWiki\MediaWikiServices;
/**
* @property int $user_id
* @property string $last_sign_date
* @property string|array $sign_days_data
* @property int $total_sign_days
*/
class IsekaiUserDailySignData extends stdClass {}
/**
* @property int $userId
* @property string $lastSignDate
* @property array $signDaysData
* @property int $totalSignDays
*/
class IsekaiUserDailySign {
/** @var MediaWikiServices */
private $services;
/** @var User */
private $user;
/** @var array */
private $pointConfig;
/** @var array */
private $dailySignConfig;
private $dataKeysMap = [
'userId' => 'user_id',
'lastSignDate' => 'last_sign_date',
'signDaysData' => 'sign_days_data',
'totalSignDays' => 'total_sign_days'
];
/** @var IsekaiUserDailySignData|null */
private $mDailySignData = null;
private $recordExists = false;
public function __construct(User $user, array $pointConfig, array $dailySignConfig, MediaWikiServices $services) {
$this->user = $user;
$this->pointConfig = $pointConfig;
$this->dailySignConfig = $dailySignConfig;
$this->services = $services;
}
private function loadDailySignData() {
if (!$this->mDailySignData) {
$dbr = $this->services->getDBLoadBalancer()->getConnection(DB_REPLICA);
$this->mDailySignData = $dbr->selectRow(
'isekai_user_daily_sign',
'*',
[
'user_id' => $this->user->getId()
],
__METHOD__
);
if (!$this->mDailySignData) {
$this->initDefaultData();
} else {
$this->mDailySignData->sign_days_data = json_decode($this->mDailySignData->sign_days_data, true) ?? [];
$this->recordExists = true;
}
}
}
private function initDefaultData() {
$this->mDailySignData = new IsekaiUserDailySignData();
$this->mDailySignData->user_id = $this->user->getId();
$this->mDailySignData->last_sign_date = '1970-01-01';
$this->mDailySignData->sign_days_data = [];
$this->mDailySignData->total_sign_days = 0;
}
public function __get($name) {
$this->loadDailySignData();
if (isset($this->dataKeysMap[$name])) {
$key = $this->dataKeysMap[$name];
return $this->mDailySignData->$key;
} else {
throw new \Exception("Invalid property $name");
}
}
public function doSign() {
$this->loadDailySignData();
$pointDelta = [];
$lastSignTime = strtotime($this->mDailySignData->last_sign_date);
if (date('Y-m-d', time()) == date('Y-m-d', $lastSignTime)) { // already signed in today
return [];
}
/** @var IsekaiUserPointsFactory */
$userPointsFactory = $this->services->getService('IsekaiUserPoints');
foreach ($this->dailySignConfig as $pointType => $config) {
if (!isset($this->pointConfig[$pointType])) { // point type not exist, ignore
continue;
}
if (!isset($config['points'])) { // no points config, ignore
continue;
}
$signDays = $this->mDailySignData->sign_days_data[$pointType] ?? 0;
$continuous_reset = $config['continuous_reset'] ?? false;
$expireTime = $config['expire_time'] ?? -1;
$points = $config['points'];
if (!is_array($points)) {
$points = [ $points ];
}
switch ($continuous_reset) {
case 'day':
if (date('Y-m-d', strtotime('-1 day')) != date('Y-m-d', $lastSignTime)) {
$signDays = 0;
}
case 'week':
if (date('Y-W', time()) != date('Y-W', $lastSignTime)) {
$signDays = 0;
}
break;
case 'month':
if (date('Y-m', time()) != date('Y-m', $lastSignTime)) {
$signDays = 0;
}
break;
case 'year':
if (date('Y', time()) != date('Y', $lastSignTime)) {
$signDays = 0;
}
break;
}
$pointsIndex = min($signDays, count($points) - 1);
$pointsAdd = $points[$pointsIndex];
$pointsService = $userPointsFactory->newFromUser($this->user, $pointType);
$pointsService->addPoints($pointsAdd, $expireTime, 'daily_sign', 'sign_in');
$pointDelta[$pointType] = $pointsAdd;
$this->mDailySignData->sign_days_data[$pointType] = $signDays + 1;
}
$this->mDailySignData->last_sign_date = date('Y-m-d H:i:s', time());
$this->mDailySignData->total_sign_days ++;
$this->save();
$this->saveSignLog($pointDelta);
return $pointDelta;
}
private function save() {
$dbw = $this->services->getDBLoadBalancer()->getConnection(DB_PRIMARY);
if ($this->recordExists) {
$dbw->update(
'isekai_user_daily_sign',
[
'last_sign_date' => $this->mDailySignData->last_sign_date,
'sign_days_data' => json_encode($this->mDailySignData->sign_days_data),
'total_sign_days' => $this->mDailySignData->total_sign_days,
],
[
'user_id' => $this->user->getId()
],
__METHOD__
);
} else {
$dbw->insert(
'isekai_user_daily_sign',
[
'user_id' => $this->mDailySignData->user_id,
'last_sign_date' => $this->mDailySignData->last_sign_date,
'sign_days_data' => json_encode($this->mDailySignData->sign_days_data),
'total_sign_days' => $this->mDailySignData->total_sign_days,
],
__METHOD__
);
$this->recordExists = true;
}
}
private function saveSignLog($pointDelta) {
$dbr = $this->services->getDBLoadBalancer()->getConnection(DB_REPLICA);
$dbw = $this->services->getDBLoadBalancer()->getConnection(DB_PRIMARY);
$currentYear = intval(date('Y', time()));
$currentMonth = intval(date('m', time()));
$currentDate = intval(date('d', time()));
$logData = $dbr->selectRow(
'isekai_user_daily_sign_log',
'*',
[
'user_id' => $this->user->getId(),
'year' => $currentYear,
'month' => $currentMonth
],
__METHOD__
);
if ($logData) {
$signLog = json_decode($logData->sign_log, true);
if (!is_array($signLog)) {
$signLog = [];
}
$signLog[] = [
'date' => $currentDate,
'delta' => $pointDelta
];
$logData->sign_log = json_encode($signLog);
$dbw->update(
'isekai_user_daily_sign_log',
[
'sign_log' => $logData->sign_log
],
[
'user_id' => $this->user->getId(),
'year' => $currentYear,
'month' => $currentMonth
],
__METHOD__
);
} else {
$signLog = [[
'date' => $currentDate,
'delta' => $pointDelta
]];
$dbw->insert(
'isekai_user_daily_sign_log',
[
'user_id' => $this->user->getId(),
'year' => $currentYear,
'month' => $currentMonth,
'sign_log' => json_encode($signLog)
],
__METHOD__
);
}
}
}