I am working on a project where I need to update two related models in my controller. Below, I am creating one transaction record for a user that can have many transactions. After that, I need access to the id of the recently created transaction, but since thats hasMany relationship, laravel is throwing an error.
UserModel
public function transaction()
{
return $this->hasMany('App\Model\Transaction');
}
Controller
$user->transaction()->create([
...
...
])->save();
$devUnit = new DevUnit();
$devUnit->transaction_id = $user->transaction()->id; //this throws an error
Error
Undefined property: Illuminate\Database\Eloquent\Relations\HasMany::$id
Sorry, totally misread your question.
Save the result of the create method to a variable to get access to the populated model with the ID.
$transaction = $user->transaction()->create([
//
]);
$timeshareUnit = new TimeshareUnit();
$timeshareUnit->transaction_id = $transaction->id;
Related
I understand Laravel is checking the object reference id to check if the object existed, so the save() method will run the edit method to edit it. and if it's a new object, it will run the create() method.
but I can't find the codes behind it, in the Eloquent package.
I want the exact address of the file that includes these codes
from the blow codes I infer the above conclusion:
I wrote this code in Laravel:
$setting = new Setting;
$setting->name = 'name1';
$setting->save();
$setting->name = 'name2';
$setting->save();
after executing I see just name2 in the database and it seems, after saving name1 Laravel edit that and save name2 in the database.
and after I execute this code:
$setting = new Setting;
$setting->name = 'name1';
$setting->save();
$setting = new Setting;
$setting->name = 'name2';
$setting->save();
and I saw both the records saved correctly, so I have name1 and name2.
You can find the code for Eloquent's save() method in vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 833 in Laravel 8.12.
The behaviour that you're observing is a characteristic of the Active Record pattern, which Laravel is based on. Each time you use new to create an Eloquent model, it's creating a object that will represent a row in your database. Within Eloquent's save() method, it will check to see if a record already exists, and if it does it will update it (code below).
if ($this->exists) {
$saved = $this->isDirty() ?
$this->performUpdate($query) : true;
}
Your code is working as expected.
Trying to get property from a object in laravel. I have this:
public function index()
{
$firmen = Companies::all();
$allcountcompanies = Companies::count();
$agent = Agent::find($firmen->agent_firma_id);
return view('companies',compact(['firmen'],['allcountcompanies'],['agent']));
}
The Exeption gives me that:
Property [agent_firma_id] does not exist on this collection instance.
But when i put the id eg 1001 it shows corrent entry in db field.
What i0'm doing wrong?
Info:
CompaniesController.php (table: br_firma)
AgentController.php (table: br_firma_agents)
Table "br_firma_agents" contains a foreign_key from table "br_firma".
You are getting id from collection.
$firmens = Companies::all();
it return collection you may be use it useing loop and get one by one data as
for($firmens as $firmen){
$agent = Agent::find($firmen->agent_firma_id);
}
Or you create relation between Company and agent as,
In company model define relation as
public function agents(){
return $this->hasMany(Agent::class);
}
and in agent model define relation as
public function company(){
return $this->belongsTo(Companies::class);
}
and then call it as in controller,
$data = Companies::with('agents')->get();
You are trying to access an agent_firma_id from a collection of companies, you could first use a loop on that collection,or use an index on that collection,
you could try
$firmens = Companies::all();
foreach($firmens as $firmen){
$agent = Agent::find($firmen->agent_firma_id);
}
I'm using parent->child (master->detail) relation in Yii2 Active Record
When I want to create a child, I have to manually fill its parent info like this:
Relation: Client (1) ---> (n) Comments
class ClientController extends \yii\web\Controller
{
public function actionAddComment() {
$comment = new Comment;
if ($comment->load(Yii::$app->request->post())) {
$comment->client = $this->id; // Client id
$comment->save();
}
return $this->render('view', ['comment'=>$comment]);
}
}
I've optimized it, creating a Comment method to do that:
class Comment extends ActiveRecord {
public function newComment($client) {
$comment = new Comment;
$comment->client = $client; // Client id
return $comment;
}
}
And I have gone through beforeSave in the Comment model, but still not sure if there is a better way.
Is there anything like:
$comment = new Comment(Yii::$app->request->post());
$client->save($comment); // Here the parent is writing his information to the child
Or one-liner shortcut:
$client->save(new Comment(Yii::$app->request->post());
Without having to create this logic in beforeSave?
Yes, I recommend to use the built in link() and unlink() methods provided by Active Record which you can use in your controller to relate or unrelate 2 models either they share many-to-many or one-to-many relationship.
It even has an optional $extraColumns attribute for additional column values to be saved into a junction table if using it link( $name, $model, $extraColumns = [] )
So your code may look like this :
$comment = new Comment;
if ($comment->load(Yii::$app->request->post())) {
$comment->link('client', $this);
}
check docs for more info.
Now about where to use this code to relate models, it depend on how your app is structured. I'm not sure if doing that through a triggered event would be a good practice, you need to remember that errors may happens and
you may need to evaluate certain scenarios or logic before throwing exceptions. So in my case, I prefer to use that code into my Controllers.
Sometimes you need to build a specific action like you did actionAddComment(), In certain other cases like when your Post request is meant to update the Parent model and also update its related child models at once, the Parent's Update Action ClientController::actionUpdate() may be a good place to do so, maybe something like this will do the job :
$params = Yii::$app->request->post();
$client->load($this->params, '');
if ($client->save() === false && !$client->hasErrors()) {
throw new ServerErrorHttpException('Failed to update the object for unknown reason.');
}
foreach ($params["comments"] as $comment) {
// We may be sure that both models exists before linking them.
// In this case I'm retrieving the child model from db so I don't
// have to validate it while i just need its id from the Post Request
$comment = Comment::findOne($comment['id']);
if (!$comment) throw new ServerErrorHttpException('Failed to update due to unknown related objects.');
// according to its documentation, link() method will throw an exception if unable to link the two models.
$comment->link('client', $client);
...
I have a User that has many Positions. I want to update the User (the model and the relation Position), and then return the updated result.
The input will be an array of the format
{
first_name,
last_name,
email,
... (other user information),
positions : [
{
id,
name,
descriton
},
...
]
}
My update function currently is
public function update($id)
{
// This is a validation that works fine
if ( ! User::isValid(Input::all())) return $this->withValidation(User::$errors);
$user = User::with('positions')->find($id);
$new_ids = array_pluck(Input::get('positions'), 'id');
$user->positions()->sync($new_ids);
$user->update(Input::all());
return $user;
}
My User and its permissions are updated, but I still get the old $user's relationship back (i.e. the basic information is updated, and the new positions are updated in the DB, but the returned result is the NEW basic information with the OLD positions).
Right now to fix this, I recall the User::with('positions')->find($id) at the end and return that. But why isn't my code above working?
Correct, sync doesn't update related collection on the parent model.
However you should use $user->load('positions') to reload the relation, it will call only 1 query, without fetching the user again.
Also, you can call load on the Collection:
$user->positions->load('anotherRelation');
because here positions is a Collection, which have load method to lazy load all the related models for each item in the collection.
This would not work, since positions() returns relation object, not collection:
$user->positions()->load('anotherRelation');
I am laravel newbie and I am trying to follow the documentation.So I have two models, 'User' model and a 'UserPhone' model. A user has many phones.
User model:
public function userPhone() {
return $this->hasMany('UserPhone');
}
UserPhone model:
public function user(){
return $this->belongsTo('User');
}
On my controller I am trying to "copy" the documentation:
$userPhone = User::find(1)->userPhone;
Well the result is an error:
Trying to get property of non-object
I know that I am missing something here , but I cannot find it.
I'm pretty sure that you don't have an user with id of 1.
$userPhone = User::find(1)->userPhone;
This should work, but, if it doesn't find the user the first part:
User::find(1)
I will return a NULL and NULL is not an object, then you get the error: Trying to get property of non-object.
My advice is, try to do this
var_dump( User::find(1) );
And you if you receive just a NULL, you found the problem.
Well the answer is that everything was ok!
I had accidentaly left
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
before the UserPhone Model Class declaration..It was such a newbie mistake.
If you want to fetch Users with their related phone numbers (userPhone) you can use Eager Loading.
//get all users (User) with their respective phonenumbers (userPhone)
$users = User::with('userPhone')->get()
//get User with id==1, with his related phonenumbers (userPhone of User(1))
$user_1 = User::with('userPhone')->where('id',1)->first()
and than you can do
if(!is_null($user))
$phones_of_user_1 = $user_1->userPhone();
else
$phones_of_user_1 = array();
That way, if a user of id==1 exists, you fetch his phone numbers. Else, you get an empty array and no exception/error (trying to get property on a non-object) thrown .
That relationship would automatically be loaded for you.
$user = User::find(1);
echo $user->userPhone->id;
This is assuming you have your database tables are setup correctly according to laravel's conventions and you actually have a User with an ID of 1.
1) You are missing a pair of () after userPhone
$userPhone = User::find(1)->userPhone();
2) You are not using the 'find' method properly. I think what you want to do is :
$userPhone = User::userPhone()->get();
or
$userPhone = User::find($phoneId); //where $phoneId is the id of the phone you are trying to find.
The 'find' method return only one object and will try to find it with it's id.