├── tests ├── .gitkeep ├── Team.php ├── User.php ├── DbTestCase.php └── FeedTest.php ├── .gitignore ├── src ├── Contracts │ ├── Notifiable.php │ ├── Notification.php │ ├── NotifiableGroup.php │ ├── PushFeed.php │ ├── PullFeed.php │ └── Store.php ├── Exceptions │ └── NotNotifiableException.php ├── Facades │ └── Feed.php ├── Store │ ├── Eloquent │ │ ├── Notifiable.php │ │ └── Notification.php │ └── Manager.php ├── helpers.php ├── Events │ ├── NotificationRead.php │ ├── NotificationUnread.php │ └── NotificationAdded.php ├── FeedServiceProvider.php └── Feed.php ├── .travis.yml ├── composer.json ├── config └── feed.php ├── migrations └── 2015_12_23_100000_create_notifications_table.php ├── LICENSE ├── phpunit.xml └── README.md /tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | composer.lock -------------------------------------------------------------------------------- /src/Contracts/Notifiable.php: -------------------------------------------------------------------------------- 1 | morphMany('Michaeljennings\Feed\Store\Eloquent\Notification', 'notifiable'); 15 | } 16 | } -------------------------------------------------------------------------------- /tests/Team.php: -------------------------------------------------------------------------------- 1 | pull($notifiable); 19 | } 20 | 21 | return $feed; 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /tests/User.php: -------------------------------------------------------------------------------- 1 | 1]; 19 | 20 | /** 21 | * Set the attributes available for mass assignment. 22 | * 23 | * @var array 24 | */ 25 | protected $fillable = ['id']; 26 | } -------------------------------------------------------------------------------- /src/Events/NotificationRead.php: -------------------------------------------------------------------------------- 1 | notification = $notification; 19 | } 20 | 21 | /** 22 | * Get the read notification. 23 | * 24 | * @return Notification 25 | */ 26 | public function getNotification() 27 | { 28 | return $this->notification; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Events/NotificationUnread.php: -------------------------------------------------------------------------------- 1 | notification = $notification; 19 | } 20 | 21 | /** 22 | * Get the read notification. 23 | * 24 | * @return Notification 25 | */ 26 | public function getNotification() 27 | { 28 | return $this->notification; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Store/Manager.php: -------------------------------------------------------------------------------- 1 | app['config']['feed']['drivers']['eloquent']['model']; 18 | } 19 | 20 | /** 21 | * Get the default driver name. 22 | * 23 | * @return string 24 | */ 25 | public function getDefaultDriver() 26 | { 27 | return $this->app['config']['feed']['driver']; 28 | } 29 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "michaeljennings/feed", 3 | "description": "A simple activity feed for laravel 5+", 4 | "keywords": ["laravel", "feed", "activity"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Michael Jennings", 9 | "email": "michael.jennings91@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "illuminate/database": "5.*" 14 | }, 15 | "autoload": { 16 | "psr-4": { 17 | "Michaeljennings\\Feed\\": "src/" 18 | }, 19 | "files": [ 20 | "src/helpers.php" 21 | ] 22 | }, 23 | "require-dev": { 24 | "mockery/mockery": "0.9.*", 25 | "satooshi/php-coveralls": "1.0.*", 26 | "orchestra/testbench": "^3.0" 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "Michaeljennings\\Feed\\Tests\\": "tests/" 31 | } 32 | }, 33 | "minimum-stability": "stable" 34 | } 35 | -------------------------------------------------------------------------------- /config/feed.php: -------------------------------------------------------------------------------- 1 | 'eloquent', 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Drivers 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Set any driver specific configuration options here. 24 | | 25 | */ 26 | 27 | 'drivers' => [ 28 | 'eloquent' => [ 29 | 'model' => 'Michaeljennings\Feed\Store\Eloquent\Notification', 30 | ], 31 | ] 32 | 33 | ]; -------------------------------------------------------------------------------- /migrations/2015_12_23_100000_create_notifications_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 17 | $table->string('notifiable_type'); 18 | $table->integer('notifiable_id')->unsigned(); 19 | $table->string('icon', 50)->nullable(); 20 | $table->string('body'); 21 | $table->boolean('read')->default(0); 22 | $table->timestamp('read_at')->nullable(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::drop('notifications'); 35 | } 36 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Michael Jennings 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/Events/NotificationAdded.php: -------------------------------------------------------------------------------- 1 | notifiable = $notifiable; 27 | $this->notification = $notification; 28 | } 29 | 30 | /** 31 | * Return the notifiable member. 32 | * 33 | * @return Notifiable 34 | */ 35 | public function getNotifiable() 36 | { 37 | return $this->notifiable; 38 | } 39 | 40 | /** 41 | * Return the notification that was added. 42 | * 43 | * @return Notification 44 | */ 45 | public function getNotification() 46 | { 47 | return $this->notification; 48 | } 49 | } -------------------------------------------------------------------------------- /src/Contracts/PushFeed.php: -------------------------------------------------------------------------------- 1 | artisan('migrate', ['--path' => '../../../../migrations']); 20 | } 21 | 22 | /** 23 | * Define environment setup. 24 | * 25 | * @param \Illuminate\Foundation\Application $app 26 | * @return void 27 | */ 28 | protected function getEnvironmentSetUp($app) 29 | { 30 | // Setup default database to use sqlite :memory: 31 | $app['config']->set('database.default', 'testbench'); 32 | $app['config']->set('database.connections.testbench', [ 33 | 'driver' => 'sqlite', 34 | 'database' => ':memory:', 35 | 'prefix' => '', 36 | ]); 37 | } 38 | 39 | /** 40 | * @inheritdoc 41 | */ 42 | protected function getPackageProviders($app) 43 | { 44 | return [ 45 | FeedServiceProvider::class, 46 | ]; 47 | } 48 | } -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests 15 | 16 | 17 | 18 | 19 | . 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ./src/ 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/FeedServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([__DIR__ . '/../migrations/' => database_path('migrations')], 'migrations'); 16 | $this->publishes([__DIR__ . '/../config/' => config_path()], 'config'); 17 | 18 | $this->mergeConfigFrom(__DIR__ . '/../config//feed.php', 'feed'); 19 | } 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | public function register() 25 | { 26 | $this->app->bind('feed.manager', function($app) { 27 | return new Manager($app); 28 | }); 29 | 30 | $this->app->bind('feed.store', function($app) { 31 | return $app['feed.manager']->driver(); 32 | }); 33 | 34 | $this->app->bind('feed', function($app) { 35 | return new Feed($app['feed.store']); 36 | }); 37 | 38 | $this->app->alias('feed.store', 'Michaeljennings\Feed\Contracts\Store'); 39 | $this->app->alias('feed', 'Michaeljennings\Feed\Contracts\PullFeed'); 40 | $this->app->alias('feed', 'Michaeljennings\Feed\Contracts\PushFeed'); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Contracts/PullFeed.php: -------------------------------------------------------------------------------- 1 | morphTo(); 76 | } 77 | 78 | /** 79 | * Get all of the unread notifications where their notifiable type 80 | * is in the array of types, and their notifiable id is in the 81 | * array of ids. 82 | * 83 | * @param array $types 84 | * @param array $ids 85 | * @param bool $read 86 | * @return \Michaeljennings\Feed\Contracts\Notification[] 87 | */ 88 | public function getNotifications(array $types, array $ids, $read = false) 89 | { 90 | $query = $this->whereIn('notifiable_type', $types) 91 | ->whereIn('notifiable_id', $ids) 92 | ->where('read', $read) 93 | ->orderBy($this->orderBy, $this->orderByDirection); 94 | 95 | if ($this->limit) { 96 | $query->limit($this->limit); 97 | } 98 | 99 | if ($this->offset) { 100 | $query->offset($this->offset); 101 | } 102 | 103 | foreach($this->filters as $filter) { 104 | $filter($query); 105 | } 106 | 107 | if ($this->paginate) { 108 | return $query->paginate($this->paginate); 109 | } 110 | 111 | return $query->get(); 112 | } 113 | 114 | /** 115 | * Add a limit to the query. 116 | * 117 | * @param int $limit 118 | * @return Store 119 | */ 120 | public function limit($limit) 121 | { 122 | $this->limit = $limit; 123 | 124 | return $this; 125 | } 126 | 127 | /** 128 | * Add an offset to the query. 129 | * 130 | * @param int $offset 131 | * @return Store 132 | */ 133 | public function offset($offset) 134 | { 135 | $this->offset = $offset; 136 | 137 | return $this; 138 | } 139 | 140 | /** 141 | * Set the amount to paginate the results by. 142 | * 143 | * @param int $perPage 144 | * @return $this 145 | */ 146 | public function paginateResults($perPage) 147 | { 148 | $this->paginate = $perPage; 149 | 150 | return $this; 151 | } 152 | 153 | /** 154 | * Add a filter to be called at run time. 155 | * 156 | * @param callable $filter 157 | * @return $this 158 | */ 159 | public function filter(callable $filter) 160 | { 161 | $this->filters[] = $filter; 162 | 163 | return $this; 164 | } 165 | 166 | /** 167 | * Order the results by the latest notification. 168 | * 169 | * @param string $column 170 | * @return $this 171 | */ 172 | public function latest($column = 'created_at') 173 | { 174 | $this->orderBy = $column; 175 | $this->orderByDirection = 'desc'; 176 | 177 | return $this; 178 | } 179 | 180 | /** 181 | * Order the results by the oldest notification. 182 | * 183 | * @param string $column 184 | * @return $this 185 | */ 186 | public function oldest($column = 'created_at') 187 | { 188 | $this->orderBy = $column; 189 | $this->orderByDirection = 'asc'; 190 | 191 | return $this; 192 | } 193 | 194 | /** 195 | * Mark the provided notification as read. 196 | * 197 | * @param array|NotificationContract[] $notifications 198 | * @return NotificationContract[] 199 | */ 200 | public function markAsRead(array $notifications) 201 | { 202 | $ids = $this->getIds($notifications); 203 | 204 | $this->whereIn($this->getKeyName(), $ids)->update(['read' => true, 'read_at' => new Carbon()]); 205 | 206 | return $this->whereIn($this->getKeyName(), $ids)->get()->all(); 207 | } 208 | 209 | /** 210 | * Mark the provided notification as unread. 211 | * 212 | * @param array|NotificationContract[] $notifications 213 | * @return NotificationContract[] 214 | */ 215 | public function markAsUnread(array $notifications) 216 | { 217 | $ids = $this->getIds($notifications); 218 | 219 | $this->whereIn($this->getKeyName(), $ids)->update(['read' => false, 'read_at' => null]); 220 | 221 | return $this->whereIn($this->getKeyName(), $ids)->get()->all(); 222 | } 223 | 224 | /** 225 | * Get the primary of all of the notifications. 226 | * 227 | * @param array $notifications 228 | * @return array 229 | */ 230 | public function getIds($notifications) 231 | { 232 | return array_map(function($notification) { 233 | if ($notification instanceof NotificationContract) { 234 | return $notification->getKey(); 235 | } else { 236 | return $notification; 237 | } 238 | }, $notifications); 239 | } 240 | } -------------------------------------------------------------------------------- /src/Feed.php: -------------------------------------------------------------------------------- 1 | store = $store; 30 | } 31 | 32 | /** 33 | * Push the provided notification to the notifiable members. 34 | * 35 | * @param string|array $notification 36 | * @param Notifiable[]|Notifiable $notifiable 37 | * @throws NotNotifiableException 38 | */ 39 | public function push($notification, $notifiable) 40 | { 41 | if ( ! is_array($notifiable) && ! $notifiable instanceof Traversable) { 42 | $notifiable = [$notifiable]; 43 | } 44 | 45 | foreach ($notifiable as $toBeNotified) { 46 | if ( ! $toBeNotified instanceof Notifiable && !$toBeNotified instanceof NotifiableGroup) { 47 | throw new NotNotifiableException("The notifiable members must implement the notifiable interface."); 48 | } 49 | } 50 | 51 | $notification = is_string($notification) ? ['body' => $notification] : $notification; 52 | 53 | foreach ($notifiable as $toBeNotified) { 54 | $this->pushNotification($notification, $toBeNotified); 55 | } 56 | } 57 | 58 | /** 59 | * Push a notification to a member. 60 | * 61 | * @param string|array $notification 62 | * @param Notifiable $notifiable 63 | */ 64 | protected function pushNotification($notification, $notifiable) 65 | { 66 | if ($notifiable instanceof NotifiableGroup) { 67 | foreach ($notifiable->getGroup() as $toBeNotified) { 68 | $this->push($notification, $toBeNotified); 69 | } 70 | } else { 71 | // @todo Change this fucking shite 72 | $notification = $notifiable->notifications()->create($notification); 73 | 74 | event(new NotificationAdded($notification, $notifiable)); 75 | } 76 | } 77 | 78 | /** 79 | * Get all of the unread notifications for the provided notifiable members. 80 | * 81 | * @param array|Notifiable $notifiable 82 | * @return mixed 83 | * @throws NotNotifiableException 84 | */ 85 | public function pull($notifiable) 86 | { 87 | if ( ! is_array($notifiable)) { 88 | $notifiable = func_get_args(); 89 | } 90 | 91 | $notifiable = $this->getUsersToPullFor($notifiable); 92 | 93 | $types = array_map(function ($notifiable) { 94 | return get_class($notifiable); 95 | }, $notifiable); 96 | 97 | $ids = array_map(function ($notifiable) { 98 | return $notifiable->getKey(); 99 | }, $notifiable); 100 | 101 | return $this->store->getNotifications($types, $ids); 102 | } 103 | 104 | /** 105 | * Get all of the read notifications for the provided notifiable members. 106 | * 107 | * @param array|Notifiable $notifiable 108 | * @return mixed 109 | */ 110 | public function pullRead($notifiable) 111 | { 112 | if ( ! is_array($notifiable)) { 113 | $notifiable = func_get_args(); 114 | } 115 | 116 | $notifiable = $this->getUsersToPullFor($notifiable); 117 | 118 | $types = array_map(function ($notifiable) { 119 | return get_class($notifiable); 120 | }, $notifiable); 121 | 122 | $ids = array_map(function ($notifiable) { 123 | return $notifiable->getKey(); 124 | }, $notifiable); 125 | 126 | return $this->store->getNotifications($types, $ids, true); 127 | } 128 | 129 | /** 130 | * Get the users to pull notifications for from the notifiable members. 131 | * 132 | * @param array $notifiable 133 | * @return array 134 | * @throws NotNotifiableException 135 | */ 136 | protected function getUsersToPullFor($notifiable) 137 | { 138 | foreach ($notifiable as $key => $toBeNotified) { 139 | if ( ! $toBeNotified instanceof Notifiable && ! $toBeNotified instanceof NotifiableGroup) { 140 | throw new NotNotifiableException("The members passed to the pull must implement the notifiable interface"); 141 | } 142 | 143 | if ($toBeNotified instanceof NotifiableGroup) { 144 | $group = $toBeNotified->getGroup(); 145 | 146 | if ($group instanceof Collection) { 147 | $group = $group->all(); 148 | } 149 | 150 | $notifiable = array_merge($notifiable, $group); 151 | 152 | unset($notifiable[$key]); 153 | } 154 | } 155 | 156 | return $notifiable; 157 | } 158 | 159 | /** 160 | * Set the amount to limit the feed by. 161 | * 162 | * @param int|string $limit 163 | * @return $this 164 | */ 165 | public function limit($limit) 166 | { 167 | $this->store->limit($limit); 168 | 169 | return $this; 170 | } 171 | 172 | /** 173 | * Set the amount to offset the feed by. 174 | * 175 | * @param int|string $offset 176 | * @return $this 177 | */ 178 | public function offset($offset) 179 | { 180 | $this->store->offset($offset); 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * Set the amount to paginate the feed by. 187 | * 188 | * @param int|string $perPage 189 | * @return $this 190 | */ 191 | public function paginate($perPage) 192 | { 193 | $this->store->paginateResults($perPage); 194 | 195 | return $this; 196 | } 197 | 198 | /** 199 | * Add a filter to be called on the query results. 200 | * 201 | * @param callable $filter 202 | * @return $this 203 | */ 204 | public function filter(callable $filter) 205 | { 206 | $this->store->filter($filter); 207 | 208 | return $this; 209 | } 210 | 211 | /** 212 | * Order the results by the latest notification. 213 | * 214 | * @param string $column 215 | * @return $this 216 | */ 217 | public function latest($column = 'created_at') 218 | { 219 | $this->store->latest($column); 220 | 221 | return $this; 222 | } 223 | 224 | /** 225 | * Order the results by the oldest notification. 226 | * 227 | * @param string $column 228 | * @return $this 229 | */ 230 | public function oldest($column = 'created_at') 231 | { 232 | $this->store->oldest($column); 233 | 234 | return $this; 235 | } 236 | 237 | /** 238 | * Mark the provided notification as read. 239 | * 240 | * @param int|Notification|array $notifications 241 | * @return mixed 242 | */ 243 | public function markAsRead($notifications) 244 | { 245 | if ( ! is_array($notifications)) { 246 | $notifications = func_get_args(); 247 | } 248 | 249 | $notifications = $this->store->markAsRead($notifications); 250 | 251 | foreach ($notifications as $notification) { 252 | event(new NotificationRead($notification)); 253 | } 254 | 255 | return count($notifications) == 1 ? $notifications[0] : $notifications; 256 | } 257 | 258 | /** 259 | * Alias for the mark as read function. 260 | * 261 | * @param int|Notification|array $notifications 262 | * @return mixed 263 | */ 264 | public function read($notifications) 265 | { 266 | return $this->markAsRead($notifications); 267 | } 268 | 269 | /** 270 | * Mark the provided notification as unread. 271 | * 272 | * @param int|Notification|array $notifications 273 | * @return mixed 274 | */ 275 | public function markAsUnread($notifications) 276 | { 277 | if ( ! is_array($notifications)) { 278 | $notifications = func_get_args(); 279 | } 280 | 281 | $notifications = $this->store->markAsUnread($notifications); 282 | 283 | foreach ($notifications as $notification) { 284 | event(new NotificationUnread($notification)); 285 | } 286 | 287 | return count($notifications) == 1 ? $notifications[0] : $notifications; 288 | } 289 | 290 | /** 291 | * Alias for the mark as unread function. 292 | * 293 | * @param int|Notification|array $notifications 294 | * @return mixed 295 | */ 296 | public function unread($notifications) 297 | { 298 | return $this->markAsUnread($notifications); 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Feed (deprecated for Laravel 5.3+) [![Build Status](https://travis-ci.org/michaeljennings/feed.svg?branch=master)](https://travis-ci.org/michaeljennings/feed) [![Coverage Status](https://coveralls.io/repos/github/michaeljennings/feed/badge.svg?branch=master)](https://coveralls.io/github/michaeljennings/feed?branch=master) 2 | 3 | > Note: This package is no longer maintaned for Laravel 5.3+ since Laravel now offers built in [notifications](https://laravel.com/docs/5.6/notifications). 4 | 5 | A basic notification feed for laravel 5+. 6 | 7 | Below is some example code of all of the basic methods for the package. 8 | 9 | ```php 10 | $user = User::find(1); 11 | $team = Team::find(1); 12 | 13 | // Push notification to a user 14 | $feed->push('This is a new notification', $user); 15 | 16 | // Push notification to a user, and a team of users 17 | $feed->push('This is a new notification', [$user, $team]); 18 | 19 | // Push notification to a user with multiple parameters 20 | $feed->push([ 21 | 'icon' => 'icon-alert', 22 | 'title' => 'Something Broke!', 23 | 'body' => 'Something super important broke' 24 | ], $user); 25 | 26 | // Get all of the notifications for a user 27 | $notifications = $feed->pull($user); 28 | 29 | // Get 10 notifications for the user 30 | $notifications = $feed->limit(10)->pull($user); 31 | 32 | // Mark a notification as read 33 | $feed->markAsRead($notification); 34 | ``` 35 | 36 | ## Navigation 37 | 38 | - [Installation](#installation) 39 | - [Configuration](#configuration) 40 | - [Changing the Notification Model](#changing-the-notification-model) 41 | - [Adding a Driver](#adding-a-driver) 42 | - [Using the Feed](#using-the-feed) 43 | - [Setting Up Notifiable Models](#setting-up-notifiable-models) 44 | - [Notifiable Groups](#notifiable-groups) 45 | - [Available Methods](#available-methods) 46 | - [Push](#push) 47 | - [Pull](#pull) 48 | - [Pull Read](#pull-read) 49 | - [Limiting Results](#limiting-results) 50 | - [Offsetting Results](#offsetting-results) 51 | - [Paginate Results](#paginate-results) 52 | - [Filtering Results](#filtering-results) 53 | - [Get the Latest Results](#get-the-latest-results) 54 | - [Get the Oldest Results](#get-the-oldest-results) 55 | - [Putting it All Together](#putting-it-all-together) 56 | - [Marking Notification as Read](#marking-notification-as-read) 57 | - [Marking Notification as Unread](#marking-notification-as-unread) 58 | 59 | ## Installation 60 | 61 | This package requires at least laravel 5. 62 | 63 | To install through composer include the package in your `composer.json`. 64 | 65 | "michaeljennings/feed": "0.2.*" 66 | 67 | Run `composer install` or `composer update` to download the dependencies, or you can run `composer require michaeljennings/feed`. 68 | 69 | Once installed add the service provider to the providers array in `config/app.php`. 70 | 71 | ```php 72 | 'providers' => [ 73 | 74 | Michaeljennings\Feed\FeedServiceProvider::class 75 | 76 | ]; 77 | ``` 78 | 79 | To publish the migrations and config files run `php artisan vendor:publish`. 80 | 81 | ## Configuration 82 | 83 | The package comes with a default migration to create the database structure for the package. By default this table allows for the notifications to have a body, and an icon. If need more data for your notification such as a title, we recommend adding the columns to the default migration. 84 | 85 | The package comes with `feed.php` config file. This allows you to customise the database driver you are using with the package. At present only eloquent is supported, but we are working on a laravel db driver currently. 86 | 87 | ### Changing the Notification Model 88 | 89 | From time to time you may need to add additional methods or properties to the notification model, for example you might want to add an additional relationship to the notification model. 90 | 91 | This can be done very simply by changing the notification model in the config file as shown below. 92 | 93 | ```php 94 | 'drivers' => [ 95 | 'eloquent' => [ 96 | 'model' => 'Path\To\Notification', // Update this to your notification model. 97 | ], 98 | ] 99 | ``` 100 | 101 | The default notification model implements a couple of interfaces that are required by this package. If you need to make changes to the model I recommend extending the default model, otherwise make sure you implement the interfaces. 102 | 103 | ```php 104 | // Example of extending the model 105 | class Notification extends \Michaeljennings\Feed\Store\Eloquent\Notification 106 | { 107 | public function foo() 108 | { 109 | // 110 | } 111 | } 112 | 113 | // Example of just implementing the interfaces 114 | class Notification implements \Michaeljennings\Feed\Contracts\Notification, \Michaeljennings\Feed\Contracts\Store 115 | { 116 | public function bar() 117 | { 118 | // 119 | } 120 | } 121 | ``` 122 | 123 | ### Adding a Driver 124 | 125 | You may require another driver, i.e. you're using a data store not supported by laravel. If this is the case you can add a driver to the system verify simply as shown below. 126 | 127 | ```php 128 | // Here we grab the driver manager and then extend it to a new 'foo' driver. 129 | // Ideally this would be done within a service provider. 130 | app('feed.manager')->extend('foo', function($app) { 131 | return new Foo(); 132 | }); 133 | 134 | // The Foo driver needs to implement the Store interface so it has all of 135 | // the necessary methods. 136 | class Foo implements Michaeljennings\Feed\Contracts\Store 137 | { 138 | // 139 | } 140 | 141 | // The in the config file set the driver to our new foo driver. 142 | return [ 143 | 'driver' => 'foo' 144 | ] 145 | ``` 146 | 147 | For more information on adding drivers look at the [laravel documentation on extending the framework](https://laravel.com/docs/5.0/extending). 148 | 149 | ## Using the Feed 150 | 151 | Once installed you can access the feed in multiple ways. 152 | 153 | Firstly you can dependency inject it from the IOC container by either the push or pull feed interfaces. Both interfaces will return the same instance, it's just to make your code more readable. 154 | 155 | ```php 156 | public function __construct( 157 | Michaeljennings\Feed\Contracts\PullFeed $pullFeed, 158 | Michaeljennings\Feed\Contracts\PushFeed $pushFeed 159 | ) { 160 | $this->pullFeed = $pullFeed; 161 | $this->pushFeed = $pushFeed; 162 | } 163 | ``` 164 | 165 | Or you there is a `feed` helper method. 166 | 167 | ```php 168 | $feed = feed(); 169 | ``` 170 | 171 | Or if you want to use the facade you can register it in the aliases array in `config/app.php`. 172 | 173 | ```php 174 | 'aliases' => [ 175 | 'Feed' => Michaeljennings\Feed\Facades\Feed::class 176 | ] 177 | ``` 178 | 179 | ## Setting Up Notifiable Models 180 | 181 | To set up a notifiable model you just need to implement the notifiable interface, and then use the notifiable trait in your model. 182 | 183 | This will set up the required relationships. 184 | 185 | ```php 186 | use Michaeljennings\Feed\Contracts\Notifiable as NotifiableContract; 187 | use Michaeljennings\Feed\Notifications\Notifiable; 188 | 189 | class User extends Model implements NotifiableContract 190 | { 191 | use Notifiable; 192 | } 193 | ``` 194 | 195 | ### Notifiable Groups 196 | 197 | It is also possible to set up groups of notifiable models, an example of when this would be useful is having a team of users. This will allow us to push a notification to all the members of that group. 198 | 199 | To set up a notifiable group you need implement the notifiable group interface on the group model. This will add a method called `getGroup` which requires you to return the members you would like to be notified. 200 | 201 | In the example below we have a team model which implements the group interface. It has a `users` relationship which returns all of the users belonging to the team. Then in the `getGroup` method we simply return the users. 202 | 203 | ```php 204 | use Michaeljennings\Feed\Contracts\NotifiableGroup; 205 | 206 | class Team extends Model implements NotifiableGroup 207 | { 208 | public function users() 209 | { 210 | return $this->hasMany('App\User'); 211 | } 212 | 213 | public function getGroup() 214 | { 215 | return $this->users; 216 | } 217 | } 218 | ``` 219 | 220 | ## Available Methods 221 | 222 | Below is a list of all of the currently available notification methods. If you think of anything you want to add please feel free to create an issue, or a pull request. 223 | 224 | ### Push 225 | 226 | The push method allows you to push a notification to a notifiable model, multiple notifiable models, or a notifiable group. 227 | 228 | When pushing to a notifiable group each member of the group will get their own notification, it will not share one notification for all of the members. 229 | 230 | ```php 231 | $feed->push('My awesome notification', $user); 232 | $feed->push('My awesome notification', [$user, $team]); 233 | $feed->push([ 234 | 'title' => 'New Notification', 235 | 'body' => 'My awesome notification' 236 | ], $user); 237 | ``` 238 | 239 | When the notification is pushed a `NotificationAdded` event will be fired. 240 | 241 | You can then listen for this and then broadcast the notification, send an email etc. 242 | 243 | You just need to register the listeners in the event service provider. 244 | 245 | ```php 246 | protected $listen = [ 247 | 'Michaeljennings\Feed\Events\NotificationAdded' => [ 248 | 'App\Listeners\BroadcastNotification', 249 | 'App\Listeners\EmailNotification', 250 | ], 251 | ]; 252 | ``` 253 | 254 | ### Pull 255 | 256 | The pull method gets all of the unread notifications for the notifiable models you pass it. 257 | 258 | ```php 259 | $feed->pull($user); 260 | ``` 261 | 262 | #### Pull Read 263 | 264 | To get all of the read notifications for a member, use the `pullRead` method. 265 | 266 | ```php 267 | $feed->pullRead($user); 268 | ``` 269 | 270 | #### Limiting Results 271 | 272 | To limit the amount of notifications returned when pulling, chain the `limit` method. 273 | 274 | ```php 275 | $feed->limit(10)->pull($user); 276 | $feed->limit(10)->pullRead($user); 277 | ``` 278 | 279 | #### Offsetting Results 280 | 281 | To offset the results when pulling, chain the `offset` method. This can be useful for infinte scrollers. 282 | 283 | ```php 284 | $feed->offset(10)->pull($user); 285 | $feed->offset(10)->pullRead($user); 286 | ``` 287 | 288 | #### Paginate Results 289 | 290 | If you want to paginate the results and let laravel handle the limiting and offsetting for you, chain the `paginate` method. 291 | 292 | ```php 293 | $feed->paginate(10)->pull($user); 294 | $feed->paginate(10)->pullRead($user); 295 | ``` 296 | 297 | #### Filtering Results 298 | 299 | From time to time you may wish to run additional queries on the notification results, to do this chain the filter method. 300 | 301 | The filter method requires a closure which is passed an instance of the query builder. In the example below we're only getting results that have an alert icon. 302 | 303 | ```php 304 | $feed->filter(function($query) { 305 | $query->where('icon', 'icon-alert'); 306 | })->pull($user); 307 | 308 | $feed->filter(function($query) { 309 | $query->where('icon', 'icon-alert'); 310 | })->pullRead($user); 311 | ``` 312 | 313 | #### Get the Latest Results 314 | 315 | To order the results by the latest notification added, chain the `latest` method. By default the notifications are ordered by the latest notification added. 316 | 317 | ```php 318 | $feed->latest()->pull($user); 319 | $feed->latest()->pullRead($user); 320 | ``` 321 | 322 | #### Get the Oldest Results 323 | 324 | To order the results by the oldest notification added, chain the `oldest` method. By default the notifications are ordered by the latest notification added. 325 | 326 | ```php 327 | $feed->oldest()->pull($user); 328 | $feed->oldest()->pullRead($user); 329 | ``` 330 | 331 | #### Putting it All Together 332 | 333 | All of these methods can be chained together, this should allow you to get the notifications in any way you require. 334 | 335 | ```php 336 | // Limit and offset the results 337 | $feed->limit(10)->offset(10)->pull($user); 338 | 339 | 340 | // Get all of the oldest read notifications, that have an alert icon. 341 | $feed->filter(function($query) { 342 | $query->where('icon', 'icon-alert'); 343 | })->oldest()->pullRead($user); 344 | ``` 345 | 346 | ### Marking Notification as Read 347 | 348 | To mark a notification as read you can either use the `markAsRead` method, or it is aliased to `read` if you prefer. 349 | 350 | ```php 351 | $feed->markAsRead($notification); 352 | $feed->read($notification); 353 | ``` 354 | 355 | When the notification is read marked as read a `NotificationRead` event will be fired. 356 | 357 | You can then listen for this and then broadcast it etc. 358 | 359 | ```php 360 | protected $listen = [ 361 | 'Michaeljennings\Feed\Events\NotificationRead' => [ 362 | 'App\Listeners\BroadcastReadNotification', 363 | ], 364 | ]; 365 | ``` 366 | 367 | ### Marking Notification as Unread 368 | 369 | To mark a notification as unread you can either use the `markAsUnread` method, or it is aliased to `unread` if you prefer. 370 | 371 | ```php 372 | $feed->markAsUnread($notification); 373 | $feed->unread($notification); 374 | ``` 375 | 376 | When the notification is read marked as unread a `NotificationUnread` event will be fired. 377 | 378 | You can then listen for this and then broadcast it etc. 379 | 380 | ```php 381 | protected $listen = [ 382 | 'Michaeljennings\Feed\Events\NotificationUnread' => [ 383 | 'App\Listeners\BroadcastUnreadNotification', 384 | ], 385 | ]; 386 | ``` 387 | -------------------------------------------------------------------------------- /tests/FeedTest.php: -------------------------------------------------------------------------------- 1 | make(); 19 | $user = new User(); 20 | 21 | $this->assertEquals(0, $feed->pull($user)->count()); 22 | $feed->push('This is a test notification', $user); 23 | 24 | $notifications = $feed->pull($user); 25 | 26 | $this->assertEquals(1, $notifications->count()); 27 | $this->assertEquals('This is a test notification', $notifications->first()->body); 28 | } 29 | 30 | /** 31 | * @test 32 | */ 33 | public function it_pushes_a_notification_to_multiple_users_in_an_array() 34 | { 35 | $feed = $this->make(); 36 | $user1 = new User(); 37 | $user2 = new User(['id' => 2]); 38 | 39 | $this->assertEquals(0, $feed->pull($user1)->count()); 40 | $this->assertEquals(0, $feed->pull($user2)->count()); 41 | 42 | $feed->push('This is a test notification', [$user1, $user2]); 43 | 44 | $notifications = $feed->pull($user1); 45 | 46 | $this->assertEquals(1, $notifications->count()); 47 | $this->assertEquals('This is a test notification', $notifications->first()->body); 48 | 49 | $notifications = $feed->pull($user2); 50 | 51 | $this->assertEquals(1, $notifications->count()); 52 | $this->assertEquals('This is a test notification', $notifications->first()->body); 53 | } 54 | 55 | /** 56 | * @test 57 | */ 58 | public function it_pushes_a_notification_to_multiple_users_in_a_collection() 59 | { 60 | $feed = $this->make(); 61 | $user1 = new User(); 62 | $user2 = new User(['id' => 2]); 63 | 64 | $this->assertEquals(0, $feed->pull($user1)->count()); 65 | $this->assertEquals(0, $feed->pull($user2)->count()); 66 | 67 | $feed->push('This is a test notification', collect([$user1, $user2])); 68 | 69 | $notifications = $feed->pull($user1); 70 | 71 | $this->assertEquals(1, $notifications->count()); 72 | $this->assertEquals('This is a test notification', $notifications->first()->body); 73 | 74 | $notifications = $feed->pull($user2); 75 | 76 | $this->assertEquals(1, $notifications->count()); 77 | $this->assertEquals('This is a test notification', $notifications->first()->body); 78 | } 79 | 80 | /** 81 | * @test 82 | */ 83 | public function it_pushes_to_a_notifiable_group() 84 | { 85 | $feed = $this->make(); 86 | $team = new Team(); 87 | $user = new User(); 88 | $user2 = new User(['id' => 2]); 89 | 90 | $this->assertEquals(0, $feed->pull($team)->count()); 91 | $feed->push('This is a test notification', $team); 92 | 93 | $notifications = $feed->pull($team); 94 | 95 | $this->assertEquals(1, $notifications->count()); 96 | $this->assertEquals('This is a test notification', $notifications->first()->body); 97 | 98 | $notifications = $feed->pull($user); 99 | 100 | $this->assertEquals(1, $notifications->count()); 101 | $this->assertEquals('This is a test notification', $notifications->first()->body); 102 | 103 | $notifications = $feed->pull($user2); 104 | 105 | $this->assertEquals(0, $notifications->count()); 106 | } 107 | 108 | /** 109 | * @test 110 | */ 111 | public function it_pushes_a_notification_with_multiple_parameters() 112 | { 113 | $feed = $this->make(); 114 | $user = new User(); 115 | 116 | $this->assertEquals(0, $feed->pull($user)->count()); 117 | $feed->push([ 118 | 'body' => 'This is a test notification', 119 | 'icon' => 'fa fa-alert', 120 | ], $user); 121 | 122 | $notifications = $feed->pull($user); 123 | 124 | $this->assertEquals(1, $notifications->count()); 125 | $this->assertEquals('This is a test notification', $notifications->first()->body); 126 | $this->assertEquals('fa fa-alert', $notifications->first()->icon); 127 | } 128 | 129 | /** 130 | * @test 131 | */ 132 | public function it_does_not_require_an_icon() 133 | { 134 | $feed = $this->make(); 135 | $user = new User(); 136 | 137 | $this->assertEquals(0, $feed->pull($user)->count()); 138 | $feed->push([ 139 | 'body' => 'This is a test notification', 140 | ], $user); 141 | 142 | $notifications = $feed->pull($user); 143 | 144 | $this->assertEquals(1, $notifications->count()); 145 | $this->assertEquals('This is a test notification', $notifications->first()->body); 146 | $this->assertNull($notifications->first()->icon); 147 | } 148 | 149 | /** 150 | * @test 151 | */ 152 | public function it_pulls_read_notifications() 153 | { 154 | $feed = $this->make(); 155 | $user = new User(); 156 | 157 | $this->assertEquals(0, $feed->pull($user)->count()); 158 | $feed->push('This notification will not be read', $user); 159 | $feed->push('This notification will be read', $user); 160 | 161 | $notifications = $feed->oldest()->pull($user); 162 | 163 | $this->assertEquals(2, $notifications->count()); 164 | 165 | $feed->markAsRead($notifications->last()); 166 | 167 | $this->assertEquals(1, $feed->pull($user)->count()); 168 | 169 | $readNotifications = $feed->pullRead($user); 170 | 171 | $this->assertEquals(1, $readNotifications->count()); 172 | $this->assertEquals('This notification will be read', $readNotifications->first()->body); 173 | } 174 | 175 | /** 176 | * @test 177 | */ 178 | public function it_marks_notification_as_read_using_the_read_alias() 179 | { 180 | $feed = $this->make(); 181 | $user = new User(); 182 | 183 | $this->assertEquals(0, $feed->pull($user)->count()); 184 | $feed->push('This notification will not be read', $user); 185 | $feed->push('This notification will be read', $user); 186 | 187 | $notifications = $feed->pull($user); 188 | 189 | $this->assertEquals(2, $notifications->count()); 190 | 191 | $feed->read($notifications->last()); 192 | 193 | $this->assertEquals(1, $feed->pull($user)->count()); 194 | 195 | $readNotifications = $feed->pullRead($user); 196 | 197 | $this->assertEquals(1, $readNotifications->count()); 198 | $this->assertEquals('This notification will be read', $readNotifications->first()->body); 199 | } 200 | 201 | /** 202 | * @test 203 | */ 204 | public function it_marks_a_notification_as_unread() 205 | { 206 | $feed = $this->make(); 207 | $user = new User(); 208 | 209 | $this->assertEquals(0, $feed->pull($user)->count()); 210 | $feed->push('This notification will not be read', $user); 211 | $feed->push('This notification will be read', $user); 212 | 213 | $notifications = $feed->oldest()->pull($user); 214 | 215 | $this->assertEquals(2, $notifications->count()); 216 | 217 | $feed->markAsRead($notifications->last()); 218 | 219 | $this->assertEquals(1, $feed->pull($user)->count()); 220 | 221 | $readNotifications = $feed->pullRead($user); 222 | 223 | $this->assertEquals(1, $readNotifications->count()); 224 | $this->assertEquals('This notification will be read', $readNotifications->first()->body); 225 | 226 | $feed->markAsUnread($readNotifications->first()); 227 | 228 | $notifications = $feed->oldest()->pull($user); 229 | 230 | $this->assertEquals(2, $notifications->count()); 231 | $this->assertEquals('This notification will be read', $notifications->last()->body); 232 | 233 | $this->assertEquals(0, $feed->pullRead($user)->count()); 234 | } 235 | 236 | /** 237 | * @test 238 | */ 239 | public function it_marks_a_notification_as_unread_using_the_alias() 240 | { 241 | $feed = $this->make(); 242 | $user = new User(); 243 | 244 | $this->assertEquals(0, $feed->pull($user)->count()); 245 | $feed->push('This notification will not be read', $user); 246 | $feed->push('This notification will be read', $user); 247 | 248 | $notifications = $feed->oldest()->pull($user); 249 | 250 | $this->assertEquals(2, $notifications->count()); 251 | 252 | $feed->read($notifications->last()); 253 | 254 | $this->assertEquals(1, $feed->pull($user)->count()); 255 | 256 | $readNotifications = $feed->pullRead($user); 257 | 258 | $this->assertEquals(1, $readNotifications->count()); 259 | $this->assertEquals('This notification will be read', $readNotifications->first()->body); 260 | 261 | $feed->unread($readNotifications->first()); 262 | 263 | $notifications = $feed->oldest()->pull($user); 264 | 265 | $this->assertEquals(2, $notifications->count()); 266 | $this->assertEquals('This notification will be read', $notifications->last()->body); 267 | 268 | $this->assertEquals(0, $feed->pullRead($user)->count()); 269 | } 270 | 271 | /** 272 | * @test 273 | */ 274 | public function it_marks_a_notification_as_read_using_the_notification_id() 275 | { 276 | $feed = $this->make(); 277 | $user = new User(); 278 | 279 | $this->assertEquals(0, $feed->pull($user)->count()); 280 | $feed->push('This notification will not be read', $user); 281 | $feed->push('This notification will be read', $user); 282 | 283 | $notifications = $feed->oldest()->pull($user); 284 | 285 | $this->assertEquals(2, $notifications->count()); 286 | 287 | $feed->markAsRead($notifications->last()->id); 288 | 289 | $this->assertEquals(1, $feed->pull($user)->count()); 290 | 291 | $readNotifications = $feed->oldest()->pullRead($user); 292 | 293 | $this->assertEquals(1, $readNotifications->count()); 294 | $this->assertEquals('This notification will be read', $readNotifications->first()->body); 295 | } 296 | 297 | /** 298 | * @test 299 | */ 300 | public function it_marks_a_notification_as_unread_using_the_notification_id() 301 | { 302 | $feed = $this->make(); 303 | $user = new User(); 304 | 305 | $this->assertEquals(0, $feed->pull($user)->count()); 306 | $feed->push('This notification will not be read', $user); 307 | $feed->push('This notification will be read', $user); 308 | 309 | $notifications = $feed->oldest()->pull($user); 310 | 311 | $this->assertEquals(2, $notifications->count()); 312 | 313 | $feed->markAsRead($notifications->last()->id); 314 | 315 | $this->assertEquals(1, $feed->pull($user)->count()); 316 | 317 | $readNotifications = $feed->pullRead($user); 318 | 319 | $this->assertEquals(1, $readNotifications->count()); 320 | $this->assertEquals('This notification will be read', $readNotifications->first()->body); 321 | 322 | $feed->markAsUnread($readNotifications->first()->id); 323 | 324 | $notifications = $feed->oldest()->pull($user); 325 | 326 | $this->assertEquals(2, $notifications->count()); 327 | $this->assertEquals('This notification will be read', $notifications->last()->body); 328 | 329 | $this->assertEquals(0, $feed->pullRead($user)->count()); 330 | } 331 | 332 | /** 333 | * @test 334 | */ 335 | public function it_limits_the_amount_of_notifications_returned() 336 | { 337 | $feed = $this->make(); 338 | $user = new User(); 339 | 340 | $feed->push('Notification 1', $user); 341 | $feed->push('Notification 2', $user); 342 | $feed->push('Notification 3', $user); 343 | $feed->push('Notification 4', $user); 344 | 345 | $notifications = $feed->limit(2)->oldest()->pull($user); 346 | 347 | $this->assertEquals(2, $notifications->count()); 348 | $this->assertEquals('Notification 1', $notifications->first()->body); 349 | $this->assertEquals('Notification 2', $notifications->last()->body); 350 | } 351 | 352 | /** 353 | * @test 354 | */ 355 | public function it_offsets_and_limits_the_returned_notifications() 356 | { 357 | $feed = $this->make(); 358 | $user = new User(); 359 | 360 | $feed->push('Notification 1', $user); 361 | $feed->push('Notification 2', $user); 362 | $feed->push('Notification 3', $user); 363 | $feed->push('Notification 4', $user); 364 | 365 | $notifications = $feed->limit(2)->oldest()->offset(1)->pull($user); 366 | 367 | $this->assertEquals(2, $notifications->count()); 368 | $this->assertEquals('Notification 2', $notifications->first()->body); 369 | $this->assertEquals('Notification 3', $notifications->last()->body); 370 | } 371 | 372 | /** 373 | * @test 374 | */ 375 | public function it_limits_the_amount_of_read_notifications_returned() 376 | { 377 | $feed = $this->make(); 378 | $user = new User(); 379 | 380 | $feed->push('Notification 1', $user); 381 | $feed->push('Notification 2', $user); 382 | $feed->push('Notification 3', $user); 383 | $feed->push('Notification 4', $user); 384 | 385 | $feed->markAsRead(1); 386 | $feed->markAsRead(2); 387 | $feed->markAsRead(3); 388 | $feed->markAsRead(4); 389 | 390 | $notifications = $feed->limit(2)->oldest()->pullRead($user); 391 | 392 | $this->assertEquals(2, $notifications->count()); 393 | $this->assertEquals('Notification 1', $notifications->first()->body); 394 | $this->assertEquals('Notification 2', $notifications->last()->body); 395 | } 396 | 397 | /** 398 | * @test 399 | */ 400 | public function it_limits_and_offsets_the_read_notifications_returned() 401 | { 402 | $feed = $this->make(); 403 | $user = new User(); 404 | 405 | $feed->push('Notification 1', $user); 406 | $feed->push('Notification 2', $user); 407 | $feed->push('Notification 3', $user); 408 | $feed->push('Notification 4', $user); 409 | 410 | $feed->markAsRead(1); 411 | $feed->markAsRead(2); 412 | $feed->markAsRead(3); 413 | $feed->markAsRead(4); 414 | 415 | $notifications = $feed->limit(2)->oldest()->offset(1)->pullRead($user); 416 | 417 | $this->assertEquals(2, $notifications->count()); 418 | $this->assertEquals('Notification 2', $notifications->first()->body); 419 | $this->assertEquals('Notification 3', $notifications->last()->body); 420 | } 421 | 422 | /** 423 | * @test 424 | */ 425 | public function it_paginates_the_amount_of_notifications_returned() 426 | { 427 | $feed = $this->make(); 428 | $user = new User(); 429 | 430 | $feed->push('Notification 1', $user); 431 | $feed->push('Notification 2', $user); 432 | $feed->push('Notification 3', $user); 433 | $feed->push('Notification 4', $user); 434 | 435 | $notifications = $feed->paginate(2)->oldest()->pull($user); 436 | 437 | $this->assertEquals(2, $notifications->count()); 438 | $this->assertEquals('Notification 1', $notifications->first()->body); 439 | $this->assertEquals('Notification 2', $notifications->last()->body); 440 | 441 | request()->merge(['page' => 2]); 442 | 443 | $notifications = $feed->paginate(2)->oldest()->pull($user); 444 | 445 | $this->assertEquals(2, $notifications->count()); 446 | $this->assertEquals('Notification 3', $notifications->first()->body); 447 | $this->assertEquals('Notification 4', $notifications->last()->body); 448 | } 449 | 450 | /** 451 | * @test 452 | */ 453 | public function it_paginates_the_amount_of_read_notifications_returned() 454 | { 455 | $feed = $this->make(); 456 | $user = new User(); 457 | 458 | $feed->push('Notification 1', $user); 459 | $feed->push('Notification 2', $user); 460 | $feed->push('Notification 3', $user); 461 | $feed->push('Notification 4', $user); 462 | 463 | $feed->markAsRead(1); 464 | $feed->markAsRead(2); 465 | $feed->markAsRead(3); 466 | $feed->markAsRead(4); 467 | 468 | $notifications = $feed->paginate(2)->oldest()->pullRead($user); 469 | 470 | $this->assertEquals(2, $notifications->count()); 471 | $this->assertEquals('Notification 1', $notifications->first()->body); 472 | $this->assertEquals('Notification 2', $notifications->last()->body); 473 | 474 | request()->merge(['page' => 2]); 475 | 476 | $notifications = $feed->paginate(2)->oldest()->pullRead($user); 477 | 478 | $this->assertEquals(2, $notifications->count()); 479 | $this->assertEquals('Notification 3', $notifications->first()->body); 480 | $this->assertEquals('Notification 4', $notifications->last()->body); 481 | } 482 | 483 | /** 484 | * @test 485 | */ 486 | public function it_filters_the_notifications() 487 | { 488 | $feed = $this->make(); 489 | $user = new User(); 490 | 491 | $feed->push('Notification 1', $user); 492 | $feed->push('Notification 2', $user); 493 | $feed->push('Notification 3', $user); 494 | $feed->push('Notification 4', $user); 495 | 496 | $notifications = $feed->filter(function($query) { 497 | $query->where('body', 'Notification 1'); 498 | })->pull($user); 499 | 500 | $this->assertEquals(1, $notifications->count()); 501 | $this->assertEquals('Notification 1', $notifications->first()->body); 502 | } 503 | 504 | /** 505 | * @test 506 | */ 507 | public function it_filters_the_read_notifications() 508 | { 509 | $feed = $this->make(); 510 | $user = new User(); 511 | 512 | $feed->push('Notification 1', $user); 513 | $feed->push('Notification 2', $user); 514 | $feed->push('Notification 3', $user); 515 | $feed->push('Notification 4', $user); 516 | 517 | $feed->markAsRead(1, 2, 3, 4); 518 | 519 | $notifications = $feed->filter(function($query) { 520 | $query->where('body', 'Notification 1'); 521 | })->oldest()->pullRead($user); 522 | 523 | $this->assertEquals(1, $notifications->count()); 524 | $this->assertEquals('Notification 1', $notifications->first()->body); 525 | } 526 | 527 | /** 528 | * @test 529 | */ 530 | public function it_orders_the_results_by_the_latest_notifications() 531 | { 532 | $feed = $this->make(); 533 | $user = new User(); 534 | 535 | $feed->push('Notification 1', $user); 536 | $feed->push('Notification 2', $user); 537 | $feed->push('Notification 3', $user); 538 | sleep(1); 539 | $feed->push('Notification 4', $user); 540 | 541 | $notifications = $feed->latest()->pull($user); 542 | 543 | $this->assertEquals(4, $notifications->count()); 544 | $this->assertEquals('Notification 4', $notifications->first()->body); 545 | } 546 | 547 | /** 548 | * @test 549 | */ 550 | public function it_orders_the_results_by_the_oldest_notifications() 551 | { 552 | $feed = $this->make(); 553 | $user = new User(); 554 | 555 | $feed->push('Notification 1', $user); 556 | sleep(1); 557 | $feed->push('Notification 2', $user); 558 | $feed->push('Notification 3', $user); 559 | $feed->push('Notification 4', $user); 560 | 561 | $notifications = $feed->oldest()->pull($user); 562 | 563 | $this->assertEquals(4, $notifications->count()); 564 | $this->assertEquals('Notification 1', $notifications->first()->body); 565 | } 566 | 567 | /** 568 | * @test 569 | * @expectedException \Michaeljennings\Feed\Exceptions\NotNotifiableException 570 | */ 571 | public function it_tests_not_notifiable_exception_is_thrown_when_pushing() 572 | { 573 | $feed = $this->make(); 574 | 575 | $feed->push('this is a test', new stdClass); 576 | } 577 | 578 | /** 579 | * @test 580 | * @expectedException \Michaeljennings\Feed\Exceptions\NotNotifiableException 581 | */ 582 | public function it_tests_not_notifiable_exception_is_thrown_when_pulling() 583 | { 584 | $feed = $this->make(); 585 | 586 | $feed->pull(new stdClass); 587 | } 588 | 589 | /** 590 | * @test 591 | */ 592 | public function it_fires_a_notification_added_event_when_a_notification_is_pushed() 593 | { 594 | $this->expectsEvents(NotificationAdded::class); 595 | 596 | $feed = $this->make(); 597 | $user = new User(); 598 | 599 | $feed->push('This is a test notification', $user); 600 | } 601 | 602 | /** 603 | * @test 604 | */ 605 | public function it_fires_a_notification_read_event_when_a_notification_is_marked_as_read() 606 | { 607 | $this->expectsEvents(NotificationRead::class); 608 | 609 | $feed = $this->make(); 610 | $user = new User(); 611 | 612 | $feed->push('This is a test notification', $user); 613 | 614 | $notifications = $feed->pull($user); 615 | 616 | $feed->markAsRead($notifications->first()); 617 | } 618 | 619 | /** 620 | * @test 621 | */ 622 | public function it_fires_a_notification_read_event_when_a_notification_is_marked_as_unread() 623 | { 624 | $this->expectsEvents(NotificationUnread::class); 625 | 626 | $feed = $this->make(); 627 | $user = new User(); 628 | 629 | $feed->push('This is a test notification', $user); 630 | 631 | $notifications = $feed->pull($user); 632 | 633 | $feed->markAsRead($notifications->first()); 634 | $feed->markAsUnread($notifications->first()); 635 | } 636 | 637 | /** 638 | * @test 639 | */ 640 | public function it_tests_the_feed_helper() 641 | { 642 | $feed = feed(); 643 | 644 | $this->assertInstanceOf('Michaeljennings\Feed\Contracts\PullFeed', $feed); 645 | 646 | $user = new User(); 647 | 648 | $this->assertInstanceOf('Illuminate\Support\Collection', feed($user)); 649 | } 650 | 651 | /** 652 | * @test 653 | */ 654 | public function it_tests_the_facade_works_correctly() 655 | { 656 | $user = new User(); 657 | 658 | $this->assertInstanceOf('Illuminate\Support\Collection', Feed::pull($user)); 659 | } 660 | 661 | protected function make() 662 | { 663 | return feed(); 664 | } 665 | } --------------------------------------------------------------------------------