How can I use queue on custom class in laravel? - laravel

In laravel 5.5 I was making an SMS service
SMS::to("xxxx")->send(new WelcomeSms());
or
WelcomeSms::message("xxx")->sendTo("xxx");
in here I want to use queue. When I call sendTo it must be work with queue. How can I do that?

All about Queues in Laravel you can read in the documentation. You need to generate Queue Job and dispatch SmsMessage from a controller:
SmsMessage Class:
class SmsMessage {
private $number;
private $message;
public function getNumber(): ?string {
return $this->number;
}
public function setNumber(string $number) {
$this->number = $number
}
public function getMessage(): ?string {
return $this->message;
}
public function setMessage(string $message) {
$this->message = $message
}
}
Controller:
Then from a controller method dispatch some data and put it on the queue:
class SmsController extends Controller
{
/**
* Send new sms
*
* #param Request $request
* #return Response
*/
public function send(Request $request)
{
// Some code here
$smsMessage = new SmsMessage();
$smsMessage->setNumber('xxx');
$smsMessage->setMessage('Lorem ipsum ...');
SendSms::dispatch($smsMessage);
}
}
SmsQueueJob Class:
php artisan make:job SmsQueueJob
It will generate a simple skeleton class:
class SmsQueueJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $smsMessage;
/**
* Create a new job instance.
*
* #param SmsMessage $smsMessage
* #return void
*/
public function __construct(SmsMessage $smsMessage)
{
$this->smsMessage= $smsMessage;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
// Here send the SMS message
SMS::to($sms->getNumber())->send(new WelcomeSms());
}
}
You can generate new queue, new connection for this queue
To run queue worker run command below:
php artisan queue:work
In production environment you should run this command as a Cron Job or use Supervisor

Related

How can i use the Queue::after on Laravel?

I'm using Queue to send my mails on my application, and it's working great:
class SendMail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $user_mail;
private $person_data;
private $title;
private $company_name;
private $html;
private $email_sender;
private $email_reply;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($user_mail, $person_data, $title, $company_name, $html, $email_sender, $email_reply)
{
$this->user_mail = $user_mail;
$this->person_data = $person_data;
$this->title = $title;
$this->company_name = $company_name;
$this->html = $html;
$this->email_sender = $email_sender;
$this->email_reply = $email_reply;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Mail::to($this->user_mail)
->queue(new DocumentMessage($this->person_data, $this->title, $this->company_name, $this->html,
$this->email_sender, $this->email_reply));
}
}
Now I want to get the log of the moment when the emails were sent by the queue and, following the documentation, I put this code in my AppServiceProvider for testing:
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Carbon::setLocale('pt_BR');
setlocale(LC_ALL, 'pt_BR');
Carbon::setUtf8(true);
Paginator::useBootstrapThree();
Blade::withoutDoubleEncoding();
Queue::after(function (JobProcessing $event) {
DB::raw("INSERT INTO activity_log (log_name, description, subject_id, subject_type, causer_id, causer_type, properties)
VALUES ('email_sent', now(), null, null, 1111,
'App\Models\User','');");
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
But nothing happens after i send mails using my queue. Should i restart my queue job or do something after modify AppServideProvider?
According to the documentation, JobProcessed is the right event class to use. You might want to update this:
Queue::after(function (JobProcessed $event) {
...
});
By the way, I suggest a bit cleaner approach that leverage the framework better. Laravel has already includes the Illuminate\Mail\Events\MessageSent out of the box. So you can listen to the mail event.

How to not add Notification broadcast in Queue? laravel 5.8

what I want to achieve is to broadcast notification immediately instead of need to run
php artisan queue:listen
If in Event class I just need to Implements ShouldBroadcastNow to make events broadcast immediately. But I tried same things in Notification but it is not working.
Notification
<?php
namespace App\Notifications;
use App\Tournament;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\BroadcastMessage;
use Illuminate\Notifications\Messages\MailMessage;
class TournamentAdded extends Notification implements ShouldBroadcastNow
{
use Queueable;
protected $tournament;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(Tournament $tournament)
{
$this->tournament = $tournament;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database', 'broadcast'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
$this->tournament
];
}
public function toBroadcast($notifiable)
{
return new BroadcastMessage([
$this->tournament
]);
}
}
Execute notification
$t = Tournament::latest()->first();
$user->notify(new AppTournamentAdded($t));

Can not get Request data in custom service?

I have custom service:
<?php
namespace App\Library\Services;
use Illuminate\Http\Request;
class RegisterCustomerService
{
private $request;
public function constructor(Request $request)
{
$this->request = $request;
}
public function register($role)
{
dd($this->request);
}
}
Why I can not get dd($this->request); when I do POST request:
$customer = $registerCustomerService->register('customer');
My service provider is:
class RegisterCustomerServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register(Request $request)
{
$this->app->bind('App\Library\Services\RegisterCustomerService', function ($app) {
return new RegisterCustomerService($request);
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
You don't need to bind the instance in the container because Laravel can automatically resolve the namespace and the class dependencies if you resolve an object through the container.
You can the remove the binding from the service provider and use:
$customer = app('App\\Library\\Services\\RegisterCustomerService')->register('customer');
In this way the container will resolve the Register customer service and will create that with all the needed dependencies (the request object in your example).

How can I create a controller constructor in Laravel that takes in two concrete implementations of the same interface?

Background
Note: this is using Laravel 5.3, Please don't judge.
We are trying to use dependency injection with our laravel controllers and push as much business logic into repos that are injected to controllers upon the controller instantiation.
We already have this functioning example:
class AcmeController extends Controller
{
protected $repository;
public function __construct(AcmeInterface $repository)
{
$this->repository = $repository;
}
}
inside app/Providers/RepositoryServiceProvider.php we do the binding:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(\App\Repositories\Contracts\AcmeInterface::class, \App\Repositories\OpCity\AcmeRepo::class);
}
}
and then the AcmeRepo naturally implements the AcmeInterface:
class AcmeRepo implements AcmeInterface
Question
right now we have a case where some of the data of the same model is persisted in a memory type storage (redis) and the rest is persisted in relational db storage (psql). We would like to have two separate repos where each repo is specific to its storage type, ie RedisAcmeRepo and SqlAcmeRepo
How is it possible to do this in the AcmeController constructor?
public function __construct(AcmeInterface $sqlRepo, AcmeInterface $redisRepo)
{
$this->sqlRepo = $sqlRepo;
$this->redisRepo = $redisRepo;
}
For example you may do this:
$this->app->bind(AcmeController::class, function ($app) {
return new AcmeController($app->make(sqlRepo::class), $app->make(redisRepo::class));
});
Or this:
$this->app->when(AcmeController::class)
->needs('$sqlRepo')
->give($app->make(sqlRepo::class));
$this->app->when(AcmeController::class)
->needs('$redisRepo')
->give($app->make(redisRepo::class));
based on the answers above I came up with this solution, that kind of uses the composite pattern as well (I changed the name of the repos from Acme to ShopperLogs):
<?php
interface ShopperLogInterface
{
public function getLogs($from, $to, $shopper);
}
class ShopperLogsController extends Controller
{
/**
* service
*
* #var \App\Repositories\Contracts\ShopperLogInterface
* #access protected
*/
protected $manager;
public function __construct(ShopperLogInterface $manager)
{
$this->manager = $manager;
}
}
class ShopperLogManager implements ShopperLogInterface
{
protected $sqlRepo;
protected $redisRepo;
public function __construct(ShopperLogInterface $sqlRepo, ShopperLogInterface $redisRepo)
{
$this->sqlRepo = $sqlRepo;
$this->redisRepo = $redisRepo;
}
public function getLogs($from, $to, $shopper)
{
$todayRange = //get the today part of from -- to
/**
* array of ShopperLogs
*/
$todaysLogs;
if ($todayRange) {
$this->redisRepo->getLogs($todayRange->start, $todayRange->finish, $shopper);
}
$legacyRange = //get the part of from -- to that excludes today's range
/**
* array of ShopperLogs
*/
$legacyLogs;
if ($legacyLogs) {
$this->sqlRepo->getLogs($todayRange->start, $todayRange->finish, $shopper);
}
return merge($todayRange, $legacyRange);
}
}
class ShopperLogsSqlRepo implements ShopperLogInterface
{
/**
* #var /Illuminate\Database\Eloquent\Model/ShopperLogs
*/
protected $model;
/**
* #param /Illuminate\Database\Eloquent\Model/ShopperLogs $model
*/
public function __construct(ShopperLogs $model)
{
$this->model = $model;
}
public function getLogs($from, $to, $shopper)
{
$this->model->whereLogs //do eloquent sql stuff here
}
}
class ShopperLogsRedisRepo implements ShopperLogInterface
{
/**
* #var \Redis\Model\Class
*/
protected $model;
/**
* #param \Redis\Model\Class $model
*/
public function __construct(ShopperLogs $model)
{
$this->model = $model;
}
public function getLogs($from, $to, $shopper)
{
$this->model->whereLogs //do redis stuff
}
}
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, \App\Managers\ShopperLogManager::class);
$this->app->bind(ShopperLogsController::class, function ($app) {
return new ShopperLogsController($app->make(ShopperLogManager::class));
});
$this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, function() {
return new \App\Managers\ShopperLogManager(new \App\Repositories\ShopperLogsSqlRepo(new \App\ShopperLog), new \App\Repositories\ShopperLogsRedisRepo(new \App\ShopperLog));
});
}
}

Pass data to Mail Job/Queue - Lumen/Laravel

I'm using Lumen and want to know how to pass data to my job class.
I have my job class like below;
<?php
namespace App\Jobs;
use App;
use Illuminate\Contracts\Mail\Mailer;
class TestEmailJob extends Job
{
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* #return void
*/
public function handle(Mailer $mailer)
{
//
$data; // I want to pass this from my function
$mailer->queue('emails.emailtemplate', $data , function ($message) {
$message->from('support#xxx.com', 'Laravel');
$message->to('xxx#gmail.com')->cc('xxx#yahoo.co.uk');
});
}
}
I then have a function to push the job on the queue;
public function emailTest () {
$data = ['user' => $user];
Queue::push(new TestEmailJob);
}
How can I pass $data and receive it and use it in the job class?
You can instantiate the variable by passing to the constructor
class TestEmailJob extends Job implements SelfHandling, ShouldQueue
{
use InteractsWithQueue;
protected $data;
public function __construct($data)
{
$this->data = $data;
}
public function handle()
{
// $this->data;
}
}
Now from the Controller, you can call it like:
$this->dispatch(new TestEmailJob($data));
http://laravel.com/docs/5.1/queues#writing-job-classes

Resources