├── .github
└── FUNDING.yml
├── .stubs.php
├── 3x1io-tomato-fcm.md
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── SECURITY.md
├── arts
└── 3x1io-tomato-fcm.jpg
├── composer.json
├── config
├── .gitkeep
└── filament-fcm.php
├── database
└── migrations
│ ├── .gitkeep
│ └── 2022_05_29_032309_create_user_has_notifications_table.php
├── resources
└── views
│ ├── .gitkeep
│ ├── firebase-base.blade.php
│ └── firebase.blade.php
├── src
├── Console
│ ├── .gitkeep
│ └── FilamentFcmInstall.php
├── FilamentFcmPlugin.php
├── FilamentFcmServiceProvider.php
├── Http
│ ├── Controllers
│ │ └── .gitkeep
│ ├── Middleware
│ │ └── .gitkeep
│ └── Requests
│ │ └── .gitkeep
├── Jobs
│ └── NotifyFCMJob.php
├── Livewire
│ └── Firebase.php
├── Models
│ ├── .gitkeep
│ └── UserToken.php
├── Notifications
│ └── FCMNotificationService.php
└── Traits
│ └── InteractsWithFCM.php
├── stubs
└── firebase.stub
└── tests
├── Feature
└── .gitkeep
└── Unit
└── .gitkeep
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [3x1io]
2 |
--------------------------------------------------------------------------------
/.stubs.php:
--------------------------------------------------------------------------------
1 | plugin(\TomatoPHP\FilamentFcm\FilamentFcmPlugin::make()
56 | )
57 | ```
58 |
59 | ## Usage
60 |
61 | you can use the filament native notification and we add some macro for you
62 |
63 | ```php
64 | use Filament\Notifications\Notification;
65 |
66 | Notification::make('send')
67 | ->title('Test Notifications')
68 | ->body('This is a test notification')
69 | ->icon('heroicon-o-bell')
70 | ->color('success')
71 | ->actions([
72 | \Filament\Notifications\Actions\Action::make('view')
73 | ->label('View')
74 | ->url('https://google.com')
75 | ->markAsRead()
76 | ])
77 | ->sendToFCM(
78 | user: auth()->user(),
79 | data: [
80 | 'key' => 'value'
81 | ],
82 | sendToDatabase: false,
83 | type: 'fcm-web' // or fcm-api
84 | )
85 | ```
86 |
87 | or you can send it directly from the user model
88 |
89 | ```php
90 |
91 | $user->notifyFCMSDK(
92 | message: $this->message,
93 | type: $this->provider,
94 | title: $this->title,
95 | url: $this->url,
96 | image: $this->image,
97 | icon: $this->icon,
98 | data: [
99 | 'url' => $this->url,
100 | 'id' => $this->model_id,
101 | 'actions' => [],
102 | 'body' => $this->message,
103 | 'color' => null,
104 | 'duration' => null,
105 | 'icon' => $this->icon,
106 | 'iconColor' => null,
107 | 'status' => null,
108 | 'title' => $this->title,
109 | 'view' => null,
110 | 'viewData' => null,
111 | 'data'=> $this->data
112 | ],
113 | sendToDatabase: false
114 | );
115 |
116 | ```
117 | ## Publish Assets
118 |
119 | you can publish config file by use this command
120 |
121 | ```bash
122 | php artisan vendor:publish --tag="filament-fcm-config"
123 | ```
124 |
125 | you can publish views file by use this command
126 |
127 | ```bash
128 | php artisan vendor:publish --tag="filament-fcm-views"
129 | ```
130 |
131 |
132 | you can publish migrations file by use this command
133 |
134 | ```bash
135 | php artisan vendor:publish --tag="filament-fcm-migrations"
136 | ```
137 |
138 | ## Other Filament Packages
139 |
140 | Checkout our [Awesome TomatoPHP](https://github.com/tomatophp/awesome)
141 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/SECURITY.md
--------------------------------------------------------------------------------
/arts/3x1io-tomato-fcm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/arts/3x1io-tomato-fcm.jpg
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tomatophp/filament-fcm",
3 | "type": "library",
4 | "description": "Firebase Cloud Messaging integration to Native FilamentPHP Notification Package",
5 | "keywords": [
6 | "php",
7 | "laravel",
8 | "firebase",
9 | "google-firebase",
10 | "filamentphp",
11 | "integration",
12 | "filament-notifications"
13 | ],
14 | "license": "MIT",
15 | "autoload": {
16 | "psr-4": {
17 | "TomatoPHP\\FilamentFcm\\": "src/"
18 | }
19 | },
20 | "autoload-dev": {
21 | "psr-4": {
22 | "Tests\\": "tests/"
23 | }
24 | },
25 | "extra": {
26 | "laravel": {
27 | "providers": [
28 | "TomatoPHP\\FilamentFcm\\FilamentFcmServiceProvider"
29 | ]
30 | }
31 | },
32 | "authors": [
33 | {
34 | "name": "Fady Mondy",
35 | "email": "info@3x1.io"
36 | }
37 | ],
38 | "require": {
39 | "php": "^8.1|^8.2",
40 | "filament/filament": "^3.0.0",
41 | "filament/notifications": "^3.0.0",
42 | "tomatophp/console-helpers": "^1.1",
43 | "tomatophp/fcm-notifications": "^1.0",
44 | "mobiledetect/mobiledetectlib": "^4.8"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/config/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/config/.gitkeep
--------------------------------------------------------------------------------
/config/filament-fcm.php:
--------------------------------------------------------------------------------
1 | [
11 | "apiKey"=> env("FIREBASE_API_KEY"),
12 | "authDomain"=> env("FIREBASE_AUTH_DOMAIN"),
13 | "databaseURL"=> env("FIREBASE_DATABASE_URL"),
14 | "projectId"=> env("FIREBASE_PROJECT_ID"),
15 | "storageBucket"=> env("FIREBASE_STORAGE_BUCKET"),
16 | "messagingSenderId"=> env("FIREBASE_MESSAGING_SENDER_ID"),
17 | "appId"=> env("FIREBASE_APP_ID"),
18 | "measurementId" => env("FIREBASE_MEASUREMENT_ID"),
19 | ],
20 |
21 | /*
22 | * ---------------------------------------------------------------
23 | * Firebase Cloud Messaging Configuration
24 | * ---------------------------------------------------------------
25 | *
26 | */
27 | "vapid" => env("FIREBASE_VAPID"),
28 |
29 | /*
30 | * ---------------------------------------------------------------
31 | * Firebase Alert Sound when notification received
32 | * ---------------------------------------------------------------
33 | *
34 | */
35 | "alert" => [
36 | "sound" => env("FCM_ALERT_SOUND"),
37 | ]
38 | ];
39 |
--------------------------------------------------------------------------------
/database/migrations/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/database/migrations/.gitkeep
--------------------------------------------------------------------------------
/database/migrations/2022_05_29_032309_create_user_has_notifications_table.php:
--------------------------------------------------------------------------------
1 | id();
18 |
19 | //If Selected Record On the model
20 | $table->string('model_type');
21 | $table->unsignedBigInteger('model_id');
22 |
23 | $table->string('provider')->default('fcm-web')->nullable();
24 | $table->string('provider_token')->nullable();
25 |
26 | $table->timestamps();
27 | });
28 | }
29 |
30 | /**
31 | * Reverse the migrations.
32 | *
33 | * @return void
34 | */
35 | public function down()
36 | {
37 | Schema::dropIfExists('user_has_notifications');
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/resources/views/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/resources/views/.gitkeep
--------------------------------------------------------------------------------
/resources/views/firebase-base.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
54 |
--------------------------------------------------------------------------------
/resources/views/firebase.blade.php:
--------------------------------------------------------------------------------
1 | @livewire(\TomatoPHP\FilamentFcm\Livewire\Firebase::class)
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Console/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/src/Console/.gitkeep
--------------------------------------------------------------------------------
/src/Console/FilamentFcmInstall.php:
--------------------------------------------------------------------------------
1 | info('Install FCM Worker');
42 | $this->generateStubs(
43 | __DIR__ . '/../../stubs/firebase.stub',
44 | public_path('firebase-messaging-sw.js'),
45 | [
46 | 'apiKey' => config('filament-fcm.project.apiKey'),
47 | 'authDomain' => config('filament-fcm.project.authDomain'),
48 | 'databaseURL' => config('filament-fcm.project.databaseURL'),
49 | 'projectId' => config('filament-fcm.project.projectId'),
50 | 'storageBucket' => config('filament-fcm.project.storageBucket'),
51 | 'messagingSenderId' => config('filament-fcm.project.messagingSenderId'),
52 | 'appId' => config('filament-fcm.project.appId'),
53 | 'measurementId' => config('filament-fcm.project.measurementId'),
54 | 'sound' => config('filament-fcm.alert.sound') ? "var audio = new Audio('".config('filament-fcm.alert.sound')."');\n audio.play();": null
55 | ]
56 | );
57 | $this->info('Filament Alerts FCM installed successfully.');
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/FilamentFcmPlugin.php:
--------------------------------------------------------------------------------
1 | env('FIREBASE_CREDENTIALS', public_path('storage/' . setting('fcm_cr'))),
41 | 'database' => [
42 | 'url' => env('FIREBASE_DATABASE_URL', setting('fcm_database_url')),
43 | ]
44 | ]);
45 |
46 | } catch (\Exception $e) {
47 | \Log::error($e);
48 | }
49 |
50 | FilamentView::registerRenderHook(
51 | PanelsRenderHook::BODY_END,
52 | function (){
53 | return view('filament-fcm::firebase');
54 | },
55 | );
56 | }
57 |
58 | public static function make(): static
59 | {
60 | return new static();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/FilamentFcmServiceProvider.php:
--------------------------------------------------------------------------------
1 | commands([
20 | \TomatoPHP\FilamentFcm\Console\FilamentFcmInstall::class,
21 | ]);
22 |
23 | //Register Config file
24 | $this->mergeConfigFrom(__DIR__.'/../config/filament-fcm.php', 'filament-fcm');
25 |
26 | //Publish Config
27 | $this->publishes([
28 | __DIR__.'/../config/filament-fcm.php' => config_path('filament-fcm.php'),
29 | ], 'filament-fcm-config');
30 |
31 | //Register Migrations
32 | $this->loadMigrationsFrom(__DIR__.'/../database/migrations');
33 |
34 | //Publish Migrations
35 | $this->publishes([
36 | __DIR__.'/../database/migrations' => database_path('migrations'),
37 | ], 'filament-fcm-migrations');
38 |
39 | //Register views
40 | $this->loadViewsFrom(__DIR__.'/../resources/views', 'filament-fcm');
41 |
42 | //Publish Views
43 | $this->publishes([
44 | __DIR__.'/../resources/views' => resource_path('views/vendor/filament-fcm'),
45 | ], 'filament-fcm-views');
46 |
47 | Livewire::component(Firebase::class);
48 | }
49 |
50 | public function boot(): void
51 | {
52 |
53 | Notification::macro('sendToFCM', function (Model $user, array $data=[], ?bool $sendToDatabase=true, ?string $type ='fcm-web'): static
54 | {
55 | /** @var Notification $this */
56 | $user->notifyFCMSDK(
57 | title: $this->title,
58 | message: $this->body,
59 | type: $type,
60 | url: count($this->actions)? $this->actions[0]->getUrl() : null,
61 | icon: $this->icon,
62 | data: [
63 | 'url' => count($this->actions)? $this->actions[0]->getUrl() : null,
64 | 'id' => $this->getId(),
65 | 'actions' => array_map(fn (Action | ActionGroup $action): array => $action->toArray(), $this->getActions()),
66 | 'body' => $this->getBody(),
67 | 'color' => $this->getColor(),
68 | 'duration' => $this->getDuration(),
69 | 'icon' => $this->getIcon(),
70 | 'iconColor' => $this->getIconColor(),
71 | 'status' => $this->getStatus(),
72 | 'title' => $this->getTitle(),
73 | 'view' => $this->getView(),
74 | 'viewData' => $this->getViewData(),
75 | 'data'=> $data
76 | ],
77 | sendToDatabase: $sendToDatabase
78 | );
79 |
80 | return $this;
81 | });
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Http/Controllers/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/src/Http/Controllers/.gitkeep
--------------------------------------------------------------------------------
/src/Http/Middleware/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/src/Http/Middleware/.gitkeep
--------------------------------------------------------------------------------
/src/Http/Requests/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/src/Http/Requests/.gitkeep
--------------------------------------------------------------------------------
/src/Jobs/NotifyFCMJob.php:
--------------------------------------------------------------------------------
1 | user = $arrgs['user'];
40 | $this->title = $arrgs['title'];
41 | $this->message = $arrgs['message'];
42 | $this->icon = $arrgs['icon'];
43 | $this->url = $arrgs['url'];
44 | $this->image = $arrgs['image'];
45 | $this->type = $arrgs['type'];
46 | $this->data = $arrgs['data'];
47 | $this->sendToDatabase = $arrgs['sendToDatabase'];
48 | }
49 |
50 | /**
51 | * Execute the job.
52 | *
53 | * @return void
54 | */
55 | public function handle()
56 | {
57 | $this->user->setFCM($this->type)->notify(new FCMNotificationService(
58 | $this->message,
59 | $this->type,
60 | $this->title,
61 | $this->icon,
62 | $this->image,
63 | $this->url,
64 | $this->data,
65 | $this->sendToDatabase,
66 | ));
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Livewire/Firebase.php:
--------------------------------------------------------------------------------
1 | user()){
18 | $user = auth()->user();
19 | $getToken = $user->setFCM($detect->isMobile() ? 'fcm-api' :'fcm-web')->userTokensFcm()->where('provider', $detect->isMobile() ? 'fcm-api' :'fcm-web')->first();
20 | if($getToken){
21 | $getToken->provider_token = $token;
22 | $getToken->save();
23 | }
24 | else {
25 | $user->setFCM($detect->isMobile() ? 'fcm-api' :'fcm-web')->userTokensFcm()->create([
26 | 'provider' => $detect->isMobile() ? 'fcm-api' :'fcm-web',
27 | 'provider_token' => $token
28 | ]);
29 | }
30 | }
31 | }
32 |
33 | #[On('fcm-notification')]
34 | public function fcmNotification(mixed $data)
35 | {
36 | $actions = [];
37 | if(isset($data['data'])){
38 | if(isset($data['data']['actions']) && is_object(json_decode($data['data']['actions']))){
39 | foreach (json_decode($data['data']['actions']) as $action){
40 | $actions[] = Action::make($action->name)
41 | ->color($action->color)
42 | ->eventData($action->eventData)
43 | ->icon($action->icon)
44 | ->iconPosition($action->iconPosition)
45 | ->iconSize($action->iconSize)
46 | ->outlined($action->isOutlined)
47 | ->disabled($action->isDisabled)
48 | ->label($action->label)
49 | ->url($action->url)
50 | ->close($action->shouldClose)
51 | ->size($action->size)
52 | ->tooltip($action->tooltip)
53 | ->view($action->view)
54 | ->markAsUnread($action->shouldMarkAsUnRead??false)
55 | ->markAsRead($action->shouldMarkAsRead??false);
56 | }
57 | }
58 | }
59 |
60 | if(isset($data['data']['sendToDatabase']) && $data['data']['sendToDatabase'] === true){
61 | Notification::make($data['data']['id'])
62 | ->title($data['data']['title'])
63 | ->actions($actions)
64 | ->body($data['data']['body'])
65 | ->icon($data['data']['icon'])
66 | ->iconColor($data['data']['iconColor'])
67 | ->color($data['data']['color'])
68 | ->duration($data['data']['duration'])
69 | ->send()
70 | ->sendToDatabase(auth()->user());
71 | }
72 | else {
73 | Notification::make($data['data']['id'])
74 | ->title($data['data']['title'])
75 | ->actions($actions)
76 | ->body($data['data']['body'])
77 | ->icon($data['data']['icon'])
78 | ->iconColor($data['data']['iconColor'])
79 | ->color($data['data']['color'])
80 | ->duration($data['data']['duration'])
81 | ->send();
82 | }
83 | }
84 |
85 | public function render()
86 | {
87 | return view('filament-fcm::firebase-base');
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Models/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/src/Models/.gitkeep
--------------------------------------------------------------------------------
/src/Models/UserToken.php:
--------------------------------------------------------------------------------
1 | title,
46 | body: $this->message,
47 | image: $this->image ?? null
48 | ),
49 | data: [
50 | 'id' => $this->data['id'],
51 | 'actions' => json_encode($this->data['actions']),
52 | 'body' => $this->data['body'],
53 | 'color' => $this->data['color'],
54 | 'duration' => $this->data['duration'],
55 | 'icon' => $this->data['icon'],
56 | 'iconColor' => $this->data['iconColor'],
57 | 'status' => $this->data['status'],
58 | 'title' => $this->data['title'],
59 | 'view' => $this->data['view'],
60 | 'viewData' => json_encode($this->data['viewData']),
61 | 'data' => json_encode($this->data['data']),
62 | 'sendToDatabase' =>$this->sendToDatabase
63 | ],
64 | custom: [
65 | 'android' => [
66 | 'notification' => [
67 | 'color' => '#0A0A0A',
68 | ],
69 | 'fcm_options' => [
70 | 'analytics_label' => 'analytics',
71 | ],
72 | ],
73 | 'apns' => [
74 | 'fcm_options' => [
75 | 'analytics_label' => 'analytics',
76 | ],
77 | ],
78 | ]
79 | )
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Traits/InteractsWithFCM.php:
--------------------------------------------------------------------------------
1 | $this,
27 | 'title' => $title,
28 | 'message' => $message,
29 | 'icon' => $icon,
30 | 'image' => $image,
31 | 'url' => $url,
32 | 'type' => $type,
33 | 'data' => $data,
34 | 'sendToDatabase' => $sendToDatabase,
35 | ]));
36 | }
37 |
38 | public function initializeUseNotifications()
39 | {
40 | $this->appends[] = 'fcm';
41 | $this->appends[] = 'fcmID';
42 | }
43 |
44 | public function setFcmAttribute($value)
45 | {
46 | $this->fcm = $value;
47 | }
48 |
49 | public function getFcmAttribute()
50 | {
51 | return 'fcm-web';
52 | }
53 |
54 | public function setFcmIdAttribute($value)
55 | {
56 | $this->fcmId = $value;
57 | }
58 |
59 | public function getFcmIdAttribute()
60 | {
61 | return $this->id;
62 | }
63 |
64 | public function setFCM(?string $type='fcm-web'): static
65 | {
66 | $this->fcm = $type;
67 | $this->fcmId = $this->id;
68 | return $this;
69 | }
70 |
71 | public function userTokensFcm()
72 | {
73 | return $this->morphOne(UserToken::class, 'model')->where('provider', $this->fcm);
74 | }
75 |
76 | public function routeNotificationForFcm()
77 | {
78 | return $this->userTokensFcm ? $this->userTokensFcm->provider_token : '';
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/stubs/firebase.stub:
--------------------------------------------------------------------------------
1 | // Give the service worker access to Firebase Messaging.
2 | // Note that you can only use Firebase Messaging here. Other Firebase libraries
3 | // are not available in the service worker.
4 | importScripts('https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js');
5 | importScripts('https://www.gstatic.com/firebasejs/8.10.1/firebase-messaging.js');
6 |
7 | try
8 | {
9 | // Initialize the Firebase app in the service worker by passing in
10 | // your app's Firebase config object.
11 | // https://firebase.google.com/docs/web/setup#config-object
12 | firebase.initializeApp({
13 | apiKey: "{{ apiKey }}",
14 | authDomain: "{{ authDomain }}",
15 | databaseURL: "{{ databaseURL }}",
16 | projectId: "{{ projectId }}",
17 | storageBucket: "{{ storageBucket }}",
18 | messagingSenderId: "{{ messagingSenderId }}",
19 | appId: "{{ appId }}",
20 | measurementId: "{{ measurementId }}"
21 | });
22 |
23 |
24 | // Retrieve an instance of Firebase Messaging so that it can handle background
25 | // messages.
26 | const messaging = firebase.messaging();
27 |
28 | messaging.onBackgroundMessage((payload) => {
29 | //
30 | {{ sound }}
31 |
32 | let options = {
33 | body: "",
34 | icon: "",
35 | image: "",
36 | tag: "alert",
37 | };
38 |
39 | if(payload.data.body){
40 | options.body = payload.data.body;
41 | }
42 |
43 | if(payload.data.image){
44 | options.icon = payload.data.image;
45 | }
46 |
47 | let notification = self.registration.showNotification(
48 | payload.data.title,
49 | options
50 | );
51 |
52 | if(payload.data.url){
53 | // link to page on clicking the notification
54 | notification.onclick = (payload) => {
55 | window.open(payload.data.url);
56 | };
57 | }
58 | });
59 | }
60 | catch(e) {
61 | console.log(e)
62 | }
63 |
--------------------------------------------------------------------------------
/tests/Feature/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/tests/Feature/.gitkeep
--------------------------------------------------------------------------------
/tests/Unit/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomatophp/filament-fcm/d0b78888e4590d47265517b0518c27b4b3bbcbe3/tests/Unit/.gitkeep
--------------------------------------------------------------------------------