How can i use the Queue::after on Laravel? - 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.

Related

Adding a custom faker service provider?

I'm trying to add https://github.com/morawskim/faker-images to faker in Laravel.
I have a faker service provider...
<?php
namespace App\Providers;
use Faker\{Factory, Generator};
use Illuminate\Support\ServiceProvider;
class FakerServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->singleton(Generator::class, function () {
$faker = Factory::create();
$faker->addProvider(new \Mmo\Faker\PicsumProvider($faker));
$faker->addProvider(new \Mmo\Faker\LoremSpaceProvider($faker));
$faker->addProvider(new \Mmo\Faker\LoremFacesProvider($faker));
return $faker;
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
This is conditionally loaded via the app service provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
if (!$this->app->environment('production')) {
$this->app->register('App\Providers\FakerServiceProvider');
}
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
}
Yet, fake()->picsumUrl() gives the error Unknown format "picsumUrl".
I've checked and the faker service provider is ran. There is no issues with the package either as I can do the following and get an image url...
$faker = \Faker\Factory::create('en_GB');
$faker->addProvider(new \Mmo\Faker\LoremFacesProvider($faker));
dd($faker->loremFacesUrl(1234));
So there must be something wrong with how the package is being added to faker.

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));

How can I use queue on custom class in 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

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));
});
}
}

Event listeners not firing in Laravel 5.1

I am having an issue getting my event listeners to fire in Laravel 5.1.
I am firing the following event:
/**
* Add new project.
*
* #param AddNewProjectRequest $request
* #return Redirect
*/
public function add(AddNewProjectRequest $request)
{
// Event(s);
Event::fire(new ProjectAdded($project, $request->only('file')));
}
I have the following event setup:
<?php
namespace App\Events\Project;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ProjectAdded extends Event
{
use SerializesModels;
public $project;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($project)
{
$this->project = $project;
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
return [];
}
}
Here is my EventServiceProvider file:
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
\App\Events\ProjectAdded::class => [
\App\Listeners\Project\ImportFileListener::class,
],
];
/**
* Register any other events for your application.
*
* #param \Illuminate\Contracts\Events\Dispatcher $events
* #return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
//
}
}
Here is my ImportFileListener listener:
<?php
namespace Woodford\Listeners\Project;
use Woodford\Events\ProjectAdded;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class ImportFileListener
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
}
/**
* Handle the event.
*
* #param ProjectAdded $event
* #return void
*/
public function handle(ProjectAdded $event)
{
dd('listener');
}
}
As you can see above I have added dd('listener'); to see if the listener gets fired - it doesn't!
I have also tried running php artisan optimize and composer dump-autoload but still no luck!
Does anyone know what could be wrong?

Resources