I am SwiftMailer with Laravel 4 to send emails.
It works fine, but it takes about 5 seconds to send a single mail.
It is possible somehow to speed up the process?
Thank you!
EDIT: I Would like to use the queue in this function:
public function send()
{
$self = $this;
return \Mail::queue($this->view, $this->data, function($message) use($self)
{
$message->to($self->email)->subject($self->subject);
});
}
I have created an account in iron.io and inserted into queue.php the project_id and the token. What i have to insert in this case as queue-name?
Use Queues: http://laravel.com/docs/queues
It's pretty easy to setup IronMQ in Laravel: http://iron.io/
This is a screencast from Taylor showing it: http://vimeo.com/64703617
Related
I ask this question while I have done researches to find clear solution for this problem but many of available answers are just how to use Laravel Scheduler itself!
So I am creating a simple website with Laravel to let users create reminders for themselves.Users can receive reminder either on their Emails or if they are logged in, they receive a notification alert something like Facebook Notifications.
I am not sure if I am following the right path or not but I'm using Laravel Scheduler to send reminders to each specific user.
I also use Events in the Laravel to push recent changes every 1 minute to users but my problem is, all users receive same notification. For example if I want to remind an appointment to Mr X, Ms Y also receives same exact notification!!!
At this point, I have two questions:
1 - Is using Laravel Scheduler a good idea for this project or not? If not then what technology or method is recommended?
2 - If I have to use Laravel Scheduler for this project, so how can I send notification to related user? (I cannot use User ID as Laravel Scheduler is running by server itself and not users!)
I also attached my codes to show you what I have up to this point and I know the method I used in Laravel Channels Broadcast is somehow wrong but I just tried it!If anyone knows the answer please help me. Thank you
Laravel Scheduler - Command - Handle Function
public function handle()
{
$reminders = Note::whereTime('task_date', '<=', Carbon::now()->addMinutes(30))
->WhereTime('task_date', '>', Carbon::now()->subMinutes(30))->get();
foreach ($reminders as $reminder) {
if (!$reminder->notified) {
Note::find($reminder->id)
->update(['notified' => 1]);
event(new RemindUsers($reminder));
dd($reminder->title);
}
}
}
Laravel Event
public $reminder;
public function __construct($reminder)
{
$this->reminder = $reminder;
}
public function broadcastOn()
{
return new PrivateChannel('remind.'.$this->reminder->user_id);
}
public function broadcastWith () {
return [
'reminders' => $this->reminder
];
}
Laravel Channels
Broadcast::channel('remind.{id}', function ($user, $id) {
$notes = Note::where('user_id', $id)->get();
foreach ($notes as $note) {
return $user->id === $note->user_id;
}
});
Vue JS Code - Echo Method
data () {
return {
user: 1
}
},
CatchReminders () {
Echo.private(`remind.${this.user}`)
.listen('RemindUsers', (response) => {
this.$toast.info(`${response.reminders.title}`)
})
}
I have a unit test with the following:
use \Illuminate\Notifications\DatabaseNotification;
public function testMailSentAndLogged()
{
Notification::fake();
$user = factory(User::class)->create();
$emailAddress = $user->emailAddress;
$emailAddress->notify(new UserCreated);
Notification::assertSentTo(
$emailAddress,
UserCreated::class
);
error_log('DatabaseNotification '.print_r(DatabaseNotification::get()->toArray(), 1));
$this->assertEquals(1, $emailAddress->notifications->count());
}
My Notification has this for the via():
public final function via($notifiable)
{
// complex logic...
error_log('mail, database');
return ['mail', 'database'];
}
The code fails on the $this->assertEquals code. the error_log produces the following:
[03-Jan-2018 01:23:01 UTC] mail, database
[03-Jan-2018 01:23:01 UTC] DatabaseNotification Array
(
)
WHY don't the $emailAddress->notifications pull up anything? Why doesn't DatabaseNotification::get() pull anything?;
In your test, you are calling the method
Notification::fake();
As stated in Laravel's documentation on Mocking,
You may use the Notification facade's fake method to prevent
notifications from being sent.
Actually, this bit of code is the assertion that the Notification would have been sent, under normal circumstances (ie in prod) :
Notification::assertSentTo();
If you remove the call to Notification::fake(), your notification should appear in your testing database.
So you kinda have two solutions. The first one is to remove the call to fake(), thus really sending the notification, which will appear in the database. the second is not to test if the notification was written successfully in the database : it's Laravel's responsibility, not your application's. I recommand the second solution :)
I've an application that sends a mail to list of emails after submit the form. For this I'm using queue jobs to send mail to that list in the background. I'm using SMTP for this with mailtrap. I'm new to this queue jobs functionality.
this is my controller code to dispatch queue:
public function sendMail(Request $request)
{
$lists = List::where('list_id',$request->list_id)->pluck('email')->toArray();
$jobs = (new SendEmailToList($lists));
$this->dispatch($jobs);
return 'success';
}
And this is my job functionality in queue :
public function handle()
{
$lists = $this->lists;
Mail::send('email.test', array('email' => 'Sample'), function ($message) use ($lists) {
$message->to($lists);
});
}
I've a program file in the supervisor of my Linux system to queue:listen.
I've done all things but still it's not sending mail to all the list of emails. I've referred many of documentations but still same issue, all the documents given that to implement a QueueManager.
You should probably call Mail::queue or Mail::later instead of Mail::send.
Please refer to Mail documentation in case you've been missing something else.
I have the following code in 'saved' model event:
Session::flash('info', 'Data has been saved.')`
so everytime the model is saved I can have a flash message to inform users. The problem is, sometimes I just need to update a field like 'status' or increment a 'counter' and I don't need a flash message for this. So, is it possible to temporarily disable triggering the model event? Or is there any Eloquent method like $model->save() that doesn't trigger 'saved' event?
Solution for Laravel 8.x and 9.x
With Laravel 8 it became even easier, just use saveQuietly method:
$user = User::find(1);
$user->name = 'John';
$user->saveQuietly();
Laravel 8.x docs
Laravel 9.x docs
Solution for Laravel 7.x, 8.x and 9.x
On Laravel 7 (or 8 or 9) wrap your code that throws events as per below:
$user = User::withoutEvents(function () use () {
$user = User::find(1);
$user->name = 'John';
$user->save();
return $user;
});
Laravel 7.x docs
Laravel 8.x docs
Laravel 9.x docs
Solution for Laravel versions from 5.7 to 6.x
The following solution works from the Laravel version 5.7 to 6.x, for older versions check the second part of the answer.
In your model add the following function:
public function saveWithoutEvents(array $options=[])
{
return static::withoutEvents(function() use ($options) {
return $this->save($options);
});
}
Then to save without events proceed as follow:
$user = User::find(1);
$user->name = 'John';
$user->saveWithoutEvents();
For more info check the Laravel 6.x documentation
Solution for Laravel 5.6 and older versions.
In Laravel 5.6 (and previous versions) you can disable and enable again the event observer:
// getting the dispatcher instance (needed to enable again the event observer later on)
$dispatcher = YourModel::getEventDispatcher();
// disabling the events
YourModel::unsetEventDispatcher();
// perform the operation you want
$yourInstance->save();
// enabling the event dispatcher
YourModel::setEventDispatcher($dispatcher);
For more info check the Laravel 5.5 documentation
There is a nice solution, from Taylor's Twitter page:
Add this method to your base model, or if you don't have one, create a trait, or add it to your current model
public function saveQuietly(array $options = [])
{
return static::withoutEvents(function () use ($options) {
return $this->save($options);
});
}
Then in you code, whenever you need to save your model without events get fired, just use this:
$model->foo = 'foo';
$model->bar = 'bar';
$model->saveQuietly();
Very elegant and simple :)
Call the model Object then call unsetEventDispatcher
after that you can do whatever you want without worrying about Event triggering
like this one:
$IncidentModel = new Incident;
$IncidentModel->unsetEventDispatcher();
$incident = $IncidentModel->create($data);
To answer the question for anyone who ends up here looking for the solution, you can disable model listeners on an instance with the unsetEventDispatcher() method:
$flight = App\Flight::create(['name' => 'Flight 10']);
$flight->unsetEventDispatcher();
$flight->save(); // Listeners won't be triggered
In laravel 8.x :
Saving A Single Model Without Events
Sometimes you may wish to "save" a given model without raising any events. You may accomplish this using the saveQuietly method:
$user = User::findOrFail(1);
$user->name = 'Victoria Faith';
$user->saveQuietly();
See Laravel docs
In laravel 7.x you can do that as easy as
use App\User;
$user = User::withoutEvents(function () {
User::findOrFail(1)->delete();
return User::find(2);
});
See more in Laravel 7.x Muting Events documentation
You shouldnt be mixing session flashing with model events - it is not the responsibility of the model to notify the session when something happens.
It would be better for your controller to call the session flash when it saves the model.
This way you have control over when to actually display the message - thus fixing your problem.
Although it's a long time since the question, I've found a way to turn off all events at once. In my case, I'm making a migration script, but I don't want any event to be fired (either from Eloquent or any other).
The thing is to get all the events from the Event class and remove them with the forget method.
Inside my command:
$events = Event::getRawListeners();
foreach ($events as $event_name => $closure) {
Event::forget($event_name);
}
The only thing that worked for me was using the trait WithoutEvents. This will be executed inside the setUp method and does prevent any dispatch you have added to the code.
I've integrated ironMQ push queues in my Laravel 4 app for longer running processes. I have some views that perform a $.get that might take 30 seconds. I wanted to see what others are doing to easily get notified when ironMQ is done pushing back to an endpoint.
An example of what I will be doing with push queues mostly:
public function getCompletedTasks() {
$user = User::find(Auth::user()->id);
Queue::push(function($job) use ($user) {
$recent = new Recent;
$tasks = $recent->getCompletedTasks($user);
// append data from $tasks to DOM
// here's where I want to receive my notification
});
}
Here I am just getting tasks from an API that match data from user.
I know I can store the response data to a database and use AJAX long polling to constantly check for the data but it seems like too much work for most situations I will need to do this. I don't know much about websockets. What types of things have you guys done in these situations? And if you have any examples that would be very helpful. Thanks.
UPDATE: Solved the issue using Pusher. See my answer.
I was able to solve my problem with the help of Pusher. Here's what I did:
Setup my Iron MQ push queue as normal. In routes.php:
Route::post('queue/push', function() {
return Queue::marshal();
});
Installed pusher laravel package.
In my controller then I Queue::push my data. Inside the closure I trigger a new Pusher channel. This will obviously only trigger when the data has been returned from IronMQ.
public function getCompletedTasks() {
$user = User::find(Auth::user()->id);
Queue::push(function($job) use ($user) {
$recent = new Recent;
$tasks = $recent->getCompletedTasks($user);
$pusher = new Pusher('xxx', 'xxx', 'xxx');
$pusher->trigger('reports', 'get_completed_tasks', array('tasks' => $tasks));
$job->delete();
});
});
Next in my view I call my AJAX function with no callback since I won't be doing anything else just yet:
$.get('account/tasks/completed');
Next in my view I initialize Pusher, subscribe to the event and bind get_completed_tasks to the Pusher channel. Now we just wait for a response from Pusher which will then allow me to perform the latter part of my original AJAX request:
{{ HTML::script('//js.pusher.com/2.1/pusher.min.js') }}
<script>
var pusher = new Pusher('xxx');
var channel = pusher.subscribe('reports');
channel.bind('get_completed_tasks', function(data) {
// do something with the data returned
});
</script>
Once I used Pusher in my app, the rest was a breeze. Hope this helps someone!