Laravel ManyToMany withPivot Trying to get property 'started_at' of non-object - php

I have a simeple ManyToMany relation between 2 models when I try to access a field in my pivot table I get this error:
Trying to get property 'started_at' of non-object
I have followed the instructions on the laravel documentation correctly.
My Models:
Instance:
public function steps(): BelongsToMany
{
return $this->belongsToMany(Step::class)
->using(InstanceStep::class)
->withTimestamps();
}
Step:
public function instances(): BelongsToMany
{
return $this->belongsToMany(Instance::class)
->using(InstanceStep::class)
->withPivot([
'started_at',
'finished_at',
'failed_at',
'output',
])
->withTimestamps();
}
How I try to access 'started_at' of a step:
dd($step->pivot->started_at);
EDIT
private function finishStep(Step $step)
{
dd($step->pivot->started_at);
}
/** #var Step $step */
foreach ($this->workflow->steps as $step) {
StepJob::dispatch($step, $instance);
}
dd($step)
Step {#420 ▼
#table: "workflow_steps"
#fillable: array:6 [▶]
#casts: array:3 [▶]
#connection: "mysql"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:10 [▼
"id" => "ca646f59-b215-41b0-afe6-ea9e6174f4f5"
"workflow_id" => "d786bd13-4111-4199-94d6-c52fef33b78b"
"category" => "transport"
"properties" => "props"
"entity_type" => "App\TransportWorkflowStep"
"entity_id" => "4d32e11c-6453-4f48-9419-7c5cbd647128"
"order" => 1
"created_at" => "2019-07-04 11:19:41"
"updated_at" => "2019-07-04 11:41:16"
"deleted_at" => null
]
#original: array:10 [▶]
#changes: []
#dates: array:1 [▶]
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
#forceDeleting: false
}
Attach step to instance
// set started_at
$workflowInstance->workflowsteps()->attach(
$step,
[
'started_at' => Carbon::now(),
]
);
// do something
// set finished_at when done
dd($step->pivot->started_at);
I did the dd($step->pivot->started_at); to see if i am working with the correct pivot row

You've not specified the relationship you're after, you may access the intermediate table using the pivot attribute on the models:
Try the following code:
private function finishStep(Step $step)
{
foreach ($step->instances as $instance) {
var_dump($instance->pivot->started_at);
}
die();
}

It depends on how declare $step, it gets collection and you have to insert it in foreach loop.
private function finishStep(Step $step)
{
dd($step->pivot->started_at);
}
this doesn't declare $step, you have to declare it first like
$step=Step::where(...)->get();
and then you can dd($step);
in short - object doesn't exist yet

Related

Laravel 5.8: Parameter passed to the event listener is getting null

I have created an Event called UserWalletNewTransaction.php and added this to it:
public $transaction;
public function __construct($transaction) {
$this->$transaction = $transaction;
}
And also registered it at EventServiceProivder.php:
use App\Listeners\UserWalletNotification;
protected $listen = [
UserWalletNewTransaction::class => [
UserWalletNotification::class,
],
Now in order to fire this event at the Controller, I coded this:
$newTransaction = UserWalletTransaction::create(['user_id' => $user_id, 'wallet_id' => $wallet_id, 'creator_id' => $creator_id, 'amount' => $amount_add_value, 'description' => $trans_desc]);
event(new UserWalletNewTransaction($newTransaction));
Then at the Listener, UserWalletNotification.php, I tried:
public function handle(UserWalletNewTransaction $event) {
dd($event->transaction);
}
But it returns null somehow.
However if I dd($event) instead, I get this:
So what is going wrong here? I can properly insert new record at user_wallet_transactions and the variable $newTransaction should contain the transaction information but it's not.
Here is also the Model UserWalletTransaction.php:
protected $fillable = ['user_id','wallet_id','amount','description','creator_id'];
protected $table = 'user_wallet_transactions';
I would really appreciate any idea or suggestion from you guys about this...
Thanks in advance.
UPDATE #1:
If I do dd($newTransaction) at the Controller before event(), I get this:
UPDATE #2:
Here is the full code of event, UserWalletNewTransaction.php:
class UserWalletNewTransaction
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public $transaction;
public function __construct($transaction)
{
$this->$transaction = $transaction;
}
}
UPDATE #3:
Here is the full result of dd($event) at the Listener:
App\Events\UserWalletNewTransaction {#2533 ▼
+newTransaction: null
+socket: null
+"{"user_id":"373","wallet_id":"2","creator_id":2,"amount":"-60","description":null,"updated_at":"2021-07-18 13:33:59","created_at":"2021-07-18 13:33:59","id":61}": App\UserWalletTransaction {#2535 ▼
#fillable: array:5 [▼
0 => "user_id"
1 => "wallet_id"
2 => "amount"
3 => "description"
4 => "creator_id"
]
#table: "user_wallet_transactions"
#connection: "mysql"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: true
#attributes: array:8 [▼
"user_id" => "373"
"wallet_id" => "2"
"creator_id" => 2
"amount" => "-60"
"description" => null
"updated_at" => "2021-07-18 13:33:59"
"created_at" => "2021-07-18 13:33:59"
"id" => 61
]
#original: array:8 [▼
"user_id" => "373"
"wallet_id" => "2"
"creator_id" => 2
"amount" => "-60"
"description" => null
"updated_at" => "2021-07-18 13:33:59"
"created_at" => "2021-07-18 13:33:59"
"id" => 61
]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▼
0 => "*"
]
}
}
I just figured out the problem... You are doing $this->$transaction when it should be $this->transaction.
I also had this problem, in case it is the case: remove the underscores in the properties of the event. ($_order has to be $order)

No data was collected in my relation array in Laravel Eloquent method

I used eloquent method in my controller to collect data from my database, but something weird happened. If i use this code below,
$female_old_visitors = Treatment::with('diseases', 'patient', 'insurance', 'referer')
->leftJoin('patients', 'treatments.patient_id', 'patients.id')
->where('treatments.visit_status', 'old')
->where('patients.gender', 'female')
->whereBetween('treatments.date', $date_range)
->get();
i can get all the data that i want include diseases and referer
Collection {#3053 ▼
#items: array:25 [▼
0 => Treatment {#2799 ▼
...
#relations: array:4 [▼
"diseases" => Collection {#3346 ▼
#dates: array:1 [▶]
#cascadeDeletes: array:1 [▶]
#guarded: []
#connection: "mysql"
#table: "diseases"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:32 [▶]
#original: array:32 [▶]
#changes: []
#casts: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#fillable: []
#forceDeleting: false
}
"patient" => Patient {#3328 ▶}
"insurance" => Insurance {#3346 ▶}
"referer" => TreatmentReferer {#3138 ▶}
]
#touches: []
+timestamps: true
#hidden: []
#visible: []
#fillable: []
#forceDeleting: false
}
but when i use other code like this
$common_insurance_old_visitors = Treatment::with('diseases', 'patient', 'insurance', 'referer')
->leftJoin('insurances', 'treatments.insurance_id', 'insurances.id')
->where('treatments.visit_status', 'old')
->where('insurances.id', 1)
->whereBetween('treatments.date', $date_range)
->get();
all the data has been selected or collected except disease and referer
Collection {#3053 ▼
#items: array:25 [▼
0 => Treatment {#2799 ▼
...
#relations: array:4 [▼
"diseases" => Collection {#3246 ▼
#items: []
}
"patient" => Patient {#3328 ▶}
"insurance" => Insurance {#3346 ▶}
"referer" => null
]
#touches: []
+timestamps: true
#hidden: []
#visible: []
#fillable: []
#forceDeleting: false
}
i have been checking in my database, that the data is still there and the column is not empty, it should be collected just like the code i use first. Is it because i use left join uncorrectly? i am still new for laravel, thanks for anyone who giving me a solution for this problem
this is my model for Treatment
<?php
namespace App;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Iatstuti\Database\Support\CascadeSoftDeletes;
class Treatment extends Model
{
use SoftDeletes, CascadeSoftDeletes;
protected $dates = ['deleted_at'];
protected $cascadeDeletes = ['medicines', 'actions', 'referer', 'diseases', 'queues'];
protected $guarded = [];
public function queues(){
return $this->hasMany(TreatmentQueue::class);
}
public function treatmentType(){
return $this->belongsTo(TreatmentType::class);
}
public function medicines(){
return $this->hasMany(TreatmentMedicine::class)->with('medicine', 'recu');
}
public function actions(){
return $this->hasMany(TreatmentAction::class)->with('action', 'doctor', 'nurse', 'recu', 'teeth', 'therapy', 'treatmentDisease');
}
public function insurance(){
return $this->belongsTo(Insurance::class);
}
public function referer(){
return $this->hasOne(TreatmentReferer::class)->with('puskesmas', 'disease');
}
public function diseases(){
return $this->hasMany(TreatmentDisease::class)->with('disease', 'doctor', 'teeth');
}
public function patient(){
return $this->belongsTo(Patient::class);
}
}
with() is for eager loading. That basically means, along the main model, Laravel will preload the relationship(s) you specify. This is especially helpful if you have a collection of models and you want to load a relation for all of them. Because with eager loading you run only one additional DB query instead of one for every model in the collection.
In your example.
you're using left join why? it already contain in with() you use with('patient') it means you join treatments to left join with patient
$female_old_visitors = Treatment::with('diseases', 'insurance', 'referer')
->with(['patient' => function ($q) {
$q->where('gender', 'female');
}])
->where('visit_status', 'old')
->whereBetween('treatments.date', $date_range)
->get();
eager-loads

How to transfer one-to-many data from a database to a template in Laravel?

There are many tables. One characterizes the sliders, the other contains information inside these sliders. My task is to transfer all values from tables into one template. That is, when choosing the desired slider from the possible, we were given relevant information.
What has been done:
Tables were connected by a one-to-many method.
Main model
class AdminSlider extends Model
{
public function aboutUs()
{
return $this->hasMany('App\AboutUs');
}
public function mainSlider()
{
return $this->hasMany('App\MainSlider');
}
}
Dependent models looks like
class MainSlider extends Model
{
public function adminSlider()
{
return $this->belongsTo('App\AdminSlider', 'slider_id', 'id');
}
}
2. Was created the variable which is working with template in controller
public function index()
{
$adminSlidersItems = $this->getSliderInfo();
$sliderInfo = view('admin.adminEditText')->with('sliderInfo',$adminSlidersItems)->render();
$this->vars = array_add($this->vars, 'sliderInfo', $sliderInfo);
return $this->renderOutput();
}
public function getSliderInfo() {
$sliderInfoItems = $this->as_rep->get();
return $sliderInfoItems;
}
When I looked into variable admin in controller I saw Collection
{#230 ▼
#items: array:6 [▼
0 => AdminSlider {#231 ▼
#connection: "mysql"
#table: "admin_sliders"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:7 [▼
"id" => 1
"title" => "Main Slider"
"path" => "http://jinol/admin/sliders/mainslider"
"img" => "mainslider.jpg"
"alias" => "mainslider"
"created_at" => null
"updated_at" => null
]
#original: array:7 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#fillable: []
#guarded: array:1 [▶]
}
1 => AdminSlider {#232 ▶}
2 => AdminSlider {#233 ▶}
3 => AdminSlider {#234 ▶}
4 => AdminSlider {#235 ▶}
5 => AdminSlider {#236 ▶}
]
}
template.layout
#extends('admin.site')
#section('admin.adminNavigation')
{!! $adminNavigation !!}
#endsection
#section('admin.adminEditText')
{!! $sliderInfo !!}
#endsection
Define our variables in template.
#if(count ($sliderInfo) > 0) <br>
<div id="content-page" class="content group"><br>
#foreach($sliderInfo as $info)<br>
<tr><br>
<td class="align-left">{{$info->adminSlider->id}}</td><br>
</tr><br>
#endforeach<br>
</div><br>
#endif
In the end of this I have got an error.
Trying to get property 'id' of non-object (View:
W:\domains\jinol\resources\views\admin\adminEditText.blade.php).
How can I find my mistake?
try
$info->adminSlider['id']
insted of
$info->adminSlider->id
i think it will be solve your problem
In your controller change:
public function index()
{
$adminSlidersItems = $this->getSliderInfo();
$sliderInfo = view('admin.adminEditText')->with('sliderInfo',$adminSlidersItems)->render();
$this->vars = array_add($this->vars, 'sliderInfo', $sliderInfo);
return $this->renderOutput();
}
To:
public function index()
{
$adminSlidersItems = $this->getSliderInfo();
return view('admin.adminEditText', ['sliderInfo' => $adminSlidersItems]);
}
In your view change
<td class="align-left">{{$info->adminSlider->id}}</td><br>
To
<td class="align-left">{{optional($info->adminSlider)->id}}</td><br>
Apparently, not all of your $sliderInfo's have a ->adminSlider defined and you get an error when trying to access id on it when it's set to null. The optional helper will only try to access the id when ->adminSlider is not null.

How to get Laravel set table to 'stick' for collection

We have a Laravel model and sometimes we want to get data from it's default table, but other times from a different table. It all works from a data perspective, but when the collection is returned from the alternate table, the 'table' attribute still references the original table (even though the data is from the other one as expected).
If we dd() getTable(), it is correct:
$model = COUNTRY;
$table = "countires";
$org_id = 1;
$org_collection = $model->setTable('merge_' . $table)->get()
->where('organization_id', $org_id)->keyBy('id');
dd($model->getTable()); // *** THIS SHOWS THE 2nd TABLE AS EXPECTED
dd() ouput:
"merge_countries"
But with the exact same code, if we dd() the result the table attribute in the collection is still the 1st one ('orgs') and not 'merge_orgs' as expected even though the data is correctly coming from the 'merge_orgs' table:
$model = COUNTRY;
$table = "countires";
$org_id = 1;
$org_collection = $model->setTable('merge_' . $table)->get()
->where('organization_id', $org_id)->keyBy('id');
dd($org_collection); // *** THIS SHOWS THE 1st TABLE EVEN THOUGH THE getTable() ABOVE DOES NOT
dd() output:
Collection {#297
#items: array:1 [
3 => Country {#295
#connection: "common"
#table: "countries" <---- WHY IS THIS NOT 'merge_countries'???
#hidden: array:2 [
0 => "created_at"
1 => "updated_at"
]
#appends: array:1 [
0 => "level"
]
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:7 [
"id" => 3
"organization_id" => 1
"region_id" => 2
"name" => "Southpark"
"active" => 1
"created_at" => "2018-06-21 14:05:36"
"updated_at" => "2018-06-21 13:25:27"
]
#original: array:7 [
"id" => 3
"organization_id" => 1
"region_id" => 2
"name" => "Southpark"
"active" => 1
"created_at" => "2018-06-21 14:05:36"
"updated_at" => "2018-06-21 13:25:27"
]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#visible: []
#fillable: []
#guarded: array:1 [
0 => "*"
]
}
]
}
Any idea how to address this? We're not sure what else to even try at this point. Laravel if 5.6 if that matters.
OK, there is a fix reference and more detail at github.com/laravel/framework/issues/26058. In the interim you can also override the model newInstance method in the trait to work around it:
public function newInstance($attributes = [], $exists = false)
{
// Overridden in order to allow for late table binding.
$model = parent::newInstance($attributes, $exists);
$model->setTable($this->table);
return $model;
}

Laravel save() method returning true but not updating records

I am using Eloquent to update my table Opportunity,
Opportunity Model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Opportunity extends Model {
protected $primaryKey = 'OpportunityID';
protected $table = 'opportunitys';
// relationships
public function csfs()
{
return $this->hasMany('App\Csf', 'opportunityID');
}
public function benefits()
{
return $this->hasMany('App\Benefit', 'opportunityID');
}
public function risks()
{
return $this->hasMany('App\Risk', 'opportunityID');
}
public function projects()
{
return $this->belongsTo('App\Project', 'projectID');
}
public static function createNewOpportunity($input, $projectID)
{
$opportunity = new Opportunity;
$opportunity->value = $input['value'];
$opportunity->margin = $input['margin'];
$opportunity->duration = $input['duration'];
$opportunity->tender_type = $input['tender_type'];
$opportunity->likelihood_of_success = $input['likelihood_of_success'];
$opportunity->scope_of_work = $input['scope_of_work'];
$opportunity->deliverables = $input['deliverables'];
$opportunity->projectID = $projectID;
$opportunity->high_level_background = $input['high_level_background'];
if($opportunity->save())
{
Opportunity::leadSalesOppComplete($projectID);
return true;
};
}
public static function leadSalesOppComplete($projectID)
{
$task = Lead::where('projectID', '=', $projectID)->first();
$task->sales_opp = true;
return $task->save();
}
}
public function updateOpportunity(Request $request, $id) {
I get the id and find the opportunity.
$something = Opportunity::find($id);
I have died and dumped this and I get this
Opportunity {#259 ▼
#primaryKey: "OpportunityID"
#table: "opportunitys"
#connection: null
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:12 [▼
"opportunityID" => 11
"value" => 0
"margin" => 0
"tender_type" => ""
"likelihood_of_success" => 0
"high_level_background" => ""
"scope_of_work" => ""
"deliverables" => ""
"duration" => ""
"projectID" => 6
"created_at" => "2015-03-11 17:45:47"
"updated_at" => "2015-03-11 17:45:47"
]
#original: array:12 [▶]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [▶]
#dates: []
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
}
Which is correct. I then update these with
$something->margin = $request['margin'];
$something->duration = $request['duration'];
$something->tender_type = $request['tender_type'];
$something->likelihood_of_success = $request['likelihood_of_success'];
$something->scope_of_work = $request['scope_of_work'];
$something->deliverables = $request['deliverables'];
$something->high_level_background = $request['high_level_background'];
Now if I die and dump I get
Opportunity {#259 ▼
#primaryKey: "OpportunityID"
#table: "opportunitys"
#connection: null
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: array:12 [▼
"opportunityID" => 11
"value" => "25000"
"margin" => "0"
"tender_type" => "Proposal"
"likelihood_of_success" => "0"
"high_level_background" => ""
"scope_of_work" => ""
"deliverables" => ""
"duration" => ""
"projectID" => 6
"created_at" => "2015-03-11 17:45:47"
"updated_at" => "2015-03-11 17:45:47"
]
#original: array:12 [▼
"opportunityID" => 11
"value" => 0
"margin" => 0
"tender_type" => ""
"likelihood_of_success" => 0
"high_level_background" => ""
"scope_of_work" => ""
"deliverables" => ""
"duration" => ""
"projectID" => 6
"created_at" => "2015-03-11 17:45:47"
"updated_at" => "2015-03-11 17:45:47"
]
#relations: []
#hidden: []
#visible: []
#appends: []
#fillable: []
#guarded: array:1 [▶]
#dates: []
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: true
}
I only changed the value which shows the change.
I now run
$something->save();
It returns true when I die and dump it.
But no records are changed in the database.
Any ideas?
two images from tinker
This line in the Opportunity model fixed the issue.
Protected $primaryKey = "opportunityID";
Although it is difficult to understand why it was still possible to retrieve the data and create a new record.
I had a very similar issue and this post lead me to a solution. I too was overriding a primaryKey.
Environment:
PHP 7.1
Lumen 5.3 (obviously Eloquent enabled)
Oracle 12 (using https://github.com/yajra/laravel-oci8)
SELECT and INSERT operations work with protected $primaryKey = 'USER_ID';, however, UPDATE operations did not work even though save() returned true.
After finding this post I changed case. protected $primaryKey = 'user_id';, Whammy, all three operations work! I wish I had a more solid explanation why this works. When I created the table I clearly used upper USER_ID VARCHAR2(50 BYTE) NOT NULL.
To answer the question in the title:
$user = \App\User::find(1);
$boolean = $user->save();
This will return true. Save always returns true, unless update or save did not succeed (because user_id is not found or something like this). Its not checked if an attribute has been changed. To see if an attribute has been changed see Laravel check if updateOrCreate performed update
Here is a bit of a Laravel eloquent Model.php :
// If the model already exists in the database we can just update our record
// that is already in this database using the current IDs in this "where"
// clause to only update this model. Otherwise, we'll just insert them.
if ($this->exists) {
$saved = $this->isDirty() ?
$this->performUpdate($query) : true;
}
// ...
return $saved;
isDirty() is true if model attribute has been changed and not saved. So if isDirty() is false, model will be not updated and return true.
I've had the same issue with Laravel 5.4 and MySQL. My original code was:
$attach = new Attachments ;
$attach->site_id = ($type == 'site' ? $typeId : null) ;
...
By adding a null primary id, save() behaves as expected.
$attach = new Attachments ;
$attach->id = null ;
$attach->site_id = ($type == 'site' ? $typeId : null) ;
...

Categories