Please give your honest review about my service class. This class only called from model observer, wrapped within database transaction and handle
- creating and deleting user activities
- deleting notifications related to activities
| Model |
Type |
Softdelete |
| UserActivity |
Polymorphic |
✔️ |
| Notification |
Polymorphic |
❌ |
Trying to consolidate it with dedicated class but dont know where to start, which part should be refactor.
class ActivityService
{
/**
* Gets the points to reach the max level.
*/
private function pointsToMaxLevel(int $userId, int $activityPoints): int
{
$userPoints = (int) UserActivity::query()
->withTrashed()
->where('user_id', $userId)
->sum('reward');
$remaining = max(0, Level::MAX_POINTS - $userPoints);
return min($activityPoints, $remaining);
}
/**
* Create post activity.
*/
public function createPostActivity(Post $post): void
{
$points = $this->pointsToMaxLevel($post->user_id, Level::POST_POINTS);
$post->activity()->createQuietly([
'user_id' => $post->user_id,
'type' => UserActivity::CREATE_POST,
'reward' => $points,
]);
}
/**
* Create comment activity.
*/
public function createCommentActivity(Comment $comment): void
{
$points = $this->pointsToMaxLevel($comment->user_id, Level::COMMENT_POINTS);
$comment->activity()->createQuietly([
'user_id' => $comment->user_id,
'type' => UserActivity::COMMENT_POST,
'reward' => $points,
]);
}
/**
* Create or update like post activity.
*/
public function createLikePostActivity(PostLike $like): void
{
$this->toggleActivity($like, UserActivity::LIKE_POST, Level::LIKE_POINTS);
}
/**
* Create or update like comment activity.
*/
public function createLikeCommentActivity(CommentLike $like): void
{
$this->toggleActivity($like, UserActivity::LIKE_COMMENT, Level::LIKE_POINTS);
}
/**
* Create or update bookmark activity.
*/
public function createBookmarkActivity(Bookmark $bookmark): void
{
$this->toggleActivity($bookmark, UserActivity::BOOKMARK_POST, Level::BOOKMARK_POINTS);
}
/**
* Create or update toggleable activity.
*/
private function toggleActivity(ToggleableActivity $action, string $type, int $point): void
{
$points = $this->pointsToMaxLevel($action->user_id, $point);
UserActivity::withoutEvents(fn () => $action->activity()
->withTrashed()
->updateOrCreate(
[
'user_id' => $action->user_id,
],
[
'type' => $type,
'reward' => $points,
'deleted_at' => null,
'created_at' => now(),
'updated_at' => now(),
]
));
}
/**
* Deletes all activities associated with a post.
*/
public function deletePostActivities(Post $post): void
{
// delete activity and notifications related to post
tap($post, $this->deletePostNotifications(...))->activity()->delete();
// delete bookmark activities related to post
$this->deleteBookmarkActivitiesUsing(
$post->bookmarks()->select('id')
);
// delete like activities related to post
$this->deleteLikePostActivitiesUsing(
$post->likes()->select('id')
);
// delete comment activities related to post
$this->deleteCommentActivitiesUsing(
$post->comments()->select('id')
);
// delete like activities related to post's comments
$this->deleteLikeCommentActivitiesUsing(
$post->likesOnComments()->select('id')
);
}
/**
* Deletes all activities associated with comment(s).
*/
public function deleteCommentActivities(Comment $comment): void
{
// delete activities and notifications related to comment
tap($comment, $this->deleteCommentNotifications(...))->activity()->delete();
// delete like activities related to comment
$this->deleteLikeCommentActivitiesUsing(
$comment->likes()->select('id')
);
// delete reply activities related to comment
$this->deleteCommentActivitiesUsing(
$comment->replies()->select('id')
);
// delete like activities and notifications related to comment's replies
$likesOnRepliesQuery = $comment->likesOnReplies()->select('id');
$this->deleteLikeCommentActivitiesUsing($likesOnRepliesQuery);
$this->deleteLikeCommentNotificationsUsing($likesOnRepliesQuery);
}
/**
* Deletes all activities associated with post like(s).
*/
public function deleteLikePostActivity(PostLike $like): void
{
tap($like, $this->deleteLikePostNotification(...))->activity()->delete();
}
/**
* Deletes all activities associated with comment like(s).
*/
public function deleteLikeCommentActivity(CommentLike $like): void
{
tap($like, $this->deleteLikeCommentNotification(...))->activity()->delete();
}
/**
* Deletes all activities associated with a user.
*/
public function deleteUserActivities(User $user): void
{
// delete user's notifications while deleting notifications related to user.
tap($user, $this->deleteUserNotifications(...))->notifications()->delete();
// delete notifications related to user's posts
$this->deletePostNotificationsUsing(
$user->posts()->select('id')
);
// delete like activities related to user's posts
$this->deleteLikePostActivitiesUsing(
$user->likesOnPosts()->select('id')
);
// delete bookmark activities related to user's posts
$this->deleteBookmarkActivitiesUsing(
$user->bookmarksOnPosts()->select('id')
);
// delete activities related to comments on user's posts
$this->deleteCommentActivitiesUsing(
$user->commentsOnPosts()->select('id')
);
// delete like activities related to comments on user's posts
$this->deleteLikeCommentActivitiesUsing(
$user->likesOnPostComments()->select('id')
);
// delete like activities related to user's comments
$this->deleteLikeCommentActivitiesUsing(
$user->likesOnComments()->select('id')
);
// delete activities related to user's mentions
$this->deleteCommentActivitiesUsing(
$user->mentions()->select('id')
);
// delete like activities related to user's mentions
$this->deleteLikeCommentActivitiesUsing(
$user->likesOnMentions()->select('id')
);
// delete activities and notifications related to replies on user's comments
$repliesOnCommentsQuery = $user->repliesOnComments()->select('id');
$this->deleteCommentActivitiesUsing($repliesOnCommentsQuery);
$this->deleteCommentNotificationsUsing($repliesOnCommentsQuery);
// delete like activities related to replies on user's comments
$this->deleteLikeCommentActivitiesUsing(
$user->likesOnReplies()->select('id')
);
}
/**
* Deletes all activities associated with comment(s) using subquery.
*/
private function deleteCommentActivitiesUsing(Builder $query): void
{
$this->deleteActivitiesUsingClass($query, Comment::class);
}
/**
* Deletes all activities associated with post like(s) using subquery.
*/
private function deleteLikePostActivitiesUsing(Builder $query): void
{
$this->deleteActivitiesUsingClass($query, PostLike::class);
}
/**
* Deletes all activities associated with comment like(s) using subquery.
*/
private function deleteLikeCommentActivitiesUsing(Builder $query): void
{
$this->deleteActivitiesUsingClass($query, CommentLike::class);
}
/**
* Deletes all activities associated with bookmark(s) using subquery.
*/
private function deleteBookmarkActivitiesUsing(Builder $query): void
{
$this->deleteActivitiesUsingClass($query, Bookmark::class);
}
/**
* Delete post notifications.
*/
private function deletePostNotifications(Post $post): void
{
$this->deleteNotificationsUsingKey($post->id, Notification::KEY_POST);
}
/**
* Delete post notifications using subquery.
*/
private function deletePostNotificationsUsing(Builder $query): void
{
$this->deleteNotificationsUsingKey($query, Notification::KEY_POST);
}
/**
* Delete comment notifications.
*/
private function deleteCommentNotifications(Comment $comment): void
{
$this->deleteNotificationsUsingKey($comment->id, Notification::KEY_COMMENT);
$this->deleteNotificationsUsingKey($comment->id, Notification::KEY_REPLY);
}
/**
* Delete comment notifications using subquery.
*/
private function deleteCommentNotificationsUsing(Builder $query): void
{
$this->deleteNotificationsUsingKey($query, Notification::KEY_COMMENT);
$this->deleteNotificationsUsingKey($query, Notification::KEY_REPLY);
}
/**
* Delete like post notifications.
*/
private function deleteLikePostNotification(PostLike $like): void
{
$this->deleteNotificationsUsingKey($like->id, Notification::KEY_POST_LIKE);
}
/**
* Delete like comment notifications.
*/
private function deleteLikeCommentNotification(CommentLike $like): void
{
$this->deleteNotificationsUsingKey($like->id, Notification::KEY_COMMENT_LIKE);
}
/**
* Delete like comment notifications using subquery.
*/
private function deleteLikeCommentNotificationsUsing(Builder $query): void
{
$this->deleteNotificationsUsingKey($query, Notification::KEY_COMMENT_LIKE);
}
/**
* Delete user notifications.
*/
private function deleteUserNotifications(User $user): void
{
$this->deleteNotificationsUsingKey($user->id, Notification::KEY_USER);
$this->deleteNotificationsUsingKey($user->id, Notification::KEY_MENTION);
}
/**
* Deletes all activities associated with a model using subquery.
*/
private function deleteActivitiesUsingClass(Builder $query, string $class): void
{
UserActivity::query()
->whereMorphedTo('subject', $class)
->whereIn('subject_id', $query)
->delete();
}
/**
* Deletes all notifications associated with a key.
*/
private function deleteNotificationsUsingKey(Builder|int $value, string $key): void
{
$method = $value instanceof Builder ? 'whereIn' : 'where';
Notification::query()
->{$method}("data->$key", $value)
->delete();
}
}