laravel5.2 job, how to return data? - laravel-5

Job
class DataFormFields extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $fieldList = [
'name' => 'Tom',
'age' => '20',
];
public function handle()
{
$fields = $this->fieldList;
return $fields;
}
}
controller
public function create()
{
$data = $this->dispatch(new DataFormFields());
return view('create', $data);
}
I try to dd($data); print 0
the code can work in laravel5.1 ,but in 5.2 it's not ok.help

Laravel5.2 the class will implement the Illuminate\Contracts\Queue\ShouldQueue interface, indicating to Laravel that the job should be pushed onto the queue instead of run synchronously.
So you should make job like php artisan make:job fooJob --sync

I don't think you want to rely on the return from dispatch(), as queued jobs can have their execution delayed by an arbitrary amount of time, depending on your implementation. You probably want to consider using Events or a callback.
https://laravel.com/docs/5.2/queues#job-events
Or, at the end of the handle function you could do something like:
call_user_func(['FormFieldsHandler', 'dataFormFieldsCallback'], $data]);

Getting a list of fields like that isn't really the use case for a Job, as the return value of the handle() method is never returned to the calling scope through the dispatch() method.
It seems like something best left to a Service, or a model even.
Here's how you might implement this with a service.
<?php
namespace App\Services;
class DataFieldService
{
protected $fields = ['field_one', 'field_two'];
public function getFields()
{
return $this->fields;
}
}
And in the controller...
<?php
namespace App\Http\Controllers;
use App\Services\DataFieldService;
class MyController
{
// in Laravel, the IoC container will inject DataFieldService
// for you automagically if you type hint it
public function create(DataFieldService $dataFieldService)
{
$fields = $dataFieldService->getFields();
return view('create', compact('fields'));
}
}
And, obviously, you can flesh out the DataFieldService to get the fields from a database or something. Hope that helps!

Yes you can. Simply return the value. Instead of calling dispatch, you can call the job's handle like this.
public function handle()
{
$a = "return value";
return $a;
}
}
Now instead of calling $this->dispatch(new ExampleJob) in your controller. You can do this instead.
$exampleJob = new ExampleJob();
$retval = $exampleJob->handle();
echo $retval; //return value
Please note that only works if you do not intend to queue the job.

You can't get result from async job . when you implements from ShouldQueue interface it means that you tend exec job Async . you must remove ShouldQueue to exec sync job to get result

Related

Mock Laravel Eloquent save() method

Imagine you have a controller or some code that looks something like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
class TeamController {
public function create(Request $request): JsonResponse
{
$request->validated();
$team = new Team(['name' => $request->get('name')]);
if (!$team->save()) {
// some really important logic you want to cover
// cover by a test.
}
...
}
}
You cannot easily mock the Eloquent model without being a bit messy, see my answer on how to return false from the save() call.
In your test simply call:
Team::saving(fn () => false);
and your call to save() will now return false allowing you to cover that code flow.

No query results for model at boot created event

I have a model with boot function which has created event like below.
However, I sometimes (not all the time) get No query results for model on ProcessAddressRefine which is a job. As far as I understand, created event should happen after record is created, so there is no way that there is no query result unless it gets deleted right after it has been created. I also wonder that looking at the DB record, ProcessAddressRefine job is properly executed.
What would be the problem in this case?
Any advice or suggestion would be appreciated. Thank you.
Model
public static function boot()
{
parent::boot();
self::created(function ($model) {
if (!$model->lat || !$model->lng) {
ProcessAddressRefine::dispatch($model);
}
});
}
Job
class ProcessAddressRefine implements ShouldQueue
{
use Dispatchable, SerializesModels;
private $place;
public function __construct($place)
{
$this->place = $place;
}
public function handle()
{
if ($this->place->addressRefine()) {
$this->place->save();
}
}
}
Extra
public function addressRefine()
{
$helper = new MapHelper();
$coordinate = $helper->addressToCoordinate($geo_code_address);
if ($coordinate !== false) {
$this->lat = $coordinate['lat'];
$this->lng = $coordinate['lng'];
return true;
} else {
return false;
}
}
Assuming job is queued it's quite possible that model is created, then you dispatch the job, then model is deleted and then job is really executed and you are getting this message because model doesn't exist any more.
This was because of DB::transaction when Order record is created.

Where to put response messages in laravel api?

In my laravel 5.5 api I have a lot of response message like
"You successfully completed some action..".
At the moment I have stored them as constants in the controller they
are used. I want to move all of them to a single location, so if I need to change them later I don't have to hunt for them in each controller.
What is the best approach for this usecase?
What about Laravel localization? Then using it as trans('success-message-key-here')
In your use case, I would make static functions to call the responses the same way.
class ResponseMessage
{
public static function succesfulResponse()
{
return response('successfull', 200);
}
public static function failedResponse()
{
return response('fail', 400);
}
}
Use case:
...
return ResponseMessage::succesfulResponse();
Another way is to take the parent controller, which is often just named Controller in your controller folder, which you extend from.
class controller
{
public function succesfulResponse()
{
return response('successfull', 200);
}
}
Now you are not in a static context, but you can use the functions if you extend from it.
class yourController extends Controller
{
public function get($id) {
...
return $this->succesfulResponse();
}
}
You could make use of the translations files even if you are just supporting one language.
In your controller you would have something like:
$message = \Lang::get('directory/file.str1');
And your translation file:
return [
'str1' => 'You successfully completed some action.',
];
In resource/lang/en directory (in other words Localization you can put your message like this
ApiMessage.php
return [
'success' => 'success message',
];
Then in your controller you can call like this
public function somefunction(Request $request)
{
// your logic
return response()->json(__('apiMessages.success'));
}
here en folder denotes your local language (default is english symbolized as en)

Send email in background : Laravel 5.4

I am using an inbuilt code in Laravel to send Email Notification. Code is below. I am using smtp to send email
class RegisterNotification extends Notification
{
use Queueable;
public function __construct($token)
{
$this->token = $token;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line('hi');
}
public function toArray($notifiable)
{
return [
//
];
}
}
Here the problem is, it takes around 5 seconds to complete the process and control does not come back. I am assuming that if it come back and do the email sending work in background...it would save a lot of time.
Is there any inbuilt work to do the same? I meant, control should come back and should say email sent...and then it should do the work in background.
Email Sending code in Controller
class apiRegisterController extends Controller
{
public function Register(RegisterRequest $request) {
$RegisterNotification = new RegisterNotification($Token);
$User->notify($RegisterNotification);
}
}
Code for Queue
Controller Code
$job = (new SendForgotPasswordEmail($Data))->onConnection('database');
dispatch($job);
Job
class SendForgotPasswordEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $Data;
public $tries = 5;
public function __construct($Data)
{
$this->Data = $Data;
}
public function handle()
{
$Token = $this->Data["Token"];
$User = $this->Data["User"];
$RegisterNotification = new RegisterNotification($Token);
$User->notify($RegisterNotification);
}
}
Step 1: Change class RegisterNotification extends Notification to class RegisterNotification extends Notification implements ShouldQueue
Step 2: Implement a queue driver. In your config/queue.php make sure your driver is not set to sync like so: 'default' => env('QUEUE_DRIVER', 'sync'), and make sure your .env doesnt have QUEUE_DRIVER=sync. You can look at the Laravel documentation for queues to choose an appropriate queue driver
You can use the build-in API.
$user = User::findOrFail($id);
Mail::queue('emails.welcome', $data, function ($message) use ($user){
$message->from('hello#app.com', 'Your Application');
$message->to($user->email, $user->name)->subject('Your Reminder!');
});
But first you have to configure the queues.
Add in your .env file the line QUEUE_DRIVER=sync and then write on the terminal php artisan queue:listen.
If you want the queue to run forever on the server use Supervisor. Queues documentation explains how you can use it.
you can use laravel job queue https://laravel.com/docs/5.4/queues
Mail::queue(

Using Yii's CActiveRecord onBeforeDelete

I'm trying to attach some listeners to a CActiveRecord's onBeforeDelete, this I'm doing as follows:
<?php
class SomeModule extends CWebModule
{
public function init()
{
Submission::model()->onBeforeDelete = array($this, 'cleanUpFiles');
}
public function cleanUpFiles ($event) {
var_dump('Well... Hi there, being deleted are we?');
}
}
?>
Sadly, this does not have any effect on Submission's delete(). Though, when replacing onBeforeDelete with onBeforeFind, it seems to react seamlessly on the find methods. I'm having the feeling that the onBeforeDelete should be applied to an instance of Submission and not on it's singleton model, is that feeling correct? If I'm correct, is there any other way to attach my event listener in global on every Submission?
Thanks in advance!
I've managed to solve this with a little bit of improvisation, I've overwritten the Submission's function beforeDelete() as follows:
<?php
protected function beforeDelete() {
foreach (Submission::model()->onBeforeDelete as $key => $value) {
$this->onBeforeDelete = $value;
}
return parent::beforeDelete();
}
?>
Now, when delete is called, the beforeDelete() will rip out the onBeforeDelete from the singleton model and assign it to it's own instance. Now, the callbacks are being triggered.

Resources