Listeners and Events get error: Too few arguments to function App\Events\User\Created::__construct(), - laravel

I need have two Listeners in same event, and when an user has been created in the system, Lavarel send my an email with the credentials and another to assign roles of users. It's possible have two listeners in same event? Why does the system show me this message?
When I create an user the system show me:
Too few arguments to function App\Events\User\Created::__construct(), 1 passed in C:\xampp\htdocs\bwm\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasEvents.php on line 205 and exactly 2 expected
This is my Event:
class UserCreated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
public $password;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($user,$password)
{
$this->user = $user;
$this->password = $password;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
This is my Listener Assign Roles:
class AssignRoles
{
private $request;
/**
* Create the event listener.
*
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Handle the event.
*
* #param Created $event
* #return void
*/
public function handle(UserCreated $event)
{
$event->user;
switch($role = $this->request->role)
{
case $role == 'Asesor':
$event->user->assignRole('Asesor');
$asesoria = Asesoria::orderby('created_at', 'desc')->first();
$asesoria->user_id = $event->user->id;
$asesoria->published = true;
$asesoria->update();
break;
case $role == 'Comprador':
$event->user->assignRole('Comprador');
break;
default:
$event->user->assignRole('Writer');
}
}
}
This is my Listener Send Login Credentials:
class SendLoginCredentials
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param Created $event
* #return void
*/
public function handle(UserCreated $event)
{
Mail::to($event->user)->queue(
new LoginCredentials($event->user, $event->password)
);
}
}
In my function store of my UsersController I call to dispach:
UserCreated::dispatch($user, $password);
In my EventServiceProvider I have this:
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
'App\Events\User\UserCreated' => [
'App\Listeners\User\AssignRoles',
'App\Listeners\SendLoginCredentials',
],
];

You have two parameters in your constructor of UserCreated class and you are passing only one because you are dispatching it wrong way.
you can do it several ways:
Event::dispatch(new UserCreated($user, $password))
event(new UserCreated($user, $password))
Try these. Hope it works

I had a protected $dispachesEvents in User Model:
protected $dispatchesEvents = ['created' => 'App\Events\User\Created'];
That's why I got the error:
Too few arguments to function App\Events\User\Created::__construct(), 1 passed in C:\xampp\htdocs\bwm\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasEvents.php on line 205 and exactly 2 expected
I deleted it, and put the call to the dispacher in my RegisterController.
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
//'password' => Hash::make($data['password']), //mutador en User model
'password' => $data['password'],
'surname1' => $data['surname1'],
'surname2' => $data['surname2'],
'comunidad_id' => $data['cbx_comunidad'],
'provincia_id' => $data['cbx_provincia'],
'municipio_id' => $data['cbx_municipio'],
]);
//dd($data['password']);
event(new Created($user,$data['password']));
return $user;
}
As I had a protected $dispatchesEvents in User Model,this it executes before that my call in the RegisterController.

Related

Am I overcomplicating events/listeners/notifications?

I'm not sure if I'm overcomplicating events/listeners/notifications in Laravel, but it feels like maybe I am, and I'm getting some unexpected results, although technically it's working.
My basic structure is this:
MonthlySummaryCompletedEventis fired.
The HandleMonthlySummaryCompletedEvent listener listens for the event.
It triggers a SendMonthlySummaryCreatedNotification notification.
This is all working (locally at least), except for 2 things:
I've had to put in a 5 second sleep in my livewire component that receives the notification because of timing issues. It almost seems like the pusher notification arrives before the notification has been written to the database.
It appears that 2 messages are sent to pusher:
Here's the code for my event:
class MonthlySummaryCompletedEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public User $requestedBy;
public string $fileDownloadUrl;
public string $fileName;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($event, string $fileDownloadUrl, string $fileName)
{
$this->requestedBy = $event->requestedBy;
$this->fileDownloadUrl = $fileDownloadUrl;
$this->fileName = $fileName;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('users.' . $this->requestedBy->id);
}
}
here's the code for my listener:
class HandleMonthlySummaryCompletedEvent implements ShouldQueue
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param object $event
* #return void
*/
public function handle($event)
{
Notification::send($event->requestedBy, new SendMonthlySummaryCreatedNotification($event));
}
}
and here's the code for the notification:
class SendMonthlySummaryCreatedNotification extends Notification implements ShouldQueue, ShouldBroadcast
{
use Queueable;
public $fileDownloadUrl;
public $fileName;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($event)
{
$this->fileDownloadUrl = $event->fileDownloadUrl;
$this->fileName = $event->fileName;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database', 'broadcast'];
}
/**
* Get the broadcastable representation of the notification.
*
* #param mixed $notifiable
* #return BroadcastMessage
*/
public function toBroadcast($notifiable)
{
Log::debug($notifiable->toArray());
return new BroadcastMessage([
'title' => 'Monthly Summary Complete',
'message' => "{$this->fileName} is ready. ",
'link' => $this->fileDownloadUrl,
'link_text' => 'Click here to download',
'show_toast' => true,
'user_id' => $notifiable->id
]);
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toDatabase($notifiable)
{
return [
'title' => 'Monthly Summary Complete',
'message' => "{$this->fileName} is ready. ",
'link' => $this->fileDownloadUrl,
'link_text' => 'Click here to download',
'show_toast' => true,
'user_id' => $notifiable->id
];
}
}
And here's my front end livewire component:
public function getListeners()
{
return [
"echo-private:users.{$this->user->id},StatementCompleted" => 'notifyUser',
"echo-private:users.{$this->user->id},MonthlySummaryCompletedEvent" => 'notifyUser',
];
}
public function mount()
{
$this->user = Auth::user();
$this->refreshNotifications();
$this->showNotificationsBadge = ($this->notificationCount > 0) ? true : false;
}
public function render()
{
return view('livewire.components.notifications');
}
public function notifyUser()
{
$this->showNotificationsBadge = true;
sleep(5);
$this->refreshNotifications();
$message = $this->notifications->first()->data['message'];
if (isset($this->notifications->first()->data['show_toast']) && $this->notifications->first()->data['show_toast'] == true) {
$this->dispatchBrowserEvent('triggerToast', [Helper::notification('Success', $message)]);
}
}

Laravel: Using policy on FormRequest always returns false

I'm trying to authorize whether a user is allowed to invite other users.
InvitedUserController
public function store(InvitedUserRequest $request)
{
$data = $request->all();
$data['user_id'] = auth()->user()->id;
$data['account_id'] = $request->session()->get('account_id');
InvitedUser::create($data);
}
I created a FormRequest class to handle validation:
class InvitedUser extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize(Request $request)
{
$account = Account::find($request->session()->get('account_id'));
return $this->user()->can('manageUsers', $account);
}
/**
* Validation error message
*/
public function messages() {
return [
'max' => 'You may only enter up to :max characters'
];
}
public function invalid() {
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required|max:255|email',
'role_id' => 'required|exists:roles,id',
];
}
}
Then my policy to handle authorization:
class InvitedUserPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\User $user
* #return mixed
*/
public function manageUsers(User $user, Account $account)
{
dd('test');
$role = $user->roles()->wherePivot('account_id', $account->id)->first();
return $role->manage_users;
}
}
I registered the policy:
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
'App\InvitedUser' => 'App\Policies\InvitedUserPolicy'
];
For some reason, that dd() call doesn't even occur. So it's not reaching my policy and all requests are returning unauthorized.
even if i changed my policy to return true
public function manageUsers(User $user, Account $account)
{
return true;
}
I would still get unauthorized
How Can I call my policy from a FormRequest? Why is this not working?
So, while this is confusing to me, I've figured out the issue.
I needed to change my registered policies to the following:
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
'App\Account' => 'App\Policies\InvitedUserPolicy'
];
It's using the Account model instead of InvitedUser model. I think because that's what I'm passing in as a model?

Login log laravel 5

I wanted to create user logs but something does not work for me.
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
LogSuccessfulLogin.php
class LogSuccessfulLogin
{
/**
* Create the event listener.
*
* #param Request $request
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Handle the event.
*
* #param Login $event
* #return void
*/
public function handle()
{
Event::listen('auth.login', function ($user, $remember) {
$user->update([
'last_login' => \Carbon\Carbon::now(),
'ip_address' => \Request::ip()
]);
});
}
}
I read many tutorials but did not help
You are telling Laravel to listing to the login event here:
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
Listening to the event within the handle statement is incorrect. The event has already been triggered.
If you remove the Event::listen from your handle method, it should work.
/**
* Handle the event.
*
* #param Login $event
* #return void
*/
public function handle()
{
$this->user->update([
'last_login' => \Carbon\Carbon::now(),
'ip_address' => \Request::ip()
]);
}

Trying to get property of non-object. Error in laravel

I'm kinda new at laravel and need your help.
I have this IR model :
class IR extends Model
{
//
protected $fillable=['irnum','date','subject','cause','facts','as','at','rec','user_id'];
protected $casts=['user_id'=>'int'];
public function user()
{
return $this->belongsTo(user::class);
}
public static $rules =array (
'date'=>'required',
'status'=>'required|min:10',
'cause' => 'required|min:10',
'facts' => 'required|min:10',
'ir-as' => 'required|min:10',
'rec' => 'required|min:10',
'ir-at' => 'required|min:10',
);
}
and route:
Route::group(['middleware' => ['web']], function () {
Route::get('/', function () {
return view('welcome');
})->middleware('guest');
Route::resource('tasks','TaskController');
Route::get('ir',function ()
{
return View::make('tasks/ir');
});
Route::resource('irs','IRController');
Route::auth();
});
and this is my controller :
class IRController extends Controller
{
/**
* The task repository instance.
*
* #var TaskRepository
*/
protected $irs;
/**
* Create a new controller instance.
*
* #param TaskRepository $tasks
* #return void
*/
public function __construct(IRRepository $irs)
{
$this->middleware('auth');
$this->irs = $irs;
}
/**
* Display a list of all of the user's task.
*
* #param Request $request
* #return Response
*/
public function index(Request $request)
{
return view('tasks.ir',[
'irs' => $this->irs->forUser($request->user()),
]);
}
/**
* Create a new task.
*
* #param Request $request
* #return Response
*/
public function create()
{
return View::make('irs.create');
}
public function store(Request $request)
{
$request->user_id=Auth::user()->id;
$input =$request->all();
$validation=Validator::make($input, IR::$rules);
if($validation->passes())
{
IR::create($input);
return Redirect::route('tasks.ir');
}
return Redirect::route('tasks.ir')
->withInput()
->withErrors($validation)
->with('message','There were validation errors.');
}
/**
* Destroy the given task.
*
* #param Request $request
* #param Task $task
* #return Response
*/
public function destroy(Request $request, IR $irs)
{
}
}
I really dont know what causes to throw this error.
Error throws when i add Incident report.
Pls help.
New at laravel
You're saying you get an error when you're trying to add an incident report or IR, so I assume problem is in a store() action.
I can see only one potential candidate for this error in a store() action:
Auth::user()->id;
Add dd(Auth::user()); before this clause and if it will output null, use check() method, which checks if any user is authenticated:
if (Auth::check()) {
Auth::user->id;
}

Laravel 5 FormRequest validator with multiple scenarios

I would like to ask how should I handle validation on multiple scenarios using FormRequest in L5? I know and I was told that I can create saparate FormRequest files to handle different validations but it is very redundant and also noted that I would need to inject it into the controller manually using the use FormRequest; keyword. What did previously in L4.2 is that I can define a new function inside my customValidator.php which then being called during controller validation via trycatch and then the data is being validated by service using the below implementation.
class somethingFormValidator extends \Core\Validators\LaravelValidator
{
protected $rules = array(
'title' => 'required',
'fullname' => 'required',
// and many more
);
public function scenario($scene)
{
switch ($scene) {
case 'update':
$this->rules = array(
'title' => 'required',
'fullname' => 'required',
// and other update validated inputs
break;
}
return $this;
}
}
Which then in my LaravelValidator.php
<?php namespace Core\Validators;
use Validator;
abstract class LaravelValidator {
/**
* Validator
*
* #var \Illuminate\Validation\Factory
*/
protected $validator;
/**
* Validation data key => value array
*
* #var Array
*/
protected $data = array();
/**
* Validation errors
*
* #var Array
*/
protected $errors = array();
/**
* Validation rules
*
* #var Array
*/
protected $rules = array();
/**
* Custom validation messages
*
* #var Array
*/
protected $messages = array();
public function __construct(Validator $validator)
{
$this->validator = $validator;
}
/**
* Set data to validate
*
* #return \Services\Validations\AbstractLaravelValidator
*/
public function with(array $data)
{
$this->data = $data;
return $this;
}
/**
* Validation passes or fails
*
* #return Boolean
*/
public function passes()
{
$validator = Validator::make(
$this->data,
$this->rules,
$this->messages
);
if ($validator->fails())
{
$this->errors = $validator->messages();
return false;
}
return true;
}
/**
* Return errors, if any
*
* #return array
*/
public function errors()
{
return $this->errors;
}
}
and then finally this is how i call the scenarios inside services like this
public function __construct(somethingFormValidator $v)
{
$this->v = $v;
}
public function updateSomething($array)
{
if($this->v->scenario('update')->with($array)->passes())
{
//do something
else
{
throw new ValidationFailedException(
'Validation Fail',
null,
$this->v->errors()
);
}
}
So the problem is now since i have migrated to L5 and L5 uses FormRequest, how should I use scenario validation in my codes?
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
class ResetpasswordRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'login_email' => 'required',
'g-recaptcha-response' => 'required|captcha',
];
}
public function messages()
{
return [
'login_email.required' => 'Email cannot be blank',
'g-recaptcha-response.required' => 'Are you a robot?',
'g-recaptcha-response.captcha' => 'Captcha session timeout'
];
}
public function scenario($scene)
{
switch ($scene) {
case 'scene1':
$this->rules = array(
//scenario rules
);
break;
}
return $this;
}
}
also how should I call it in the controller?
public function postReset(ResetpasswordRequest $request)
{
$profile = ProfileService::getProfileByEmail(Request::input('login_email'));
if($profile == null)
{
$e = array('login_email' => 'This email address is not registered');
return redirect()->route('reset')->withInput()->withErrors($e);
}
else
{
//$hash = ProfileService::createResetHash($profile->profile_id);
$time = strtotime('now');
$ip = Determinator::getClientIP();
MailProcessor::sendResetEmail(array('email' => $profile->email,
'ip' => $ip, 'time' => $time,));
}
}
I believe the real issue at hand is everything is validated through the form request object before it reaches your controller and you were unable to set the appropriate validation rules.
The best solution I can come up with for that is to set the validation rules in the form request object's constructor. Unfortunately, I am not sure how or where you are able to come up with the $scene var as it seems to be hard-coded in your example as 'update'.
I did come up with this though. Hopefully reading my comments in the constructor will help further.
namespace App\Http\Requests;
use App\Http\Requests\Request;
class TestFormRequest extends Request
{
protected $rules = [
'title' => 'required',
'fullname' => 'required',
// and many more
];
public function __construct()
{
call_user_func_array(array($this, 'parent::__construct'), func_get_args());
// Not sure how to come up with the scenario. It would be easiest to add/set a hidden form field
// and set it to 'scene1' etc...
$this->scenario($this->get('scenario'));
// Could also inspect the route to set the correct scenario if that would be helpful?
// $this->route()->getUri();
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return $this->rules;
}
public function scenario($scene)
{
switch ($scene) {
case 'scene1':
$this->rules = [
//scenario rules
];
break;
}
}
}
You can use laratalks/validator package for validation with multiple scenarios in laravel. see this repo

Resources