I am implementing Laravel 5.3 Notifications at the moment which is working very nice.
At the moment I am using 'email' as a notifications channel but I want to add 'database' too. I am using different databases/connections for languages and want to store the notifications in a central database / Connection.
How do I use a different database connection for notifications?
I already tried creating a Notifications model but that did not work:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Notifications extends Model
{
protected $connection = 'system';
}
Hackish solution. But tried and tested on a MongoDB connection.
What needs to be modified;
The Notifiable trait
The DatabaseNotification model
Optionally (nothing changes if you are using mysql) modify the HasNotifications trait
Modify the DatabaseNotificationCollection.Again this is useful for a non-mysql connection
Step One : Create a custom Notifiable Trait
Copy the contents from Illuminate\Notifications\Notifiable and create a new file in your custom path...say App\Overrides\Notifications\Notifiable.
Your file will feature two changes...the namespace and you have to load the RoutesNotifications trait since we are not copying it over.
<?php
namespace App\Overrides\Notifications;
use use Illuminate\Notifications\RoutesNotifications;
trait Notifiable{
//The rest of the code remains
}
Step Two : Create a custom DatabaseNotification model
Follow the same procedure as above and copy the contents of the Illuminate\Notifications\DatabaseNotification file to the custom path that we created above...App\Overrides\Notification\DatabaseNotification
This is a standard Eloquent model and the connection change actually happens here
<?php
namespace App\Overrides\Notification;
//Use this if on mongodb.otherwise use to Illuminate\Database\Eloquent\Model
use Jenssegers\Mongodb\Eloquent\Model;
use Illuminate\Notifications\DatabaseNotificationCollection;
class DatabaseNotification extends Model
{
protected $connection = 'YOUR_CONNECTION_NAME_GOES HERE';
}
As of this point this should work if you are on a mysql connection.
To try this out change the Notifiable trait on the user model to use App\Overrides\Notifications\Notifiable. The notifications will use the connection you specified.
Users of MongoDB will have to take extra steps since the most popular driver I know of does not yet support MorphMany relations which are put to use for Laravel notifications.
Since that is not the asked question we leave it at that :-)
On Laravel 5.7 based on #Bernard answer
User.php
<?php
namespace App;
// implement the override Notifiable trait
use App\Traits\Override\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
}
Notifiable.php
<?php
namespace App\Traits\Override;
use Illuminate\Notifications\RoutesNotifications;
trait Notifiable
{
use HasDatabaseNotifications, RoutesNotifications;
}
HasDatabaseNotifications.php
<?php
namespace App\Traits\Override;
use App\Models\Override\MultiConnectionDatabaseNotification;
trait HasDatabaseNotifications
{
/**
* Get the entity's notifications.
*
* #return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function notifications()
{
return $this->morphMany(MultiConnectionDatabaseNotification::class, 'notifiable')->orderBy('created_at', 'desc');
}
/**
* Get the entity's read notifications.
*
* #return \Illuminate\Database\Query\Builder
*/
public function readNotifications()
{
return $this->notifications()->whereNotNull('read_at');
}
/**
* Get the entity's unread notifications.
*
* #return \Illuminate\Database\Query\Builder
*/
public function unreadNotifications()
{
return $this->notifications()->whereNull('read_at');
}
}
MultiConnectionDatabaseNotification.php
<?php
namespace App\Models\Override;
use Illuminate\Notifications\DatabaseNotification as DatabaseNotification;
class MultiConnectionDatabaseNotification extends DatabaseNotification
{
// set your preferred connection here
protected $connection = 'oracle';
}
It's pretty simple, Just add protected $connection = 'YOUR CONNECTION NAME'; at Illuminate\Notifications\DatabaseNotification
That's all and it will work :)
You don't need to create new models if you are going to use one notification table with same connection.
My code will works if ur using different connection for USER model.
Related
Following the guide to implement the native mail verification of laravel.
Brings me an error.
Note please that i use MongoDB, therefore i'm using Jensseger/laravel-mongodb package
This is the error:
Class App\User contains 3 abstract methods and must therefore be declared abstract or implement the remaining methods (Illuminate\Contracts\Auth\MustVerifyEmail::hasVerifiedEmail, Illuminate\Contracts\Auth\MustVerifyEmail::markEmailAsVerified, Illuminate\Contracts\Auth\MustVerifyEmail::sendEmailVerificationNotification
I've already try to implement the methods inside my model and they seem to solve the problem. But it won't send any emails.
Here's what i've implemented im my User.php model
* Determine if the user has verified their email address.
*
* #return bool
*/
public function hasVerifiedEmail()
{}
/**
* Mark the given user's email as verified.
*
* #return bool
*/
public function markEmailAsVerified()
{}
/**
* Send the email verification notification.
*
* #return void
*/
public function sendEmailVerificationNotification()
{}
Here's my User.php model
namespace App;
use App\Company;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Jenssegers\Mongodb\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;
protected $connection = 'mongodb';
Here's my web.php route file.
Route::get('/', function () {
return view('welcome');
});
Auth::routes(['verify' => true]);
Route::get('/home', 'HomeController#index')->name('home');
And here's my HomeController.php
public function __construct()
{
$this->middleware(['auth','verified']);
}
Here's my env file
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=25
MAIL_USERNAME=xxxxxxxxxxx
MAIL_PASSWORD=xxxxxxxxxxxx
MAIL_ENCRYPTION=tls
Like this the project work but it wont send emails. Do i need to put the logic inside the three method inside the User.php? If yes what should i put in it? I've no idea because if it's native and work like charm with SQL i don't really know how to get it work on my project
Hope someone has a solution for this.
Thanks
Easiest solution is to implement trait Illuminate\Auth\MustVerifyEmail which should be there, however it is not mentioned in the Laravel documentation. You can also override these methods by defining them in the model as you did. But hasVerifiedEmail and markEmailAsVerified methods should have some verification logic and return bool based on the API.
Edit:
I also forgot to mention that method sendEmailVerificationNotification should contain $this->notify(new Notifications\VerifyEmail); otherwise it won't use the Notifiable trait and thus not send any email. For more details take a look at the method in Laravel framework repository,
I am absolutely new to PHP and Laravel.
I am working on a Laravel 5.3 application and I have to use a custom web service to check the user credential so I am trying to follow this official tutorial about Adding a custom provider to handle user access: https://laravel.com/docs/5.3/authentication#adding-custom-user-providers. So, in theory it seems pretty simple but I am finding some difficulties.
As you can see in the previous tutorial as first step it modify the App\Providers\AuthServiceProvider class contained into the Laravel project.
So, I have modified my AuthServiceProvider according to the tutorial example obtaining this:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use App\Extensions\RiakUserProvider;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
// CUSTOM CODE:
Auth::provider('riak', function ($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new RiakUserProvider($app->make('riak.connection'));
});
}
}
The problem is that it can't find the App\Extension namespace, this:
use App\Extensions\RiakUserProvider;
PhpStorm signs Exstensions in red saying "Undefined Extensions namespace" so it can't use the RiakUserProvider class in my code.
Why? Do I have to add some dependencies in Composer? What is wrong? What am I missing? How can I fix this issue?
What exactly is the RiakUserProvider class?
What exactly does this code:
Auth::provider('riak', function ($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new RiakUserProvider($app->make('riak.connection'));
});
In the Laravel docs the RiakUserProvider class is just an example custom User Provider. Class is located in App\Extensions namespace, but the actual provider class content was not provided.
If you want to create a custom User Provider you should create a folder named Extensions in your App folder and create RiakUserProvider.php file containing RiakUserProvider class. This follows PSR-4 class autoloading standard.
When you create your own User Provider please make sure it implements Illuminate\Contracts\Auth\UserProvider interface.
Here is a nice step by step tutorial of creating one:
https://www.georgebuckingham.com/laravel-52-auth-custom-user-providers-drivers
I am building a notification system at the moment, and the notifications get delivered via model events. Some of the notifications are dependent on things happening with the models relationships.
Example: I have a project model that has a one:many relationship with users,
public function projectmanager() {
return $this->belongsToMany('User', 'project_managers');
}
I am wanting to monitor for changes on this relationship in my project model events. At the moment, I am doing this by doing this following,
$dirtyAttributes = $project->getDirty();
foreach($dirtyAttributes as $attribute => $value) {
//Do something
}
This is run in the ::updating event of the model but only looks at the models attributes and not any of it's relational data, is it possible get old relational data and new relational data to compare and process?
You should be using an observer class for this.
This has already been covered fairly simply and well by this SO answer, although that answer uses a slightly older method where the class itself needs to call upon its observer. The documentation for the current version (5.3 as of this answer) recommends registering the observer in your application service provider, which in your example would look similar to:
<?php
namespace App\Providers;
use App\Project;
use App\Observers\ProjectObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Project::observe(ProjectObserver::class);
}
}
For evaluating the differences between the new model values and the old values still in the relational DB, Laravel provides methods for both: getDirty() and getOriginal().
So your observer would look something like:
<?php
namespace App\Observers;
use App\Project;
class ProjectObserver
{
/**
* Listen to the Project updating event.
*
* #param Project $project
* #return void
*/
public function updating(Project $project)
{
$dirtyAttributes = $project->getDirty();
$originalAttributes = $project->getOriginal();
// loop over one and compare/process against the other
foreach ($dirtyAttributes as $attribute => $value) {
// do something with the equivalent entry in $originalAttributes
}
}
}
I have a class called Messaging and I created a facade to using it like
Messaging::getConversationMessages($conv_id, $user_id);
I have followed all the instructions in this link below
How do I create a facade class with Laravel?
This is my MessagingServiceProvider calss below which does the binding
<?php
use Illuminate\Support\ServiceProvider;
class MessagingServiceProvider extends ServiceProvider {
/**
* Register the service provider.
*
* #return void
*/
public function register() {
App::bind('messaging', function()
{
return new \Messaging\Messaging;
}
);
}
}
Below is my facade class that I created for me to use it in the way I wanted to
<?php
use Illuminate\Support\Facades\Facade;
class Messaging extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'messaging'; }
}
I have placed my MessagingServiceProvider.php inside a folder called serviceproviders inside app folder, and placed the messaging.php(the file containing the facade class) inside a folder called facade in the app folder and added them to auto load.
Below is the model class for the facade
<?php
namespace Messaging;
use Eloquent; // if you're extending Eloquent
class Messaging extends Eloquent {
...
}
After doing all this still I am getting an error "Non-static method Messaging\Messaging::getConversationMessages() should not be called statically, assuming $this from incompatible context"
You are not using your Facade. Try to namespace it and use a different name:
<?php namespace Messaging;
use Illuminate\Support\Facades\Facade;
class MessagingFacade extends Facade
{
...
}
Then you
composer dumpautoload
And try to use it this way:
Messaging\MessagingFacade::getConversationMessages()
If it works for you, you create an alias for it in app/config/app.php.
'Messaging' => 'Messaging\MessagingFacade',
And you should be able to use it as:
Messaging::getConversationMessages()
About namespaced classes, every time you need to a class from another namespace, you need to go root:
\DB::whatever();
I am trying to create model named CustomDataStore (models/custom_data_store.php) and it is extending Eloquent, so table is named as custom_data_stores, but it gives me error.
Eloquent wants table named customdatastores. Of course I can set manually table name, but how can I set such name automatically?
For it to be made automatically your model would have to be in models/custom/data/store.php
class Custom_Data_Store extends Eloquent
{
}
I have noticed that laravel's eloquent can't really "see" if there are underscores on the model's filename. I'm not really sure what's happening inside (still a newbie), but this is only based on my observation..
what I did was
I have two different models, named tblReport_date.php and tblReportdate.php, both have the same codes except that they are pointed at different tables.
tblReportdate.php code:
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class tblReportdate extends Eloquent implements UserInterface, RemindableInterface
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'tblClients';
...rest of the codes...
tblReport_date.php code:
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class tblReportdate extends Eloquent implements UserInterface, RemindableInterface
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'tblReport_date';
...rest of the codes...
on the controller, I have this code
$db = tblReportdate::all();
return View::make('db.index')->with('db', $db);
the result is that it will only load tblReportdate.php and not tblReport_date.php
I tried extracting tblReport_date.php alone and tested it.. it always returns an error, regardless of the class name, etc..and IDK why. If someone can explain this pls comment it out.. anyways, just avoid putting underscores on filenames XD