synergixe / php-beamzer
This is a library that provides support for real-time feeds and notifications for PHP web applications
Fund package maintenance!
Patreon
Requires
- php: >=5.6.4
- igorw/event-source: ~1.0
- illuminate/console: ^5.4
- illuminate/database: ^5.4
- illuminate/notifications: ^5.4
- illuminate/queue: ^5.4
- illuminate/redis: ^5.4
- illuminate/support: ^5.4
- nesbot/carbon: ^1.22
- symfony/http-foundation: ^3.3 || ^4.1
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.5
- mockery/mockery: ^1.0
- orchestra/testbench: ^3.4
- phpunit/phpunit: ^5.7 || ^7.0
This package is not auto-updated.
Last update: 2024-11-12 10:49:54 UTC
README
This is a library that adds cross-browser support for real-time feeds and notifications to PHP web applications in an easy way (using Server-Sent Events (SSE) only). It currently supports Laravel version 5.4, 5.5, 5.6 and 5.7 only.
How to Use
Load Up the package from Composer
$ composer require synergixe/php-beamzer:^0.1
"require": { "synergixe/php-beamzer": "^0.1" }
Publish the config for the package to the Laravel config folder
php artisan vendor:publish --provider="Synergixe\Beamzer\Providers\Laravel\BeamzerServiceProvider"
This will create the package's config file called beamzer.php
in the config
directory of your Laravel Project. These are the contents of the published config file:
return [ /* |-------------------------------------------------------------------------- | The timeout value for when Beamzer should stop trying tofetch data (milliseconds) |-------------------------------------------------------------------------- */ 'ping' => env('BEAMZER_PING_TIMEOUT', '3000'), /* |-------------------------------------------------------------------------- | To support IE 8/9 or not when sending data back to the client. |-------------------------------------------------------------------------- */ 'support_old_ie' => TRUE, /* |-------------------------------------------------------------------------- | Number of times before the client should retry an SSE connection. |-------------------------------------------------------------------------- */ 'retry_limit_count' => 10, /* |-------------------------------------------------------------------------- | To use or not to use Redis. |-------------------------------------------------------------------------- */ 'use_redis' => FALSE, /* |-------------------------------------------------------------------------- | redis publish channel name. |-------------------------------------------------------------------------- */ 'redis_pub_channel' => 'notifications', /* |-------------------------------------------------------------------------- | The size of data sent back to the client per connection. |-------------------------------------------------------------------------- */ 'data_chunks_size' => 5 ];
Create the event listener to be used with the nofication custom event using the custom command provided by the package
php artisan create:notificationfile
Then create your Laravel Controllers
php artisan make:controller EventSourceController php artisan make:controller MessageController
Create the Laravel Notifications Database Table
php artisan notifications:table php artisan migrate
Register the route for returning your stream notifications and for create notifications
/* In routes/web.php */ Route::get('/users/notifications', 'EventSourceController@getNotifications'); Route::post('/notify/subjects/{kind}', 'MessageController@fireNotificationEvent'); Route::patch('/user/notifications/update/{nid}', 'EventSourceController@updateNotificationsAsRead');
Update the app config for service provider and alias classes
If you use Laravel 5.5 and above don't bother doing this as it is included automatically
/* In app/config/app.php */ 'providers' => [ ... Synergixe\PHPBeamzer\Providers\Laravel\BeamzerServiceProvider::class ], 'alias' => [ ... 'Streamer' => Synergixe\PHPBeamzer\Facades\Laravel\Streamer::class ]
Setup the Controller for read notifications from the DB and return it to PHPBeamzer
/* In app/Http/Controllers/EventSourceController.php */ use Synergixe\PHPBeamzer\Beamzer as Beamzer; class EventSourceController extends Controller { public function __construct(){ // code goes here... } public function pullNotificationData(Request $request, $user){ if(!isset($user)){ return array(); } $last_id = $request->input('lastEventId'); if(is_null($last_id)){ return $user->unreadNotifications->take(10)->get(); }else{ return $user->unreadNotifications->where('created_at', '>', $last_id) ->take(10)->get(); } } public function deleteAllUnreadNotifications(Request $request){ $user = \Auth::user(); $user->unreadNotifications()->delete(); return response()->json(array('status' => 'ok')); } public function countAllUnreadNotifications(Request $request){ $user = \Auth::user(); $count = $user->unreadNotifications()->groupBy('notifiable_type')->count(); return response()->json(array('count' => $count)); } /* The $nid variable is the notification id sent via AJAX (as a PATCH request) to update the status of the notification to "read" */ public function updateNotificationsAsRead(Request $request, $nid){ $user = \Auth::user(); $user->unReadNotifications() ->where('id', $nid) ->update(['read_at' => date('Y-m-d H:i:s')]); if($request->expectsJson()) return response()->json(array('status' => 'ok')); else return response('okay', 200); } /* The {Beamzer} object in injected into the controller method as a dependency. */ public function getNotifications(Request $request, Beamzer $streamer){ $user = \Auth::user(); $response = $streamer->setup(array( 'as_event' => 'activity', // event name to listen for on the client-side 'exec_limit' => 3000, // number of milliseconds allowed for streamer to collect data and send to the browser 'as_cors' => TRUE // For Cross Origin requests ))->send( array( 'data_source_callback' => array(&$this, 'pullNotificationData'), // function/method to return notification data as array 'data_source_callback_args' => array( 'args' => array($request, $user) // arguments to the `data_source_callback` method/function ) ) ); return $response; }
Setup the EventServiceProvider to Configure Laravel events for Creating Notifications
/* In app/Providers/EventServiceProvider */ class EventServiceProvider extends ServiceProvider { /** * The event listener mappings for the application. * * @var array */ protected $listen = [ 'Synergixe\PHPBeamzer\Events\NotificableEvent' => [ 'App\Listeners\NotificableEventListener' ], ]; }
Setup Controller to fire Event when something happens within your Application
/* In app/Http/Controllers/MessageController.php */ use Illuminate\Http\Request; use Synergixe\PHPBeamzer\Events\NotificableEvent as NotificableEvent; class MessageController extends Controller { public function __construct(){ // code goes here... } public function fireNotificationEvent(Request $request, $kind) { $event = null; switch($kind){ case "follows": $user = \Auth::user(); $followee = User::where('id', '=', $request->input('followee_id')); $follow = $user->follows()->attach([ $followee->id ]); $event = new NotificableEvent( $user, $followee ); break; } if(! is_null($event)){ $event->setKind($kind); event($event); } } }
Add the Modifier Traits (Actionable, Describable) to the Subject of your Notifications
/* In app/User.php */ use Synergixe\PHPBeamzer\Modifiers\Actionable as Actionable; use Synergixe\PHPBeamzer\Modifiers\Describable as Describable; class User extends Eloquent { use Notifiable, Actionable, Describable; /* create the `actionsPerfomed` property for trait { Actionable } */ protected $actionsPerfomed = array( "follows" => 'asked to follow you' ); public function routeNotificationForMail(){ return $this->email_address; } public function follows(){ // relation for all `follows` return $this->belongsToMany(User::class, 'social_network_follows', 'followee_id', 'follower_id', 'id', 'id', 'follows' )->withTimestamps(); } public function followers(){ // relation for all `followers` return $this->belongsToMany(User::class, 'social_network_follows', 'follower_id', 'followee_id', 'id', 'id', 'followers' )->withTimestamps(); } /* create the `makeDescription` method for trait { Describable } */ public function makeDecription(){ /* This can be used to describe the subject/object each time on the client-side in your notifications list when rendered in HTML */ return array( 'name' => ($this->last_name . " " . $this->first_name), 'id' => $this->id ); } }
Modify the generated NotificableEventListener to include your own code in the handle method
/*In app/Listeners/NotificableEventListener.php */ use Synergixe\PHPBeamzer\Notifications\ActivityStreamNotification as ActivityStreamNotification; use Synergixe\PHPBeamzer\Events\NotificableEvent as NotificableEvent; class NotificableEventListener implements ShouldQueue { use InteractsWithQueue; public function __construct(){ // code goes here... } public function handle(NotificableEvent $event){ $event->__wakeup(); $event_kind = $event->getKind(); /* The below code assumes that the {User} model has a relationship called {followers} -> e.g. could be followers of a user on a social platform. So, all followers are notified using beamzers' custom notification {ActivityStreamNotification} with an action of 'asked to follow'. */ switch($event_kind){ case "follows": $event->reciever->notify( new ActivityStreamNotification( $event->producer, $event->reciever, $event->timestamp, $event_kind ) )->delay( \Carbon::now()->addMinutes(5); ); break; } } public function failed(NotificableEvent $event, $exception){ // code goes here... } }
On the client-side, setup beamzer-client JS libary like so
<script src="path/to/beamzer-client.min.js"></script> <script type="text/javascript"> var beam = new BeamzerClient({ source:"http://localhost:4001/users/notifications", params:{ id:"9UmxjXuu8yjI@jws8468#3" }, options:{loggingEnabled:true, interval:2500} }); beam.start(function onOpen(e){ console.log("SSE connection established!"); }, onfunction onError(e){ console.log("error: ", e); }, function onMessage(e){ console.log("message id: ", e.lastEventId); console.log("message data: ", e.data); }); beam.on("activity", function(e){ console.log("event id: ", e.lastEventId); console.log("even data: ", e.data); }); </script>
License
MIT
Requirement
- PHP 5.6.4 +
- Redis Server (Optional)
Support
It isn't absolutely necessary but you can use this library with its front end component library called beamzer-client. This front end library support the follwoing browsers:
- IE 9.0+
- FF 4.0+
- Opera 10.5+
- Chrome 4.0+
- Safari 7.0+
Contributing
You can contribute to this project by setting up a DOCS section or sending in a PR. report bugs and feature requests to the issue tracker