改进 使用 Observer 代理 boot

This commit is contained in:
iVampireSP.com 2023-02-13 00:02:45 +08:00
parent 10f5d0f2ff
commit 7fa1ccf755
No known key found for this signature in database
GPG Key ID: 2F7B001CA27A8132
11 changed files with 290 additions and 248 deletions

View File

@ -2,8 +2,6 @@
namespace App\Models;
use App\Events\Users;
use App\Notifications\User\UserCharged;
use function auth;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Model;
@ -28,33 +26,6 @@ class Balance extends Model
'amount' => 'decimal:2',
];
protected static function boot()
{
parent::boot();
static::creating(function (self $balance) {
// $balance->remaining_amount = $balance->amount;
$balance->remaining_amount = 0;
$balance->order_id = date('YmdHis').$balance->id.rand(1000, 9999);
});
static::created(function (self $balance) {
broadcast(new Users($balance->user, 'balance.created', $balance));
});
static::updated(function (self $balance) {
if ($balance->isDirty('paid_at')) {
if ($balance->paid_at) {
$balance->notify(new UserCharged());
broadcast(new Users($balance->user, 'balance.updated', $balance));
$balance->user->charge($balance->amount, $balance->payment, $balance->order_id);
}
}
});
}
public function user(): BelongsToAlias
{
return $this->belongsTo(User::class);

View File

@ -5,7 +5,6 @@
use App\Events\Users;
use App\Jobs\Host\HostJob;
use App\Jobs\Host\UpdateOrDeleteHostJob;
use App\Notifications\WebNotification;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
@ -36,82 +35,6 @@ class Host extends Model
'managed_price' => 'decimal:2',
];
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->hour_at = now()->hour;
$model->minute_at = now()->minute;
if ($model->price !== null) {
$model->price = bcdiv($model->price, 1, 2);
}
if ($model->managed_price !== null) {
$model->managed_price = bcdiv($model->managed_price, 1, 2);
}
});
static::created(function (self $model) {
$model->load('module');
// model price 使用 bcmul 保留两位小数
$model->price = bcmul($model->price, 1, 2);
$model->user->notify(new WebNotification($model, 'hosts.created'));
});
static::updating(function (self $model) {
if ($model->isDirty('status')) {
if ($model->status == 'suspended') {
$model->suspended_at = now();
} else {
$model->suspended_at = null;
}
if ($model->status == 'locked') {
$model->locked_at = now();
} else {
$model->locked_at = null;
}
if ($model->status == 'unavailable') {
$model->unavailable_at = now();
} else {
$model->unavailable_at = null;
}
}
// 调度任务
if ($model->status !== 'unavailable') {
dispatch(new HostJob($model, 'patch'));
}
broadcast(new Users($model->user_id, 'hosts.updating', $model));
});
// when Updated
static::updated(function ($model) {
broadcast(new Users($model->user_id, 'hosts.updated', $model));
});
//
// static::deleting(function ($model) {
// broadcast(new Users($model->user_id, 'hosts.deleting', $model));
// });
static::deleting(function ($model) {
Cache::forget('user_tasks_'.$model->user_id);
});
static::deleted(function ($model) {
broadcast(new Users($model->user_id, 'hosts.deleted', $model));
Cache::forget('user_tasks_'.$model->user_id);
Cache::forget('user_hosts_'.$model->user_id);
});
}
/** @noinspection PhpUndefinedMethodInspection */
public function getUserHosts($user_id = null): array|Collection
{

View File

@ -14,7 +14,6 @@
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use JetBrains\PhpStorm\ArrayShape;
class Module extends Authenticatable
@ -46,33 +45,6 @@ class Module extends Authenticatable
'balance' => 'decimal:4',
];
protected static function boot()
{
parent::boot();
static::creating(function (self $model) {
if (! app()->environment('local')) {
$model->api_token = Str::random(60);
}
// 如果设置了 url 并且结尾有 / 则去掉
if ($model->url) {
$model->url = rtrim($model->url, '/');
}
});
static::updating(function (self $model) {
// 如果结尾有 / 则去掉
$model->url = rtrim($model->url, '/');
});
}
// public function moduleHostFunctions($host_id, $func, $requests): array
// {
// $http = Http::module($this->api_token, $this->url);
// $response = $http->post("hosts/{$host_id}/functions/" . $func, $requests);
//
// return $this->getResponse($response);
// }
// post, get, patch, delete 等请求
public function remote($func, $requests): array
{

View File

@ -2,13 +2,8 @@
namespace App\Models;
use App\Events\Users;
use App\Exceptions\CommonException;
use function auth;
use function broadcast;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Ramsey\Uuid\Uuid;
class Task extends Model
{
@ -30,64 +25,6 @@ class Task extends Model
// key type string
protected $keyType = 'string';
protected static function boot()
{
parent::boot();
static::creating(function (self $model) {
// id 为 uuid
$model->id = Uuid::uuid4()->toString();
// 如果是模块创建的任务
if (auth('module')->check()) {
$model->module_id = auth('module')->id();
}
// host_id 和 user_id 至少存在一个
if (! $model->host_id && ! $model->user_id) {
throw new CommonException('host_id 和 user_id 至少存在一个');
}
// if host_id
if ($model->host_id) {
$model->load('host');
if ($model->host === null) {
throw new CommonException('host_id 不存在');
}
$model->user_id = $model->host->user_id;
}
});
// created
static::created(function (self $model) {
$model->load('host');
broadcast(new Users($model->user_id, 'tasks.created', $model));
});
// updating
static::updating(function (self $model) {
if ($model->progress == 100) {
$model->status = 'done';
}
});
// updated and delete
static::updated(function (self $model) {
$model->load('host');
broadcast(new Users($model->user_id, 'tasks.updated', $model));
});
static::deleted(function (self $model) {
broadcast(new Users($model->user_id, 'tasks.deleted', $model));
});
}
// public function scopeUser($query)
// {
// return $query->where('user_id', auth()->id());
// }
public function host(): BelongsTo
{
return $this->belongsTo(Host::class);

View File

@ -3,7 +3,6 @@
namespace App\Models;
use App\Exceptions\User\BalanceNotEnoughException;
use Carbon\Exceptions\InvalidFormatException;
use GeneaLabs\LaravelModelCaching\CachedBuilder;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
@ -21,7 +20,6 @@
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable implements MustVerifyEmail
@ -77,55 +75,6 @@ class User extends Authenticatable implements MustVerifyEmail
'birthday_at',
];
protected static function boot()
{
parent::boot();
static::creating(function (self $user) {
$user->email_md5 = md5($user->email);
$user->uuid = Str::uuid();
});
static::updating(function (self $user) {
if ($user->isDirty('banned_at')) {
if ($user->banned_at) {
$user->tokens()->delete();
$user->hosts()->update(['status' => 'suspended', 'suspended_at' => now()]);
} else {
$user->hosts()->update(['status' => 'stopped']);
}
}
if ($user->isDirty('email')) {
$user->email_md5 = md5($user->email);
}
if ($user->isDirty('id_card')) {
$user->id_card = Crypt::encryptString($user->id_card);
}
if ($user->isDirty('id_card') || $user->isDirty('real_name')) {
if (empty($user->id_card) || empty($user->real_name)) {
$user->real_name_verified_at = null;
} else {
$user->real_name_verified_at = now();
// 更新生日
// try {
// $user->birthday_at = $user->getBirthdayFromIdCard();
// } catch (InvalidFormatException) {
// $user->birthday_at = null;
// }
}
}
});
static::deleting(function (self $user) {
$user->tokens()->delete();
$user->hosts()->update(['status' => 'suspended', 'suspended_at' => now()]);
});
}
public function hosts(): HasMany
{
return $this->hasMany(Host::class);

View File

@ -0,0 +1,34 @@
<?php
namespace App\Observers;
use App\Events\Users;
use App\Models\Balance;
use App\Notifications\User\UserCharged;
class BalanceObserver
{
public function creating(Balance $balance): void
{
$balance->remaining_amount = 0;
$balance->order_id = date('YmdHis').'-'.$balance->id.'-'.$balance->user_id.'-'.rand(1000, 9999);
}
public function created(Balance $balance): void
{
broadcast(new Users($balance->user, 'balance.created', $balance));
}
public function updated(Balance $balance): void
{
if ($balance->isDirty('paid_at')) {
if ($balance->paid_at) {
$balance->notify(new UserCharged());
broadcast(new Users($balance->user, 'balance.updated', $balance));
$balance->user->charge($balance->amount, $balance->payment, $balance->order_id);
}
}
}
}

View File

@ -0,0 +1,93 @@
<?php
namespace App\Observers;
use App\Events\Users;
use App\Jobs\Host\HostJob;
use App\Models\Host;
use App\Notifications\WebNotification;
class HostObserver
{
public function creating(Host $host): void
{
$host->hour_at = now()->hour;
$host->minute_at = now()->minute;
if ($host->price !== null) {
$host->price = bcdiv($host->price, 1, 2);
}
if ($host->managed_price !== null) {
$host->managed_price = bcdiv($host->managed_price, 1, 2);
}
}
/**
* Handle the Host "created" event.
*
* @param Host $host
* @return void
*/
public function created(Host $host): void
{
$host->load('module');
// model price 使用 bcmul 保留两位小数
$host->price = bcmul($host->price, 1, 2);
$host->user->notify(new WebNotification($host, 'hosts.created'));
}
/**
* Handle the Host "updated" event.
*
* @param Host $host
* @return void
*/
public function updating(Host $host): void
{
if ($host->isDirty('status')) {
if ($host->status == 'suspended') {
$host->suspended_at = now();
} else {
$host->suspended_at = null;
}
if ($host->status == 'locked') {
$host->locked_at = now();
} else {
$host->locked_at = null;
}
if ($host->status == 'unavailable') {
$host->unavailable_at = now();
} else {
$host->unavailable_at = null;
}
}
// 调度任务
if ($host->status !== 'unavailable') {
dispatch(new HostJob($host, 'patch'));
}
broadcast(new Users($host->user_id, 'hosts.updating', $host));
}
public function updated(Host $host): void
{
broadcast(new Users($host->user_id, 'hosts.updated', $host));
}
/**
* Handle the Host "deleted" event.
*
* @param Host $host
* @return void
*/
public function deleted(Host $host): void
{
broadcast(new Users($host->user_id, 'hosts.deleted', $host));
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Observers;
use App\Models\Module;
use Illuminate\Support\Str;
class ModuleObserver
{
public function creating(Module $module): void
{
if (! app()->environment('local')) {
$module->api_token = Str::random(60);
}
// 如果设置了 url 并且结尾有 / 则去掉
if ($module->url) {
$module->url = rtrim($module->url, '/');
}
}
public function updating(Module $module): void
{
$module->url = rtrim($module->url, '/');
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Observers;
use App\Events\Users;
use App\Exceptions\CommonException;
use App\Models\Task;
use Ramsey\Uuid\Uuid;
class TaskObserver
{
/**
* @throws CommonException
*/
public function creating(Task $task): void
{
// id 为 uuid
$task->id = Uuid::uuid4()->toString();
// 如果是模块创建的任务
if (auth('module')->check()) {
$task->module_id = auth('module')->id();
}
// host_id 和 user_id 至少存在一个
if (! $task->host_id && ! $task->user_id) {
throw new CommonException('host_id 和 user_id 至少存在一个');
}
// if host_id
if ($task->host_id) {
$task->load('host');
if ($task->host === null) {
throw new CommonException('host_id 不存在');
}
$task->user_id = $task->host->user_id;
}
}
public function created(Task $task): void
{
$task->load('host');
broadcast(new Users($task->user_id, 'tasks.created', $task));
}
// updating
public function updating(Task $task): void
{
if ($task->progress == 100) {
$task->status = 'done';
}
}
public function updated(Task $task): void
{
$task->load('host');
broadcast(new Users($task->user_id, 'tasks.updated', $task));
}
public function deleted(Task $task): void
{
broadcast(new Users($task->user_id, 'tasks.deleted', $task));
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Observers;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
class UserObserver
{
public function creating(User $user): void
{
$user->email_md5 = md5($user->email);
$user->uuid = Str::uuid();
}
public function updating(User $user): void
{
if ($user->isDirty('banned_at')) {
if ($user->banned_at) {
$user->tokens()->delete();
$user->hosts()->update(['status' => 'suspended', 'suspended_at' => now()]);
} else {
$user->hosts()->update(['status' => 'stopped']);
}
}
if ($user->isDirty('email')) {
$user->email_md5 = md5($user->email);
}
if ($user->isDirty('id_card')) {
$user->id_card = Crypt::encryptString($user->id_card);
}
if ($user->isDirty('id_card') || $user->isDirty('real_name')) {
if (empty($user->id_card) || empty($user->real_name)) {
$user->real_name_verified_at = null;
} else {
$user->real_name_verified_at = now();
}
}
}
public function deleting(User $user): void
{
$user->tokens()->delete();
$user->hosts()->update(['status' => 'suspended', 'suspended_at' => now()]);
}
}

View File

@ -2,7 +2,17 @@
namespace App\Providers;
use App\Models\Balance;
use App\Models\Host;
use App\Models\Module;
use App\Models\PersonalAccessToken;
use App\Models\Task;
use App\Models\User;
use App\Observers\BalanceObserver;
use App\Observers\HostObserver;
use App\Observers\ModuleObserver;
use App\Observers\TaskObserver;
use App\Observers\UserObserver;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\ServiceProvider;
@ -43,5 +53,16 @@ public function boot(): void
});
// Carbon::setTestNow(now()->addDays(1));
$this->registerObservers();
}
private function registerObservers(): void
{
User::observe(UserObserver::class);
Host::observe(HostObserver::class);
Task::observe(TaskObserver::class);
Module::observe(ModuleObserver::class);
Balance::observe(BalanceObserver::class);
}
}