Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

theUnforgiven's avatar

Notifications System

I have a table setup:

CREATE TABLE `notifications` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `dismissed` int(1) DEFAULT NULL,
  `name` text COLLATE utf8_unicode_ci NOT NULL,
  `importance` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Then I call Notifications::all(); from my controller to get all notifications. But this isn't showing to every user, the user_id column is only used to update the post that a user a read the notification.

I do have a loop too.

 @foreach ($notifications as $notification)
        <div class="notifications">
            @if ($notification->importance == 'High' && $notification->user_id == Auth::id() && $notification->dismissed != 1)
                <div class="notify danger">
                    <button type="button" class="close del-banner-btn" data-notify-id="High" name="close" data-banner-id="1" data-user-id="{!! Auth::id() !!}">&times;</button>
                    {!! $notification->name !!}
                </div>
            @endif
        </div>
@endforeach

But ideally every notification needs to be notified to all users, then not displayed when the user clicks a X and the table is updated. Not sure I've gone about this the right way so asking for some help advice on this...

0 likes
74 replies
mstnorris's avatar

@lstables what is the relationship then between Users and Notifications?

The reason why others can't see the notifications is because of your if statement. By the looks of things it is behaving exactly as described. But probably not as you wish.

@if ($notification->importance == 'High' && $notification->user_id == Auth::id() && $notification->dismissed != 1) // you are checking that the User ID is equal to the currently authenticated user.

If you want to see which users have seen which notifications then you will need a many-to-many relationship between them.

Sorry if I misunderstood your question as I'm sure you knew that but just checking.

1 like
theUnforgiven's avatar

Right ok removed that check, so now shows to everyone, but now how would I update the user_id column when everyone clicks the X button?

I did get some help earlier for some JS like so:

$(document).ready(function () {
        $('.del-banner-btn').click(function () {
            var banner_id = $(this).data('banner-id');
            var user_id = $(this).data('user-id');
            var notify = $(this).data('notify-id')

            $.ajaxSetup({
                headers: {
                    'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
                }
            });
            $.ajax({
                method: 'POST',
                url: '/updateNotifications',
                data: {
                    'banner_id' : banner_id,
                    'user_id' : user_id,
                    'notify' : notify
                }
            });
            console.log();
            $('.notify').slideUp(250);
        });
    });

Which then points to the method:

public function updateNotifications(Request $request)
    {
        $input = $request->all();
        $notify = Notification::where('user_id', $input['user_id'])->where('importance', $input['notify'])->first();
        $notify->dismissed = $input['banner_id'];
        $notify->update();

        return redirect()->back();
    }
mstnorris's avatar

Well at the moment, there is only one user_id.

As I mentioned above, to know which users have seen which notifications you'll need a many-to-many relationship set up.

jekinney's avatar

I utilize a pivot table that detaches a user when a notification is read.

Pivot table usually looks like user_id notification_id. On larger apps it may not scale well.

theUnforgiven's avatar

So can you help me get this right with the many to many relationship then?

mstnorris's avatar
Level 55

User model

public function notifications() {
    return $this->belongsToMany('App\Notification'); // amend to your namespace
}

Notification model

public function users() {
    return $this->belongsToMany('App\User'); // amend to your namespace
}

notification_user table

Add the following to a new migration

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateRoleUserTable extends Migration {

    public function up()
    {
        Schema::create('notification_user', function(Blueprint $table)
        {
            $table->engine = 'InnoDB';
            $table->increments('id');
            $table->integer('notification_id')->unsigned()->index();
            $table->foreign('notification_id')->references('id')->on('notifications')->onDelete('cascade');
            $table->integer('user_id')->unsigned()->index();
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::drop('notification_user');
    }

}
2 likes
theUnforgiven's avatar

So in my notifications model I could do:

public function user()
    {
        return $this->belongsToMany('CRM\User');
    }

then in my User model do something:

public function notifications()
    {
        return $this->hasMany('CRM\Notifications');
    }

Then how would the code work I currently have or what should I change?

theUnforgiven's avatar

Looks you posted same time as me, so I got it wrong slightly. But still don't understand how this is going to work and what table and column will need to be updated.

jekinney's avatar

Nope, both need to be belongsToMany. And default table needs to be notification_user.

theUnforgiven's avatar

So within the notification_user table i would just need id columns for both notifications and user? so 2 columns effectively?

mstnorris's avatar

Yeah, you may want to keep the id and timestamps, but apart from that you won't need anything else. You can add extra attributes if you needed to, but they are not necessary.

mstnorris's avatar

@lstables I have updated the migration file above, so you can copy/paste that into a new migration file.

theUnforgiven's avatar

Already done the migration, but now the method to update this one:

public function updateNotifications(Request $request)
    {
        $input = $request->all();
        $notify = Notification::where('user_id', $input['user_id'])->first();
        $notify->dismissed = $input['banner_id'];
        $notify->update();

        return redirect()->back();
    }

Do i need it? Or what does it need amending to?

mstnorris's avatar

You can do

Notification::find(1)->users()->attach(User::find(1));

Or similar, depending on how you get the Notification or User.

mstnorris's avatar

That's just an example

Or similar, depending on how you get the Notification or User.

However you get the user:

Notification::find(1)->users()->attach(Auth::user()->id);
theUnforgiven's avatar

So do something like?

 $id = Auth::id();
Notification::find($id)->users()->attach(User::find($id));

but how will it know to update the notification has been read by a specific user?

mstnorris's avatar

That's exactly what it does.

You find the appropriate Notification and the appropriate user and you assign them. This is saved in the pivot table.

The below is a sample of what your tables would look like. You have three users and three notifications.

Users table

| id | name | email            |
|----|------|------------------|
| 1  | Mike | mike@exmaple.com |
| 2  | Lee  | lee@example.com  |
| 3  | John | john@example.com |

Notification table

| id | notification_title | notification_date   |
|----|--------------------|---------------------|
| 1  | First              | 2015-05-13 18:40:00 |
| 2  | Second             | 2015-05-13 18:41:00 |
| 3  | Third              | 2015-05-13 18:42:00 |

Below, it shows that Notification with ID 1 was seen by Users with IDs 1 & 2 and Notification with ID 2 was seen by User with ID 1.

Notification_User table

| id | notification_id | user_id |
|----|-----------------|---------|
| 1  | 1               | 1       |
| 2  | 2               | 1       |
| 3  | 1               | 2       |
theUnforgiven's avatar

Ok so just tried this in the browser and get Call to a member function users() on null

theUnforgiven's avatar

updated to this:

Notification::find($input['banner_id'])->users()->attach(User::find($id));

the $input['banner_id'] comes from the ajax call, so i;m presuming this is right but still getting Call to a member function users() on null

mstnorris's avatar

So it can't find a Notification with an ID of 1. Are you sure there is one?

theUnforgiven's avatar

Yes a notification with id of 1 is there now i get

Call to undefined method Illuminate\Database\Query\Builder::users()

mstnorris's avatar

On your Notification model have you set up the appropriate relationship? The code you posted earlier said user() instead of users()

theUnforgiven's avatar

Yes I think

 public function user()
    {
        return $this->belongsToMany('App\User');
    }
Next

Please or to participate in this conversation.