Changeset View
Changeset View
Standalone View
Standalone View
src/app/Observers/UserObserver.php
<?php | <?php | ||||
namespace App\Observers; | namespace App\Observers; | ||||
use App\Entitlement; | use App\Entitlement; | ||||
use App\Domain; | use App\Domain; | ||||
use App\Transaction; | |||||
use App\User; | use App\User; | ||||
use App\Wallet; | |||||
use Illuminate\Support\Facades\DB; | use Illuminate\Support\Facades\DB; | ||||
class UserObserver | class UserObserver | ||||
{ | { | ||||
/** | /** | ||||
* Handle the "creating" event. | * Handle the "creating" event. | ||||
* | * | ||||
* Ensure that the user is created with a random, large integer. | * Ensure that the user is created with a random, large integer. | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | class UserObserver | ||||
* Handle the "deleting" event. | * Handle the "deleting" event. | ||||
* | * | ||||
* @param User $user The user that is being deleted. | * @param User $user The user that is being deleted. | ||||
* | * | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
public function deleting(User $user) | public function deleting(User $user) | ||||
{ | { | ||||
if ($user->isForceDeleting()) { | |||||
$this->forceDeleting($user); | |||||
return; | |||||
} | |||||
// TODO: Especially in tests we're doing delete() on a already deleted user. | // TODO: Especially in tests we're doing delete() on a already deleted user. | ||||
// Should we escape here - for performance reasons? | // Should we escape here - for performance reasons? | ||||
// TODO: I think all of this should use database transactions | // TODO: I think all of this should use database transactions | ||||
// Entitlements do not have referential integrity on the entitled object, so this is our | // Entitlements do not have referential integrity on the entitled object, so this is our | ||||
// way of doing an onDelete('cascade') without the foreign key. | // way of doing an onDelete('cascade') without the foreign key. | ||||
$entitlements = Entitlement::where('entitleable_id', $user->id) | $entitlements = Entitlement::where('entitleable_id', $user->id) | ||||
->where('entitleable_type', User::class)->get(); | ->where('entitleable_type', User::class)->get(); | ||||
Show All 17 Lines | public function deleting(User $user) | ||||
} else { | } else { | ||||
$entitlements[] = $entitlement->id; | $entitlements[] = $entitlement->id; | ||||
} | } | ||||
} | } | ||||
$users = array_unique($users); | $users = array_unique($users); | ||||
$domains = array_unique($domains); | $domains = array_unique($domains); | ||||
// Note: Domains/users need to be deleted one by one to make sure | // Domains/users/entitlements need to be deleted one by one to make sure | ||||
// events are fired and observers can do the proper cleanup. | // events are fired and observers can do the proper cleanup. | ||||
// Entitlements have no delete event handlers as for now. | |||||
if (!empty($users)) { | if (!empty($users)) { | ||||
foreach (User::whereIn('id', $users)->get() as $_user) { | foreach (User::whereIn('id', $users)->get() as $_user) { | ||||
$_user->delete(); | $_user->delete(); | ||||
} | } | ||||
} | } | ||||
if (!empty($domains)) { | if (!empty($domains)) { | ||||
foreach (Domain::whereIn('id', $domains)->get() as $_domain) { | foreach (Domain::whereIn('id', $domains)->get() as $_domain) { | ||||
$_domain->delete(); | $_domain->delete(); | ||||
} | } | ||||
} | } | ||||
if (!empty($entitlements)) { | if (!empty($entitlements)) { | ||||
Entitlement::whereIn('id', $entitlements)->delete(); | Entitlement::whereIn('id', $entitlements)->delete(); | ||||
} | } | ||||
// FIXME: What do we do with user wallets? | // FIXME: What do we do with user wallets? | ||||
\App\Jobs\UserDelete::dispatch($user->id); | \App\Jobs\UserDelete::dispatch($user->id); | ||||
} | } | ||||
/** | /** | ||||
* Handle the "deleting" event on forceDelete() call. | |||||
* | |||||
* @param User $user The user that is being deleted. | |||||
* | |||||
* @return void | |||||
*/ | |||||
public function forceDeleting(User $user) | |||||
{ | |||||
// TODO: We assume that at this moment all belongings are already soft-deleted. | |||||
// Remove owned users/domains | |||||
$wallets = $user->wallets()->pluck('id')->all(); | |||||
$assignments = Entitlement::withTrashed()->whereIn('wallet_id', $wallets)->get(); | |||||
$entitlements = []; | |||||
$domains = []; | |||||
$users = []; | |||||
foreach ($assignments as $entitlement) { | |||||
$entitlements[] = $entitlement->id; | |||||
if ($entitlement->entitleable_type == Domain::class) { | |||||
$domains[] = $entitlement->entitleable_id; | |||||
} elseif ( | |||||
$entitlement->entitleable_type == User::class | |||||
&& $entitlement->entitleable_id != $user->id | |||||
) { | |||||
$users[] = $entitlement->entitleable_id; | |||||
} | |||||
} | |||||
$users = array_unique($users); | |||||
$domains = array_unique($domains); | |||||
// Remove the user "direct" entitlements explicitely, if they belong to another | |||||
// user's wallet they will not be removed by the wallets foreign key cascade | |||||
Entitlement::withTrashed() | |||||
->where('entitleable_id', $user->id) | |||||
->where('entitleable_type', User::class) | |||||
->forceDelete(); | |||||
// Users need to be deleted one by one to make sure observers can do the proper cleanup. | |||||
if (!empty($users)) { | |||||
foreach (User::withTrashed()->whereIn('id', $users)->get() as $_user) { | |||||
$_user->forceDelete(); | |||||
} | |||||
} | |||||
// Domains can be just removed | |||||
if (!empty($domains)) { | |||||
Domain::withTrashed()->whereIn('id', $domains)->forceDelete(); | |||||
} | |||||
// Remove transactions, they also have no foreign key constraint | |||||
Transaction::where('object_type', Entitlement::class) | |||||
->whereIn('object_id', $entitlements) | |||||
->delete(); | |||||
Transaction::where('object_type', Wallet::class) | |||||
->whereIn('object_id', $wallets) | |||||
->delete(); | |||||
} | |||||
/** | |||||
* Handle the "retrieving" event. | * Handle the "retrieving" event. | ||||
* | * | ||||
* @param User $user The user that is being retrieved. | * @param User $user The user that is being retrieved. | ||||
* | * | ||||
* @todo This is useful for audit. | * @todo This is useful for audit. | ||||
* | * | ||||
* @return void | * @return void | ||||
*/ | */ | ||||
Show All 17 Lines |