I've got offers table with id's
Messages table with columns offer_id and from
and Users table with id's
I want to get users starting with offer $this in OfferResource
My goal is to get users that have replied to the offer with at least one message.
I started to configure Offer model with function messages to get messages
public function messages(){
return $this -> hasMany('App\Message');
}
so I'm able to get all messages (starting from offer resource):
'users' => $this->messages
How should I now configure messages model to get all users instead of messages?
I tried to write in Message model :
public function fromContact()
{
return $this->hasOne(User::class, 'id', 'from');
}
and then:
'users' => $this->messages->fromContact
but i've got error: "message": "Property [fromContact] does not exist on this collection instance.",
How should I correct my code to make this work?
I am assuming the from field on the Messages table is populated using user ID. Then you could establish belongsToMany relationship between the Offer and User models. Since this is actually a many-to-many relation with a pivot table messages.
In the Offer model define
public function users()
{
return $this->belongsToMany('App\User', 'messages', 'offer_id', 'from');
}
Then from the OfferResource you could load the offers data like this—
$offers = App\Offer::with('users')->get();
Then loop over the $offers like this:
foreach ($offers as $offer) {
dd($offer->users); // one offer will have multiple users as a Collection
}
Similarly for an $offer of ID 1 you could do this
$offer = App\Offer::with('users')->find(1)
Then to get the users that commented on this offer just use $offer->users
See the official documentation for defining many-to-many relationship.
In the Message model you have to spesify the column that refer to the user :
public function fromContact()
{
return $this->hasOne(User::class, 'from');
}
And then after geting the messages loop over them to get the user like this :
foreach ($this->messages as $message) {
$user = $message->fromContact;
// do somthing with the user :)
}
Your messages table has from field that is referencing User model and offer_id field which referencing Offer model that means you have ManyToMany relations between Offer and User.
Offer Model
public function users(){
return $this->belongsToMany(User::class, 'messages', 'offer_id', 'from')->using('App\Message');
}
Message Pivot
class Message extends Pivot {
protected $table = 'messages';
}
User model
public function offers(){
return $this->belongsToMany(Offer::class, 'messages', 'from', 'offer_id')->using('App\Message');
}
OfferResource
public function toArray($request)
{
$users = $this->users;
return [
'id' => $this->id,
... //add your offer fields here
'users' => $users->toArray(), // here $users is a laravel Collection
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
Access from Controller or Route
Route::get('/offer', function () {
return new OfferResource(Offer::with('users')->find(1)); //eager load users
});
Related
I just created a profile for users, and wish to show the education details related to the logged-in user or another selected user.
for this, I created an education model for users and gave a proper relationship to it both the sides. im not able to get any data from the education table of loged in user or another user. i used foreach tag in blade file. please revview my code. thanks.
Education Model
class Education extends Model
{
use HasFactory;
protected $primaryKey = 'education_id';
public function myusers()
{
return $this->belongsTo('App\Models\User','user_id','education_id');
}
}
User Model
public function myeducation()
{
return $this->hasMany('App\Models\Education','education_id','user_id');
}
Profile Controller
public function index()
{
$user = Auth::user();
return view('candidate.profile',['user'=>$user,]);
}
Blade file
#foreach ($user->myeducation as $education)
<div>
{{ $education->school }}
</div>
#endforeach
Table Structure of Education and Users
**Education Table**
{
Schema::create('education', function (Blueprint $table) {
$table->bigIncrements('education_id');
$table->bigInteger('user_id');
$table->string('school');
$table->string('degree');
$table->string('fieldOfStudy');
$table->date('startDate');
$table->date('endDate');
$table->string('grade');
$table->string('activities');
$table->string('description');
$table->timestamps();
});
}
user table.
$table->increments('user_id');
$table->bigInteger('role_id');
$table->bigInteger('membership_id')->nullable();
$table->string('firstname');
$table->string('lastname');
there is no error message, but just blank
Table entries
DB::table('education')
'user_id' => '2',
'school' => 'University of Bedfordshire',
'degree' => 'MBA',
]);
DB::table('users')->insert([
'user_id' => '1',
'role_id' => '1',
'firstname' => 'Mohammed',
'lastname' => 'Sabeel',
.......
]);
DB::table('users')
' user_id' => '2'
'role_id' => '2',
'firstname' => 'zahida',
'lastname' => 'sabeel',
.......
]);
the problem is in your relationship second and third argument. you are passing keys in wrong way.
in Education model use code like
public function myUser()
{
return $this->belongsTo('App\Models\User', 'user_id');
}
you need not to pass the third argument if you use the primary key for relationship. though you can pass the third argument to define which column to use to join the tables
public function myUser()
{
return $this->belongsTo('App\Models\User', 'user_id', 'user_id');
// second argument user_id is from your education model while the third argument that is user_id is the primary key of your user model
// i have used singular name for the relationship name with camel case
}
now in User model
public function myEducations()
{
return $this->hasMany('App\Models\Education', 'user_id');
// user_id is the user_id of education model
// and this is a has many relation i used plural form
}
read more about relationship in laravel doc
Before we begin, make sure that you have Education associated with that logged in User.
Try eager loading you relationship. Sometime this worked for me.
In your profile controller,
public function index()
{
$user = Auth::user()->load('myeducation');
return view('candidate.profile',['user'=>$user,]);
}
Even if it didn't work, Please share your table structure and table entries. So that we can examine clearly.
I can save my ticket inside a ticket table. But i also have a ticket_user table with inside a ticket_id and a user_id. So when the user press save it need to automaticlay pick also the ticket_id and the user_id inside the ticket_user table. I have a many to many table between Users and Ticket.
this is the error i get Call to a member function attach() on null
User Models
public function ticket(){
return $this->belongsToMany(Ticket::class, 'ticket_user');
}
Ticket models
public function users() {
$this->belongsToMany(User::class, 'ticket_user');
}
Controller
public function store(Request $request)
{
$this->validate($request, array(
'title' => 'required',
'ticket' => 'required'
));
$ticket = new Ticket;
$ticket->title = $request->title;
$ticket->ticket = $request->ticket;
$ticket->save();
$ticket->users()->attach($request->input('user_id'));
return redirect()->route('users.tickets.index');
}
You are not returning anything in users function in Ticket class.
public function users() {
return $this->belongsToMany(User::class, 'ticket_user');
}
I am working on a polymorphic relationship between these classes in my small project: Submissions (same as posts), Comments and Users.
The problem is, I am able to gather all comments by relying on Submission model, for example:
$submissions = Submission::with('comments')->get()->find( $submission );
But, if I try something like this in tinker:
$users = User::with( 'comments' )->get();
I get all the users data, but no comments show up:
comments: Illuminate\Database\Eloquent\Collection {#3003
all: [],
},
Here's all the code of relations between models:
class Comment extends Model
{
protected $fillable = [ 'commentable_id', 'commentable_type', 'text' ];
public function commentable() {
return morphTo();
}
}
Now this is being added inside Submission and User model:
public function comments() {
return $this->morphMany( Comment::class, 'commentable' );
}
In Submission model I am using protected $guarded = []; to deal with Mass Assignment and I don't call it inside user model.
I hope you can tell me what am I doing wrong since somehow I can't access user model by comment model and vice versa.
Thanks in advance!
edit: Here's a code of creation of a comment:
public function store( Submission $submission ) {
$data = request()->validate([
'text' => [ 'required', 'string', 'max:255' ]
]);
$id = $submission->comments()->create([ 'text' => request()->text ]);
dd( $submission, $data );
}
Relation morphMany is one-to-many relation, like hasMany. So one comment can belong to a submission or a user, not both. One option is to create separate comments for submission and user (for the user do the same as for submission $user->comments()->->create([...])). Second option is to use many-to-many polymorphic relation, where one comment can belong to multiple submissions and users.
I'm trying to retrieve related models of the same type on from a pivot table.
I have 2 models, App\Models\User and App\Models\Group and a pivot model App\Pivots\GroupUser
My tables are have the following structure
users
id
groups
id
group_user
id
user_id
group_id
I have currently defined relationships as
In app/Models/User.php
public function groups()
{
return $this->belongsToMany(Group::class)->using(GroupUser::class);
}
In app/Models/Group.php
public function users()
{
return $this->belongsToMany(User::class)->using(GroupUser::class);
}
In app/Pivots/GroupUser.php
public function user()
{
return $this->belongsTo(User::class);
}
public function group()
{
return $this->belongsTo(Group::class);
}
I'm trying to define a relationship in my User class to access all other users that are related by being in the same group. Calling it friends. So far I've tried this:
app/Models/User.php
public function friends()
{
return $this->hasManyThrough(
User::class,
GroupUser::class,
'user_id',
'id'
);
}
But it just ends up returning a collection with only the user I called the relationship from. (same as running collect($this);
I have a solution that does work but is not ideal.
app/Models/User.php
public function friends()
{
$friends = collect();
foreach($this->groups as $group) {
foreach($group->users as $user) {
if($friends->where('id', $user->id)->count() === 0) {
$friends->push($user);
}
}
}
return $friends;
}
Is there a way I can accomplish this using hasManyThrough or some other Eloquent function?
Thanks.
You can't do that using hasManyThrough because there is no foreign key on the users table to relate it to the id of the group_user table. You could try going from the user to their groups to their friends using the existing belongsToMany relations:
app/Models/User.php:
// create a custom attribute accessor
public function getFriendsAttribute()
{
$friends = $this->groups() // query to groups
->with(['users' => function($query) { // eager-load users from groups
$query->where('users.id', '!=', $this->id); // filter out current user, specify users.id to prevent ambiguity
}])->get()
->pluck('users')->flatten(); // massage the collection to get just the users
return $friends;
}
Then when you call $user->friends you will get the collection of users who are in the same groups as the current user.
So I learned in JeffreyWay's screencasts that I can use Eloquent to get the associated id from a model injected to another model.
I'm following his series about Laravel 5.4.
Here, I have a one-to-many relationships of user to posts.
App/Post
public function user()
{
return $this->belongsTo(User::class);
}
In my User Model, I have a publish method where the Post Model is injected. The publish method is used to create a post entry into the database.
App/User
public function posts()
{
return $this->hasMany(Post::class);
}
public function publish(Post $post)
{
$this->posts()->save($post);
}
I then have a store method in my PostsController that calls the publish method inside my User Model.
PostsController
class PostsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
}
public function store()
{
auth()->user()->publish(
new Post(request(['title', 'body']))
);
}
}
When the publish method is called, the injected Post class automatically sets the user_id to the save method.
My question is, how do I make a relationship like this in a situation where for every posts, there are comments. These comments are associated to the Post and the User that created the comment.
In short, I should have both user_id and post_id when I call the addComment method.
User Model:
public function posts(){
return $this->hasMany(Post::class);
}
public function comments(){
return $this->hasMany(Comments::class);
}
Posts Model
public function user(){
return $this->belongsTo(User::class);
}
public function comments(){
return $this->hasMany(Comments::class);
}
Comments Model
public function post(){
return $this->belongsTo(Post::class);
}
public function user(){
return $this->belongsTo(User::class);
}
Example Problems:
1) Get user comments:
Solution: auth()->user()->comments()->get(); <- collection of user
comments .
2) Get user from the given comment:
Solution: Comment::find($someCommentId)->user()->first()->name; <-
User name from a specific comment.
3) Get all comments for a specific post .
Solution: Post::first()->comments()->get(); or eager load
Post::with('comments')->first(); <- A collection that contains post
information within it u can find a collection of comments for that
post.
4) Load user when loading a comment:
Solution: Comment::with('user')->first(); <- single collection
containing a collection with user info and comment info.
5) Load a specific user post and comments for that post at the same time:
Solution: User::with('posts.comments')->first(); <- Contains a
collection with user info and collection of all user posts with each
post containing comments.
In your question you wrote:
In short, I should have both user_id and post_id when I call the addComment method.
Which is absolutely correct and no problem. You don't have to set these properties through a method like $user->posts()->save($post) - this is just a convenience method that does the job for you (see save($model) and related setForeignAttributesForCreate($model) in the framework code; these methods just set the foreign key property for you).
In fact, the following three ways to create a new post are interchangeable:
// what you did
$user->posts->save(
new Post([
'title' => 'Hello',
'body' => 'World!',
])
);
// equivalent
Post::create([
'user_id' => \Auth::user()->id, // or \Auth::id()
'title' => 'Hello',
'body' => 'World!',
]);
// also equivalent
$post = new Post([
'user_id' => \Auth::user()->id, // or \Auth::id()
'title' => 'Hello',
'body' => 'World!',
]);
$post->save();
When storing a new comment, you will most likely have a controller like this, because a comment always belongs to a post and you therefore will need a reference of the post:
class CommentsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
}
public function store(Post $post)
{
$comment = new Comment(request(['body']));
$comment->user_id = \Auth::user()->id;
$comment->post_id = $post->id;
$comment->save();
}
}
You could also abbreviate it and write:
Comment::create(
array_merge(request(['body']), ['user_id' => \Auth::id(), 'post_id' => $post->id])
);