Associate on create? - laravel

A user has many posts. A post belongs to one user.
The relationship on the post model is:
public function user()
{
return $this->belongsTo(User::class);
}
But when I want to use create and also associate a user, I get a call to undefined method error...
$user = \App\Models\User::find(10);
$post = Post::create($request->validated());
$post->associate($user);
How can I use create and then associate a user?

You forgot to call the user() method before calling associate().
$user = \App\Models\User::find(10);
$post = Post::create($request->validated());
$post->user()->associate($user);
$post->save();
Or even better, associate the user before saving the post so only one query is executed:
$user = \App\Models\User::find(10);
$post = new Post($request->validated());
$post->user()->associate($user);
$post->save();

Related

What is the best way to add the authenticated user to a related model?

What is the best way to add the authenticated user to a related model?
If I wanted to add the authenticated user as the author on a post model whenever a new post is created, what would be the best way to do it?
Currently, I have the following which does the job but it runs an extra query (i.e 1. Create post. 2. Update post with author_id).
public function store(Request $request)
{
$post = Post::create($request->all());
$post→author()->associate($request->user());
$post→save();
return new PostResource($post);
}
There must be a better way to do this. I was thinking of just adding all the attributes manually, with $post-author_id = $request→user()→id, and then calling $post-save(). However, I do not like the idea of having to manually write out all the other attributes of the post.
Another option I was thinking is by creating an event listener on the Post creating event. I do not know if this will reduce the need for an extra query.
What is the simplest solution?
Instead of using the create method, you could simply create a new instance of PostResource and fill it with author_id. So it would be a bundled query.
public function store(Request $request) {
$post = new Post($request->all());
$post->author_id = Auth::user()->id;
$post->save();
return new PostResource($post);
}
I hope it helps.
Maybe you can consider this on related model:
/**
* Save auth user on create
*/
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$userID = auth()->id();
$model->author_id = $userID;
});
}

Model Relationships not finding the property

I'm trying to create a relationship between two models. My first model is the User Model, the second one is Company.
I tried adding in the User model the hasMany('App\Comapny') property, and in the Company one, belongsTo('App\User').
// In User Model
public function companies(){
return $this->hasMany('App\Company');
}
// In Company Model
public function user(){
return $this->belongsTo('App\User');
}
// And in the controller:
$user_id = auth()->user('id');
$user = User::find($user_id);
return view('devices.show')->with('companies', $user->companies);
It should return an array with all the companies that my User has when using "$user->comapnies", however, it returns this message instead:
Property [companies] does not exist on this collection instance.
Thanks, any help is welcome
Thanks for the quick response. I figured it out, the problem was this line:
$user_id = auth()->user('id');
It should be instead
$user_id = auth()->user()->id;
Try this,
$user_id = auth()->user->id;
$user = User::with('companies')->where('id', $user_id)->first();
return view('devices.show', compact('user'));
Then you can access the company relation with
$user->company[index]->
in the view.

How to retrieve all related models in a many to many relationship Laravel?

I am trying to retrieve all related models with another model through an intermediary table but can't figure out how. The Laravel docs say you can do something like this:
$roles = App\User::find(1)->roles()->orderBy('name')->get();
But when I try to apply that to my code
$roles = User::where('id', $user->id)->roles()->get();
It does not work. I am accepting the user model through my controller, so I do have access to it.
The relationship is also defined like so:
User
public function roles()
{
return $this->belongsToMany(Role::class);
}
Role
public function users()
{
return $this->belongsToMany(User::class);
}
How can I get all of the roles associated with a particular user?
edit/update:
I know I can simply use a foreach loop and get all of the roles associated with a particular user, but I am trying to return a resource collection, so I cannot do it that way
Try this,
I am assuming that $user_id is the parameter which is passed into the controller from the URL,
$roles=User::findOrFail($user_id)->roles;
But before running the above code, I assume that you have created the pivot table for many to many relationship with columns user_id and role_id. And have named the pivot table as role_user.
Hope this works
the problem with your second approach is calling roles() function on an 'Eloquent Query Builder' instance. You need to make sure to call roles() function on a 'User Model'.
this part of code User::where('id', $user->id) doesn't return a 'User Model'.
To get an 'User Model' from a 'Query Builder' instance you need to call first() function.
possible solution.
$roles = User::where('id', $user->id)->first()->roles;
The reason why you're getting the errors, is because before calling the method first() (or find() or findOrFail()), the instance is a QueryBuilder. and the roles() method exist only on an User::class instance.
if you are trying to get the user with an attribute roles containing a collection (array) of all his roles do:
$user = User::where('id', $user->id)->with('roles')->first();
if you need just the array of roles, you have two choices;
either get the user and then get his roles:
$user = App\User::find($userId);
$roles = $user->roles()->orderBy('name')->get();
//the same as
$roles = App\User::find($userId)->roles()->orderBy('name')->get();
or get the Roles (only one query)
$roles = Role::whereHas('users', function($users) use($userId) {
$users->where('id','=',$userId);
})->get();
Hope this gives you enough insight to build the exact code you need.
User
use App\User;
public function roles()
{
return $this->belongsToMany('App\Users', 'user_id');
}
Role
use App\Roles;
public function users()
{
return $this->belongsToMany('App\Roles');
}
Controller
$roles = User::where('id', $user->id)->roles()->get();
Try this one. I think your relationship is not correct.
You can read more information here Many To Many
You can use the following solution to retrieve all related models in a many to many relationship in Laravel:
$roles = User::where('id', $user->id)->get();
foreach($roles as $rol){
$rol->roles;
}

detach() in pivot table

Can't figure out how to delete record from pivot table.
I have users that belongsToMany documents with pivot document_user table.
here is my attach method:
public function share(Request $request, $company_id, $id)
{
$document = Document::find($id);
$user = $request['user'];
$document->users()->attach($user);
flash('Document has been shared!');
return back();
}
But how to make detach function? Should I build a form for this and what function should be? Something like $document->users()-detach($user). I have tried this, but doesn't work
You can do this in a couple ways:
First, you can use the detach() functionality (requires a second function in your controller). An example using a similar format to the one you provided:
public function unshare(Request $request, $id)
{
$document = Document::findOrFail($id);
$userId = $request['user']; //Assuming this is the User ID
$user = User::findOrFail($userId);
$user->documents()->detach($document->id);
flash('Document has been detached!');
return back();
}
Second, you can create a single function that toggles the association. Essentially you send a Document ID and if it is already associated to the User then it is Detached, if it is NOT associated to the User then it will Attach.
public function share(Request $request, $id)
{
$document = Document::findOrFail($id);
$userId = $request['user']; //Assuming this is the User ID
$user = User::findOrFail($userId);
$user->documents()->toggle($document->id); //This can also be an array of IDs
flash('Document has been toggled!'); //You might want to pass something or look up the association if you want custom messaging for attach or detach
return back();
}
Hope this helps!

Saving related records in laravel

I have users, and users belong to a dealership.
Upon user registration, I'm trying to save a new user, and a new dealership.
User database has a dealership_id column, which I want to be populated with the ID of the newly created dealership.
This is my current code in the UserController store method.
public function store()
{
$user = new User();
$user->email = Input::get('email');
$user->password = Input::get('password');
$dealership = new Dealership();
$dealership->name = Input::get('dealership_name');
$user->push();
return "User Saved";
}
Trying to use $user->push(); User data gets updated, but dealership is not created or updated.
Eloquent's push() saves the model and its relationships, but first you have to tell what you want to be involved in the relationsship.
Since your user-model/table holds the id of the dealership, I assume that a user can belong to only one dealership, so the relationship should look like this:
User Model:
public function dealership()
{
return $this->belongsTo('Dealership');
}
Dealership Model:
public function users()
{
return $this->hasMany('User');
}
To save a User from the Dealership perspective, you do this:
$dealership->users()->save($user);
To associate a dealership with a user, you do this:
$user->dealership()->associate($dealership);
$user->save();
Please check this answer to see the difference of push() and save()
You will need to define correctly your models relationships as per documentation
If this is done correctly, it should work .
This is what push() does :
/**
* Save the model and all of its relationships.
*
* #return bool
*/
public function push()
{
if ( ! $this->save()) return false;
// To sync all of the relationships to the database, we will simply spin through
// the relationships and save each model via this "push" method, which allows
// us to recurse into all of these nested relations for the model instance.
foreach ($this->relations as $models)
{
foreach (Collection::make($models) as $model)
{
if ( ! $model->push()) return false;
}
}
return true;
}
In your case, you have a one (dealership) belongs to many (users)
In your Users model :
class Users extends Eloquent {
public function dealership()
{
return $this->belongsTo('Dealership');
}
}
In the example above, Eloquent will look for a dealership_id column on the users table.
In your Dealership Model :
class Dealership extends Eloquent {
public function users()
{
return $this->hasMany('User');
}
}
In your store function :
public function store()
{
$user = new User();
$user->email = Input::get('email');
$user->password = Input::get('password');
$user->dealership = new Dealership();
$user->dealership->name = Input::get('dealership_name');
$user->push();
return "User Saved";
}
Learn here more about eloquent relationships
Also please take a look at my answer here
By using push on the User model, Laravel is basically recursively calling save on all the related models (which, in this case, is none, since you haven't associated any other models to it yet).
Therefore, in order to accomplish what you're trying to do, you can do first create the user then associate the dealership with it by doing the following:
$user = new User();
$user->email = Input::get('email');
$user->password = Input::get('password');
$user->save();
$dealership = new Dealership();
$dealership->name = Input::get('dealership_name');
$user->dealerships()->save($dealership);
return "User Saved";
However, prior to doing this, you must ensure your User and Dealership models have their relationships set up correctly:
User Model:
public function dealership()
{
return $this->belongsTo('Dealership');
}
Dealership Model:
public function users()
{
return $this->hasMany('User');
}
This is how I manage to do it.
In your controller: (Laravel 5)
use Auth;
$dealership->user = Auth::user()->ref_user->staff_id;

Resources