How to Create Model with Notifiable Trait - laravel

I want create a Model with Notifiable feature,
First,in my controller :
$collection = collect([
[
'name' => 'user1',
'email' => 'user1#gmail.com',
],
[
'name' => 'user2',
'email' => 'user2#gmail.com',
],
[
'name' => 'user1000',
'email' => 'user1000#gmail.com',
],
]);
$u3 = new User3($collection);
when I return $u3->getEmailList(); , output is :
[{"name":"user1","email":"user1#gmail.com"},{"name":"user2","email":"user2#gmail.com"},{"name":"user1000","email":"user1000#gmail.com"}]
my class for User3 is:
namespace App;
use App\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Notification;
use Illuminate\Notifications\RoutesNotifications;
use Notifications\EmailClientOfAccount;
class User3 extends User
{
use Notifiable;
public $emailList;
public function __construct($emails)
{
$this->emailList = $emails;
}
public function getEmailList()
{
return $this->emailList;
}
public function routeNotificationForMail($notification)
{
return $this->emailList['email'];
}
}
Then, I pass $u3 to Notification as:
Notification::send($u3->getEmailList(), new
SendMailNotification($template,$subject,$request->input('mailFromTitle'),$attachments));
It show below error:
Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function routeNotificationFor() on array
can you help me for solve this problem,Please?
Thanks in Advance,
//-------------------
I correct to :
Notification::send($u3, new SendMailNotification($template,$subject,$request->input('mailFromTitle'),$attachments));
In my My Notification:
public function toMail($notifiable)
{
return new EmailTo($notifiable,$this->view,$this->topic,$this-
>mailFrom,$this->attaches);
}
and in Build():
public function build()
{
$email= $this->view($this->view);
return $email;
}
But it not work, I dont know where is mistake?

Notification send expects a Notifiable object, not the email list itself, if you change it to this, you should get further.
Notification::send($u3, new SendMailNotification($template,$subject,$request->input('mailFromTitle'),$attachments));

Related

Laravel 9, Sanctum - Authenticate using a separate table for user, email & password

I've got 3 tables for Laravel authentication.
UserMeta, UserEmail and UserPassword.
We've set it up this way so users can add multiple emails to their account, we can track password changes (&revert if necessary).
This obviously makes authentication a bit tricky and I'm wondering how I'd go about this?
I've tried making a custom Auth::attempt and it does seem to log the user in, but when I'm checking the guard via a route I get the error:
"message": "Object of type Illuminate\\Auth\\AuthManager is not callable",
when trying to access a auth:sanctum guarded route (like using the code below)
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::get('/account/me', function (\Illuminate\Http\Request $request) {
return $request->user();
});
});
Here is my LoginController.php
public function authenticate(Request $request)
{
$authenticate = new Authenticate;
$returnArray = [
'success' => false,
'message' => null,
'userId' => null,
'token' => null,
];
if (Auth::check()) {
$returnArray['message'] = 'ALREADY_LOGGED_IN';
$returnArray['userId'] = Auth::id();
} else {
$authAttempt = $authenticate->auth($request->emailAddress, $request->password)['success'];
if ($authAttempt) {
$token = $request->user()->createToken('USER AUTHENTICATION TOKEN', ['*']);
$returnArray['message'] = 'SUCCESS';
$returnArray['success'] = true;
$returnArray['userId'] = $request->user()->id;
$returnArray['token'] = $token->plainTextToken;
} else {
$returnArray['message'] = 'Invalid email address or password.';
}
}
return $returnArray;
}
And when I hit the login route:
{
"success": true,
"message": "SUCCESS",
"userId": 1,
"token": "10|0fgn5XfZyaIuaLOxOOSkIqQdqplc8G1y7SLUKyzD"
}
which does insert into the database.
Auth:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \App\Models\User\UserMeta::class,
],
Models:
App\Models\User\UserMeta:
<?php
namespace App\Models\User;
use App\Models\BaseAuthenticatableModel;
use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class UserMeta extends BaseAuthenticatableModel
{
use HasApiTokens, HasFactory, Notifiable;
protected $table = 'UserMeta';
public function emailAddressList()
{
return $this->hasMany(UserEmail::class);
}
public function emailAddressLatest()
{
return $this->hasMany(UserEmail::class)->latest()->emailAddress;
}
public function passwordList()
{
return $this->hasMany(UserPassword::class);
}
public function passwordLatest()
{
return $this->hasMany(UserPassword::class)->latest()->value;
}
UserPassword:
<?php
namespace App\Models\User;
use App\Models\BaseModel;
class UserPassword extends BaseModel
{
protected $table = 'UserPassword';
public function user()
{
return $this->belongsTo(UserMeta::class);
}
}
UserEmail
<?php
namespace App\Models\User;
use App\Models\BaseModel;
class UserEmail extends BaseModel
{
protected $table = 'UserEmail';
public function user()
{
return $this->belongsTo(UserMeta::class);
}
}
I've been stuck on this for a few days - tried using Passport, JWT & Sanctum but I'm now really at a loss.
Thank you

Larave 6 - pivot table sync - fire created event only if the attached user is new

I have following code:
$clinic->users()->sync($sync);
Which will go to this class (sync is working):
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class ClinicUser extends Pivot
{
protected $table = 'clinic_user';
static function boot()
{
parent::boot();
static::created(function($item) {
$user = \App\User::find($item->users_id);
$clinic = \App\Models\Clinic::find($item->clinics_id);
if($user->userData->notification_email == 1)
\Mail::to($user->email)->send(new \App\Mail\ClinicManagerAdded(
$user,
$clinic));
if($user->userData->notification_app == 1)
\App\Notification::create([
'title' => "message",
'body' => "message",
'user_id' => $user->id,
]);
});
}
}
Is it possible to fire created method only to the new users (does which weren't detached)?
What i was suggesting is not that robust, infact you need to do
$clinic->users()->detach($sync->pluck('id'));
$clinic->users()->sync($sync);
Every time, and you need to remember it (and so is not robust).
What i feel to suggest you to do is something like this:
Delete the notification in the Model
Create a Service for this operation, let's call it NotyfyUsersNewClinicService (maybe you will find a better name):
<?php
namespace App;
use ...;
class NotyfyUsersNewClinicService{
public __constructor(){}
public updateUsers(Clinic& $clinic, Collection& $newUsers){
$clinic->users->diff($newUsers)->each(function(User $users){
$user->userData->notification_email = true;
\Mail::to($user->email)->send(new \App\Mail\ClinicManagerAdded(
$user,
$clinic));
});
$clinic->users()->sync($sync);
}
}
then you will only need to use this:
(new NotyfyUsersNewClinicService())->updateUsers($clinic, $users);
Note: better if you move the email to a job and send it using queue:work
If someone has a similar problem, I have managed to resolve this by creating the static variable, and fill this variable in the deleted event, like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class ClinicUser extends Pivot
{
protected $table = 'clinic_user';
static $ids = [];
static function boot()
{
parent::boot();
static::deleted(function($item){
self::$ids[] = $item->users_id;
});
static::created(function($item){
if(!\in_array($item->users_id, self::$ids)){
$user = \App\User::find($item->users_id);
$clinic = \App\Models\Clinic::find($item->clinics_id);
if($user->userData->notification_email == 1)
\Mail::to($user->email)->send(new \App\Mail\ClinicManagerAdded(
$user,
$clinic));
if($user->userData->notification_app == 1)
\App\Notification::create([
'title' => "new message",
'body' => "<p>body</p>",
'user_id' => $user->id,
]);
}
});
}
}

Pass variable from controller to notification in Laravel

I am finding it hard to understand the examples from the docs to the scenario I am having. In my project I have an application form which filled up by the user then admin will update that form once the application is approved, canceled etc.
Now I want to notify the user that her/his application has been approved, canceled etc.
in my controller:
public function update(Request $request, $id)
{
$this->validate($request, [
'status' => 'required'
]);
$requestData = $request->all();
$loanapplication = LoanApplication::findOrFail($id);
$loanapplication->update([
"status" => $request->status,
"admin_notes" => $request->admin_notes,
"date_approval" => $request->date_approved
]);
if($request->notifyBorrower = 'on') {
$user_id = $loanapplication->user_id;
$status = $request->status;
$this->notify(new AdminResponseToApplication($user_id));
}
return redirect()->back()->with('flash_message', 'LoanApplication updated!');
}
In my AdminResponseToApplication.php I like to achieve this
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class AdminResponseToApplication extends Notification implements ShouldQueue
{
use Queueable;
public function __construct()
{
//
}
public function via($notifiable)
{
return ['mail','database'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line(.$user->nameHere. 'your application has been '.$statusHere.'.')
->action('check it out', url('/'))
->subject('Regarding with your loan application')
->line('This is system generated. Do not reply here.');
}
public function toDatabase($notifiable)
{
return [
'user_id' => $user->nameHere,
'status' => $statusHere,
'title' => .$user->nameHere. 'your application has been '.$statusHere.'.',
'url' => '/'
];
}
}
How can I achieve that? Thank you in advance!
Get user object and call function notify() on it. $this->notify() will not work because $this is not an instance of User class.
$user = User::find($user_id);
$user in the $user->notify(new AdminResponseToApplication($data)) function is available in notification class as $notifiable.
You can get any value of that object using $notifiable->name etc.
Remember:
AdminResponseToApplication is a class and you can do anything with it that a php class can.
So you can pass as many variables as you want to AdminResponseToApplication class in constructor and do what you want.
$user->notify(new AdminResponseToApplication($data))
As shown above I am sending a $data object to the class which is available in the constructor.
In the class
class AdminResponseToApplication extends notification implements ShouldQueue{
use Queueable;
public $myData;
public function __construct($data)
{
$this->myData = $data; //now you have a $data copied to $this->myData which
// you can call it using $this->myData in any function of this class.
}
}

Problem with overwrite User3::all() method in User Mode

I have a User Model as:
<?php
namespace App;
use App\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Notification;
use Illuminate\Notifications\RoutesNotifications;
use Notifications\EmailClientOfAccount;
class User3 extends User
{
use Notifiable;
public $emailList;
protected $fillable = [
'name', 'email',
];
public function __construct($emails)
{
$this->emailList = $emails;
}
public function getEmailList()
{
return $this->emailList;
}
public static function all(array $columns=[])
{
return $emailList;
}
public function routeNotificationForMail($notification)
{
return $this->email;
}
}
Then,and in Controller:
$collection = collect([
[ 'name' => 'user1', 'email' => 'user1#gmail.com', ], [ 'name' => 'user2',
'email' => 'user2#gmail.com', ], [ 'name' => 'user1000', 'email' =>
'user1000#gmail.com', ],
]);
Second Stage:
$u4 = new User3($collection);
when I use :
dd($u4::all());
It show below error:
ErrorException: Declaration of App\User3::all(array $columns = Array)
should be compatible with
Illuminate\Database\Eloquent\Model::all($columns = Array)
I very try for solve it, but dont,
very Thanks for any help to me,
reference from: Laravel error "Declaration of model/model_name should be compatible with Illuminate\Database\Eloquent\Model"
When overriding a method from parent class - the signature of the method must be exactly the same in terms of parameters and their types
In the parent class, both $attributes and $options are set to be of type array, so you must also set set them this way in your class
namespace App\Models;
class User extends \Illuminate\Database\Eloquent\Model {
...
public function update(array $attributes = [], array $options = []) {
// ... your implementation
return parent::update($attributes, $options);
}
...
}
It show below error: ErrorException: Declaration of App\User3::all (array $columns = Array) should be compatible with Illuminate\Database\Eloquent\Model::all ($columns = Array)
Check that potions. they are not same. May be this is the reason. focus on this may helps you.

Laravel: One to Many Poly relation not updating automatically

3 types of posts: Personal, Business & Nature.
Below is the Post Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([
'Personal' => 'App\Personal',
'Business' => 'App\Business',
'Nature' => 'App\Nature',
]);
class Post extends Model
{
public function postable()
{
return $this->morphTo();
}
}
Below is the Personal Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Personal extends Model
{
public function posts()
{
return $this->morphMany(Post::class,'postable');
}
}
Likewise Busines & Nature models.
When I manually enter the data in phpMyAdmin, the tinker shows the result as required, but when I create a post from front-end (via form), the posts table remains unchanged.
I tried googling, but nothing works! :(
Below is the PersonalController
public function create()
{
if(Auth::guest()){
return redirect()->route('login');
}
$sectors = Sector::all();
$cities = City::all();
$ranges = Range::all();
return view('front.personal-register',compact('sectors','cities','ranges'));
}
public function store(Request $request)
{
$this->validate($request,[
"sectors" => "required",
"cities" => "required",
"ranges" => "required",
"g-recaptcha-response" => "required|captcha"
]);
$franchisee = new Personal;
$franchisee->user_id = Auth::user()->id;
$franchisee->save();
$franchisee->sectors()->sync($request->sectors);
$franchisee->cities()->sync($request->cities);
$franchisee->ranges()->sync($request->ranges);
return redirect(route('personal.index'))->with('message','Thank You! Your post has been added');
}

Resources