No query results for model at boot created event - laravel

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.

Related

Storing Data and at the same time updating data on a different table in Laravel 8

I have two tables, 'vehicles' and 'assign_vehicles'. Whenever I assign a vehicle to a driver, I want the 'status' column on the 'vehicles' table to be updated to 'assigned'. How do I go about it?
There is some assumptions to be made. You will have to have classes that looks similar to this.
public class Vechicle extends Model {
public function assigned()
{
return $this->hasMany(AssignVehicle::class);
}
}
public class AssignVehicle {
public function vehicle()
{
return $this->belongsTo(Vehicle::class);
}
}
You can monitor the AssignVehicle event and add it to your boot method. Add it in AssignVehicle.php class. From there access the vehicle and update the status. Note there is a creating and created event, creating is before saving to the database and created is after saving to the database
public static function boot() {
parent::boot();
static::created(function (AssignVehicle $assignVehicle) {
$assignVehicle->vehicle->status = 'assigned';
$assignVehicle->vehicle->save();
});
}
For this to trigger remember to use standard Laravel approaches for events to trigger. The following will work.
AssignVehicle::create([
'vehicle_id' => $vehicle->id,
// your fields
])

call the another function within a function

In laravel I want to call a function within function to make recursive.I caught the route error.how to call the function 'recursive in tableFetch'
class queryTest extends Controller
{
public function tableFetch() {
recursive();
}
function recursive(){
//condition
}
}
I want to do it for check the manager of the given person and then get the manager of the fetched value in query so need to do it recursive
A controller is not a good place for this. Instead, manage it in your Person Model(or whatever you have).
Everyone has a manager. So, your model has HasOne relation to itself.
Person Model:
public function manager()
{
return $this->hasOne(Person::class, 'manager_id');
}
Now if you need to check the manager of given person untill you meet a certain condition you can do it inside the model and get the result in the controller.
public function checkManager()
{
$manager = $this->manager
if (check manager)
return $manager;
//check for the last manager
return $this->manager ? $this->checkManager() : null;
}
Inside controller
function index()
{
$person = Person::find($id);
$manager = $person->checkManager();// this will do the recursive you need
}
Do something like this
class queryTest extends Controller
{
public function tableFetch() {
$this->recursive();
}
function recursive(){
//condition
}
}
you need to ask more precise details about your needs, because Laravel has some complications.
try doing this :
class queryTest extends Controller
{
public function tableFetch() {
$this->recursive();
}
public function recursive() {
//condition
}
}

Laravel - Delete if no relationship exists

Below is the one of the model. I would like to delete a Telco entry only if no other model is referencing it? What is the best method?
namespace App;
use Illuminate\Database\Eloquent\Model;
class Telco extends Model
{
public function operators()
{
return $this->hasMany('App\Operator');
}
public function packages()
{
return $this->hasMany('App\Package');
}
public function topups()
{
return $this->hasMany('App\Topup');
}
public function users()
{
return $this->morphMany('App\User', 'owner');
}
public function subscribers()
{
return $this->hasManyThrough('App\Subscriber', 'App\Operator');
}
}
You can use deleting model event and check if there any related records before deletion and prevent deletion if any exists.
In your Telco model
protected static function boot()
{
parent::boot();
static::deleting(function($telco) {
$relationMethods = ['operators', 'packages', 'topups', 'users'];
foreach ($relationMethods as $relationMethod) {
if ($telco->$relationMethod()->count() > 0) {
return false;
}
}
});
}
$relationships = array('operators', 'packages', 'topups', 'users', 'subscribers');
$telco = Telco::find($id);
$should_delete = true;
foreach($relationships as $r) {
if ($telco->$r->isNotEmpty()) {
$should_delete = false;
break;
}
}
if ($should_delete == true) {
$telco->delete();
}
Well, I know this is ugly, but I think it should work. If you prefer to un-ugly this, just call every relationship attributes and check whether it returns an empty collection (meaning there is no relationship)
If all relationships are empty, then delete!
After seeing the answers here, I don't feel copy pasting the static function boot to every models that need it. So I make a trait called SecureDelete. I put #chanafdo's foreach, inside a public function in SecureDelete.
This way, I can reuse it to models that need it.
SecureDelete.php
trait SecureDelete
{
/**
* Delete only when there is no reference to other models.
*
* #param array $relations
* #return response
*/
public function secureDelete(String ...$relations)
{
$hasRelation = false;
foreach ($relations as $relation) {
if ($this->$relation()->withTrashed()->count()) {
$hasRelation = true;
break;
}
}
if ($hasRelation) {
$this->delete();
} else {
$this->forceDelete();
}
}
}
Add use SecureDelete to the model that needs it.
use Illuminate\Database\Eloquent\Model;
use App\Traits\SecureDelete;
class Telco extends Model
{
use SecureDelete;
public function operators()
{
return $this->hasMany('App\Operator');
}
// other eloquent relationships (packages, topups, etc)
}
TelcoController.php
public function destroy(Telco $telco)
{
return $telco->secureDelete('operators', 'packages', 'topups');
}
In addition, instead of Trait, you can also make a custom model e.g BaseModel.php that extends Illuminate\Database\Eloquent\Model, put the function secureDelete there, and change your models to extends BaseModel.

Laravel one-to-many save Carbon error

I have a class called SubjectData:
class SubjectData extends Model
{
protected $table = 'subject_datas';
protected $fillable = ['firstname','lastname','birthdate','birthcity','months'];
protected $dates = ['birthdate'];
public function setBirthdateAttribute($date)
{
// So we can add the time, not just he php date
$this->attributes['birthdate'] = Carbon::createFromFormat('d/m/Y', $date);
}
public function anamnesis() {
return $this->belongsTo('App\Anamnesis');
}
}
And I have a class called Anamnesis:
class Anamnesis extends Model
{
public function meetingTest() {
return $this->belongsTo('App\MeetingTest');
}
public function subject() {
return $this->belongsTo('App\Subject','subject_id','id');
}
public function subjectData() {
return $this->hasOne('App\SubjectData');
}
public function scholarHistory() {
return $this->hasOne('App\ScholarHistory');
}
public function familyHistory() {
return $this->hasOne('App\FamilyHistory');
}
public function psicodiagnosis() {
return $this->hasOne('App\Psicodiagnosis');
}
}
The store function of the SubjectController class works like this:
public function store(CreateSubjectRequest $request)
{
$input = $request->all();
// Let's generate the anamnesis of the subject
$anamnesis = Anamnesis::create();
$anamnesis->save();
$newSubjectData = $this->saveSubjectData($input);
$anamnesis->subjectData()->save($newSubjectData);
......
......
}
where the function called is:
public function saveSubjectData($input)
{
$subjectData['firstname'] = $input['firstname'];
$subjectData['lastname'] = $input['lastname'];
$subjectData['birthcity'] = $input['birthcity'];
$subjectData['birthdate'] = $input['birthdate'];
return SubjectData::create($subjectData);
}
The problem is with the "birthdate" property.
If i check the value of $newSubjectData (dd($newSubjectdata)) after the call $this->saveSubjectData($input) the value of the birthdate is exactly the one i set on the calendar in the frontside (and also in the db the value is correct)
If I put the dd($anamnesis->subjectData) after the call $anamnesis->subjectData()->save($newSubjectData) the result is the "today" date and also in the DB the value is not the one I set but the date of today.
I can't find the error
P.S. The calendar is inside a Vue template
I think the problem is that, the date must be an instance of Carbon or is properly formatted according to your database table. Try the following inside your saveSubjectData() method
$subjectData['birthdate'] = Carbon\Carbon::parse($input['birthdate']
I write down the answer but i thank John Aldrin that guided me in the right direction.
You have to put the timestamp('birthdate') AFTER the default timestamps of the migration table (so at the end of the migration table)
I don't know why. If someone knows please explain !

Laravel4 - Saving a model with multiple relationships/foreign keys

I've tried to understand a process of saving a model with multiple relationships but I still can't figure out how to do it "kosher" way.
To begin with - I have an Event model that belongs to a category (Eventcat) and a Location:
// Event.php
class Event extends Eloquent {
protected $table = 'events';
public function location()
{
return $this->belongsTo('Location');
}
public function eventcat()
{
return $this->belongsTo('Eventcat');
}
public function users()
{
return $this->belongsToMany('User');
}
}
// Location.php
class Location extends Eloquent
{
protected $table = 'locations';
public function events()
{
return $this->hasMany('Event');
}
}
// Eventcat.php
class Eventcat extends Eloquent
{
protected $table = 'eventcats';
public function events()
{
return $this->hasMany('Event');
}
}
I've seeded the database with a few categories and locations and now I trying to get events saving work. I thought that the $event->eventcat()->associate( $eventcat ) would work but I got a Call to undefined method eventcat() error.
public function postCreateEvent() {
$event = new Event();
$eventcat = Eventcat::find( Input::get('event-create-eventcat[]') );
$location = Location::find( Input::get('event-create-location[]') );
$event->title = Input::get('event-create-title');
$event->description = Input::get('event-create-description');
$event->price = Input::get('event-create-price');
$event->start_date = Input::get('event-create-start_date');
$event->end_date = Input::get('event-create-end_date');
$event->eventcat()->associate( $eventcat );
$event->location()->associate( $location );
$event->save();
}
I've read the documentation, API and a few threads here but I still can't figure out the best way to deal with this.
Thanks for replies!
I would actually bet that you have a conflict in your class name. Laravel contains an Event class and I wonder if that isn't what's being called in your code. As a quick test, you could rename your class FooEvent and see if it works.
The best solution is probably namespacing your model (see http://chrishayes.ca/blog/code/laravel-4-methods-staying-organized for a quick intro) so that your model can still be called Event without conflicting with the builtin class.

Resources