luceos Following your suggestion, i started using my own database table. Thanks.
SychO I've been working on this for 2 weeks, but I still haven't been able to connect getSubjectModel to my NotificationHub model.
I get an error like "InvalidArgumentException: Flarum\Api\Serializer\UserSerializer can only serialize instances of Flarum\User\User".
I would be very grateful if you could check it. I'm trying to get the extension ready to be published tomorrow. The codes are still very messy. I hope you can help solve this problem.
Blueprint
<?php
namespace huseyinfiliz\notificationhub\Notification;
use Flarum\Notification\Blueprint\BlueprintInterface;
use Flarum\User\User;
use Illuminate\Support\Str;
use huseyinfiliz\notificationhub\Model\NotificationHub;
class CustomNotificationBlueprint implements BlueprintInterface
{
protected string $message;
protected ?User $fromUser;
protected string $notificationType;
protected string $subjectId;
protected string $url;
protected string $icon;
public function __construct(
string $message,
?User $fromUser = null,
string $notificationType = 'default',
string $subjectId = '1',
string $url = '#',
string $icon = 'fas fa-bell'
) {
$this->message = $message;
$this->fromUser = $fromUser;
$this->notificationType = $notificationType;
$this->subjectId = $subjectId;
$this->url = $url;
$this->icon = $icon;
}
public function getFromUser()
{
return $this->fromUser ?: null;
}
public function getSubject()
{
return NotificationHub::find((int) $this->subjectId);
}
public function getData()
{
$notificationHub = NotificationHub::find($this->subjectId);
$excerptText = $notificationHub ? $notificationHub->excerpt_key : null;
return [
'message' => $this->message,
'excerpt' => $excerptText,
'url' => $this->url,
'icon' => $this->icon,
'unique' => (string) Str::orderedUuid(),
];
}
public static function getType()
{
return 'customNotification';
}
public static function getSubjectModel()
{
return NotificationHub::class;
}
}
Serializer
<?php
namespace huseyinfiliz\notificationhub\Serializers;
use Flarum\Api\Serializer\AbstractSerializer;
use huseyinfiliz\notificationhub\Model\NotificationHub;
class NotificationTypeSerializer extends AbstractSerializer
{
protected $type = 'notification_types';
protected function getDefaultAttributes($model): array
{
return [
'id' => $model->id,
'name' => $model->name,
//'excerpt_key' => $model->excerpt_key,
'default_url' => $model->default_url,
'default_icon' => $model->default_icon,
'default_message_key' => $model->default_message_key,
'is_active' => $model->is_active,
//'sort_order' => $model->sort_order,
//'description' => $model->description,
//'permission' => $model->permission,
//'color' => $model->color,
//'default_recipients' => $model->default_recipients,
//'createdAt' => $this->formatDate($model->created_at),
//'updatedAt' => $this->formatDate($model->updated_at),
];
}
}
Controller
<?php
namespace huseyinfiliz\notificationhub\Controllers;
use Flarum\Foundation\ValidationException;
use Flarum\Http\RequestUtil;
use Flarum\User\UserRepository;
use Flarum\User\User;
use Flarum\Notification\NotificationSyncer;
use Illuminate\Contracts\Translation\Translator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use huseyinfiliz\notificationhub\Notification\CustomNotificationBlueprint;
use Flarum\Group\Group;
class SendNotificationController implements RequestHandlerInterface
{
public function __construct(
protected UserRepository $users,
protected NotificationSyncer $notificationSyncer
) {
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
$actor = RequestUtil::getActor($request);
$data = (array) $request->getParsedBody();
$groupIds = Arr::get($data, 'groupIds', []);
$userIds = Arr::get($data, 'userIds', []);
error_log("SendNotificationController: Received groupIds: " . json_encode($groupIds));
error_log("SendNotificationController: Received userIds: " . json_encode($userIds));
// İzin kontrolü
if (count($groupIds) > 0) {
$actor->assertCan('huseyinfiliz-notificationhub.send-all');
} else {
$actor->assertCan('huseyinfiliz-notificationhub.send-user');
}
$messageText = (string)Arr::get($data, 'message');
$fromUserId = Arr::get($data, 'fromUserId');
$subjectId = Arr::get($data, 'subjectId', '1');
$url = (string)Arr::get($data, 'url', '#');
$icon = (string)Arr::get($data, 'icon', 'fas fa-bell');
if (!$messageText) {
/** @var Translator $translator */
$translator = resolve(Translator::class);
throw new ValidationException(['message' => [$translator->get('huseyinfiliz-notificationhub.api.message_required')]]);
}
if (empty($userIds) && empty($groupIds)) {
/** @var Translator $translator */
$translator = resolve(Translator::class);
throw new ValidationException(['userIds' => [$translator->get('huseyinfiliz-notificationhub.api.user_ids_required')]]);
}
// Gönderen kullanıcıyı belirleme
$fromUser = $fromUserId ? User::find($fromUserId) : $actor;
$recipientCount = 0;
$allUserIds = []; // Initializing `$allUserIds` as an empty array.
$hasMemberGroup = in_array(Group::MEMBER_ID, $groupIds); // Defined the hasMemberGroup before.
if($userIds && count($userIds)){
$allUserIds = [...$userIds]; // Add the direct users first.
}
if(isset($groupIds) && count($groupIds)){
$userQuery = $this->users->query();
if(!$hasMemberGroup){ // If we don't have the member group then fetch by groups as before.
$userQuery->whereHas('groups', function (Builder $query) use ($groupIds) {
$query->whereIn('id', $groupIds);
});
error_log("SendNotificationController: Query after group IDs applied:" . $userQuery->toSql());
$userQuery->chunk(50, function ($users) use (&$allUserIds) {
foreach ($users as $user) {
$allUserIds[] = $user->id;
}
});
}
else {
// If member group is present then skip the `whereHas` and fetch all users
error_log("SendNotificationController: Fetching all users since the Member group is present");
$this->users->query()->chunk(50, function ($users) use(&$allUserIds){
foreach ($users as $user){
$allUserIds[] = $user->id;
}
});
}
}
$allUserIds = array_unique($allUserIds); // Remove duplicates
error_log("SendNotificationController: Final user ids before sending:". json_encode($allUserIds)); // log before sending notifications
foreach ($allUserIds as $userId) {
$user = User::find($userId);
if ($user) {
$blueprint = new CustomNotificationBlueprint(
$messageText,
$fromUser,
'custom_admin_notification',
$subjectId,
$url,
$icon
);
$this->notificationSyncer->sync($blueprint, [$user]);
$recipientCount++;
}
}
if ($recipientCount === 0) {
/** @var Translator $translator */
$translator = resolve(Translator::class);
throw new ValidationException(['userIds' => [$translator->get('huseyinfiliz-notificationhub.api.no_valid_recipients')]]);
}
return new JsonResponse([
'message' => $messageText,
'recipientCount' => $recipientCount,
'status' => 'OK'
]);
}
}