I am attempting to broadcast a message via pusher in laravel but I am getting the following error:
Symfony\Component\Debug\Exception\FatalThrowableError · Too few arguments to function
App\Providers\BroadcastServiceProvider::{closure}(), 1 passed in
laravel/framework/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php on line 77 and exactly 2
expected routes/channels.php:33App\Providers\BroadcastServiceProvider::{closure}
});
The code that it's occuring on is the following
Broadcast::channel('conversations.{id}', function ($user, $id) {
return $user->inConversation($id);
});
I have another channel and it works fine
Broadcast::channel('users.{id}', function ($user, $id){
return (int) $user->id === (int) $id;
});
Not sure why there are too few arguments
*** UPDATE ***
I'm using laravel livewire.
The event class is as follows:
class MessageAdded implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #param Message $message
*/
public function __construct(Message $message)
{
$this->message = $message;
}
public function broadcastWith()
{
return [
'message' => [
'id' => $this->message->id
]
];
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('conversations.' . $this->message->conversation->id);
}
}
The laravel livewire function is as follows:
public function reply()
{
$this->validate([
'body' => 'required'
]);
$message = $this->conversation->messages()->create([
'user_id' => auth()->id(),
'body' => $this->body
]);
$this->conversation->update([
'last_message_at' => now()
]);
foreach ($this->conversation->others as $user) {
$user->conversations()->updateExistingPivot($this->conversation, [
'read_at' => null
]);
}
broadcast(new MessageAdded($message))->toOthers();
$this->emit('message.created', $message->id);
$this->body = '';
}
Regards
Danny
Basically, the solution here was to set the Broadcast::routes in the BroadcastServiceProvider to the following
Broadcast::routes(['middleware' => 'auth']);
Related
I use mail.ru service for mailing. But when I submit for email this gives me this error
this is my .env
MAIL_MAILER=smtp
MAIL_HOST=smtp.mail.ru
MAIL_PORT=465
MAIL_USERNAME=support#domain.com
MAIL_PASSWORD=******
MAIL_ENCRYPTION=ssl
MAIL_FROM_ADDRESS=no-reply#domain.com
MAIL_FROM_NAME=Ali
this my ContactMailer.php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class ContactMailer extends Mailable
{
use Queueable, SerializesModels;
public array $data;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return
*/
public function build()
{
return $this->from('no-reply#domain.com', 'Admin')
->view('emails.contact')->with('data', $this->data);
}
}
this is my Controller method
public function send(Request $request): \Illuminate\Http\RedirectResponse
{
try {
$data = [
'header' => 'domain.com - contact',
'name' => $request->get('name'),
'email' => $request->get('email'),
'phone' => $request->get('phone'),
'message' => $request->get('message'),
];
Mail::to('support#domain.com')
->send(new ContactMailer($data));
return Redirect::back()
->with('alert','Success');
} catch (\Exception $e) {
Log::info($e);
dd($e);
return Redirect::back()
->with('alert','Fail !');
}
}
I already wrote sender in ContactMailer.php
for example I change all paramaters to my old working projects configurations. But not working yet. What I missing ?
Do you have any solutions ?
fixed by adding env key to ContactMailer.php
public function build()
{
return $this->from(env('MAIL_USERNAME'), 'Admin')
->view('emails.contact')
->with('data', $this->data);
}
I'm having trouble with sending new messages to users. I really tried a lot of things but they didn't solve the problem. I think client successfully connected to the websocket but there is no submitted message from the socket.
Here are my codes:
channels.php
Broadcast::channel('Conversations.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
}, ['guards' => ['web', 'auth']]);
MessageObserver.php
class MessageObserver
{
/**
* Handle the ConversationMessage "created" event.
*
* #param \App\Models\ConversationMessage $conversationMessage
* #return void
*/
public function created(ConversationMessage $message)
{
$conversation = $message->conversation;
$user = $conversation->other_user;
$notify = [
"to" => $user->id,
"from" => [
"id" => Auth::user()->id,
"username" => Auth::user()->username,
"name" => Auth::user()->name,
"avatar" => Auth::user()->avatar,
],
'message' => $message->message,
'attachment' => $message->attachment,
'attachment_mime' => $message->attachment_mime,
"created_at" => $message->created_at,
];
broadcast(new \App\Events\NewMessage($user->id, $notify));
}
}
App\Events\NewMessage
class NewMessage
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $to;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($to, Array $message)
{
$this->message = $message;
$this->to = $to;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn(): Channel
{
return [new PrivateChannel('Conversations.'.$this->to)];
}
public function broadcastAs()
{
return 'messages';
}
}
Lastly.. Conversation.js
window.laravelEcho.private(`Conversations.${usePage().props.value.auth.user.id}`)
.listen(`messages`, (messages) => {
console.log(messages)
})
I figured out the solution. The event class should implement Illuminate\Contracts\Broadcasting\ShouldBroadcast.
To solve my problem, i added this:
class NewMessage implements ShouldBroadcast
I would like to know how to include an attachment when sending an email using laravel and markdown.
This is the class InvoiceEmail extends Mailable
protected $data;
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from('tes#test.com')->subject('Order')->markdown('emails.invoiceEmail')->with('data',$this->data);
}
In the controller called OrderController I send the email:
$customerPDF = 'file.pdf';
$data = array(
'name' => $request->vendor_name,
'company' => $request->company,
'vat'=> $request->vat,
'category' => $request->category,
'url' => Route('vendor.reg.enable.account',$enableCode)
);
Mail::to($request->email)->send(new InvoiceEmail($data));
My question is: how can I attach the customerPDF?
Try to add attach method call to InvoiceEmail#build
public function build()
{
return $this->from('tes#test.com')
->subject('Order')
->markdown('emails.invoiceEmail')
->with('data',$this->data)
->attach(asset($this->data->pdf_file), ['mime' => 'application/pdf']);
}
I'm making an app that uses jwt as authentication system ,
when I try to update my Category model the policy always returns 403 unauthorized,
I'm using apiResource to crud my model.
my code
in api.php:
Route::apiResource('category', CategoryController::class);
in CategoryController.php:
public function update(Request $request, $id)
{
// print_r($request->all());
$validator = Validator::make(
$request->all(),
[
'name' => 'required|min:2|unique:categories,name,' . $request->id,
'description' => 'required|min:1',
],
[
"name.unique" => "اسم الصنف مستخدم مسبقا",
"name.required" => "اسم الصنف مطلوب",
"name.min" => "اسم الصنف يجب أن يحتوي على حرفين على الأقل",
"description.required" => "وصف الصنف مطلوب",
]
);
if ($validator->fails()) {
return response()->json(['errors' => $validator->messages(), 'status' => 422], 200);
}
$category = Category::find($id);
$category->name = $request->name;
$category->description = $request->description;
$category->save();
return response()->json([
"message" => "تم تحديث الصنف",
"status" => 200
], 200);
}
in CategoryPolicy.php:
public function update(User $user, Category $category)
{
return $category->user_id === $user->id;
}
It seems like the request is not even reaching the update method in CategoryPolicy.php
because even if the method always returning true it's not working :
public function update(User $user, Category $category)
{
return true;
}
any way the viewAny method is working as expected.
I'm using axios to fetch and update data and I'm sending the request with the bearer token and every thing is working ok except the issue above.
In CategoryController.php, instead of injecting $id:
public function update(Request $request, $id)
Try injecting the type-hinted model instance:
public function update(Request $request, Category $category)
And remove the find() command:
//$category = Category::find($id);
When generating new controllers, you can also use this artisan command to include type-hinted models in the function arguments.
php artisan make:controller CategoryController --api --model=Category
It's hard to see what is going wrong because it can also be the middleware and JWT token. What you could do is in your update method check if the user is logged in, add the following as the first line in the method. If false please check your JWT implementation
dd(auth()->check());
I would also suggest clean up your controller:
class CategoryController
{
/**
* CateogryController constructor.
*/
public function __construct()
{
$this->authorizeResource(Category::class); // if your are using CRUD, validate like this
}
/**
* Update specific resource.
*
* #param Category $category
* #param Request $request
* #return \Illuminate\Http\JsonResponse
*/
public function update(Category $category, CategoryRequest $request): JsonResponse
{
// notice the model route binding.
$this->authorize('update', $category); // If you only have update method, but remove the __construct.
$category->update([
'name' => $request->get('name'),
'description' => $request->get('description')
]);
return response()->json(['message' => 'تم تحديث الصنف']); // take the 200 from the headers, not add it in as text.
}
}
Your request looks similar to this:
class CategoryRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true; // you could consider to validate the user->category relation. I like it more separated and put it in a separated policy.
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|min:2|unique:categories,name',
'description' => 'required|min:1',
];
}
/**
* #return string[]
*/
public function messages()
{
return [
"name.unique" => "اسم الصنف مستخدم مسبقا",
"name.required" => "اسم الصنف مطلوب",
"name.min" => "اسم الصنف يجب أن يحتوي على حرفين على الأقل",
"description.required" => "وصف الصنف مطلوب",
];
}
}
And your policy like:
class CategoryPolicy
{
use HandlesAuthorization;
/**
* Determine if the user can update category resource.
*
* #param User $user
* #param Category $category
* #return bool
*/
public function update(User $user, Category $category): bool
{
return $user->categories()->where('id', $category->id)->exists(); // or somthing like this.
}
}
I was try to make some email to send email acticvation code when someone register. so i make it an event called UserRegistered. here's my RegisterController that call the event
public function store(Request $request){
$this->validate( $request,
[
'name' => 'required|min:3',
'username' => 'required|unique:users|min:3',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:12'
]
);
$user = User::create([
'name' => request('name'),
'email' => request('email'),
'username' => request('username'),
'password' => bcrypt(request('password')),
'token' => random(30),
]);
event(new UserRegistered($user));
return back()->with('success','Please check your email to active your account.');
}
On the UserRegistered i pass the user data like this:
class UserRegistered
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
and here's my listener:
class SendActivationCode
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param UserRegistered $event
* #return void
*/
public function handle(UserRegistered $event)
{
Mail::to($event)->send(new SendActivationMail($event));
}
}
and here the SendActivationMail class:
class SendActivationMail extends Mailable
{
use Queueable, SerializesModels;
protected $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('mails.user.activation')->with([
'name' => $this->user->name,
'token' => $this->user->token,
]);
}
}
but i got this errors:
"Type error: Argument 1 passed to App\Mail\SendActivationMail::__construct() must be an instance of App\User, instance of App\Events\UserRegistered given, called in E:\laragon\www\blog\app\Listeners\SendActivationCode.php on line 33 ◀"
My activation.blade.php:
#component('mail::message')
# Activation Code for {{ config('app.name') }}
Hi {{ $user->name }} You are recieved this because you are registered at our site. To active your account please click the link bellow.
#component('mail::button', ['url' => route('verify').$user->token])
Active Account
#endcomponent
Thanks,<br>
{{ config('app.name') }}
#endcomponent
so what can make me get this errors and how to fix it?
Looks like your SendActivatiionMail class doesn't extend Illuminate\Mail\Mailable. Try this in SendActivatiionMail.php:
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendActivatiionMail extends Mailable
{
use Queueable, SerializesModels;
...
and then in your event listener:
use App\Mail\SendActivationMail;
public function handle(UserRegistered $event)
{
Mail::to($event->user->email)->send(new SendActivationMail($event->user));
}
Your SendActivatiionCode must extends the mailable Class.
<?php
use Illuminate\Mail\Mailable;
class SendActivatiionCode extends Mailable {
...
}