I understand how relationships in Laravel (Eloquent) work, but let's say I've got a many to many relationship between two models, call them Posts and Tags.
So our relationship is fine, from Posts I can access all the related Tags, and from Tags I can get all related Posts.
But... I have the ID of a row in the pivot table, and want to return both the Post and Tag relating to this row, how would I go about doing this?
EDIT:
Let's introduce a third Model, called Foo. This contains the ID of the row in the pivot table,
is there anyway I can create a relationship from this to the two other models?
A Model for your pivot:
<?php
class PostTagPivot
{
public function Post()
{
return $this->belongsTo('Post');
}
public function Tag()
{
return $this->belongsTo('Tag');
}
}
And retrieve Post and Tag via:
$Post = PostTagPivot::find($fooBarId)->Post;
$Tag = PostTagPivot::find($fooBarId)->Tag;
Related
I have a make table and post table. Make table saves make names as make_code and make_name.
Post table has a column make. While saving a post, it will save make in make_code.
While displaying in blade, I want it to display as make_name. How can I do it?
Currently {{$post->make}} gives me make_code. I need it to show make_name.
I think its a one-to-one relationship that's needed. I tried putting it in model but did not work. How can I achieve it?
MAKE MODEL
class Make extends Model
{
public function make()
{
return $this->belongsTo(App\Post::class);
}
}
POST MODEL:
class Post extends Model
{
protected $table = 'posts';
}
Update
As Tim Lewis noticed:
the relationships can't be named make, as that's a conflict.
Assuming that the your relationship work like this:
a Make has many Post
a Post belongs to a Make object.
| Note: Correct me if I'm wrong.
So, if this is correct, you should define your relationships like this:
Post.php
public function make_rel()
{
return $this->belongsTo(Make::class, 'make', 'make_code');
}
Make.php
public function posts()
{
return $this->hasMany(Post::class, 'make', 'make_code');
}
Check the One-to-Many and One-to-Many (Inverse) relationship sections of the documentation.
So, you could do in your controller (or wherever you want):
$post = Post::find(1);
dd($post->make_rel->make_name); // 'Harley Davidson'
Additionally, you could create a computed property as a shorcout to access this related property in your Post model:
Post.php
// ...
public function getMakeNameAttribute()
{
return $this->make_rel->make_name;
}
Now, you can access it like this:
$post = Post::find(1);
dd($post->make_name); // 'Harley Davidson'
Suggestion
As a suggestion, I strongly advice you to change your foreign key column from make to make_id (in your 'posts' table) to avoid conflicts. Also, you could relate the post to the make primmary key instead of a custom key given the fact that this link is almost invisible and it is handled by Laravel. This would speed up the execution of the query because primmary id's are indexed by default.
Assume I have posts and videos that can be seen by multiple users.
- users
- id
- posts
- id
- videos
- id
- user_accessables (pivot)
- id
- user_id
- accessable_id
- accessable_type
In an example like that, I have set my User relationship like so but something feels wrong
class User extends Model {
public function posts() {
return $this->morphedByMany(
Post::class,
'accessable',
'user_accessables'
);
}
public function videos() {
return $this->morphedByMany(
Video::class,
'accessable',
'user_accessables'
);
}
public function allowedEntities() {
return ($this->posts)->merge($this->videos);
}
}
With the allowedEntities() I can get a collection of both models joined together.
However, I think the use of polymorphic relationship is returning a collection of entities through relationship rather than needing a combiner relationship, right?
I am having problems with understanding polymorphic with pivot table (the tag example in documentation doesn't seem like same scenario).
Because now I can't do:
$collection = collect(); // multiple models of Video & Post
$user->allowedEntities()->sync($collection);
As #Jonas Staudenmeir said is not possible to have a relationship that returns all related model, BUT you can define a method on the model that returns a query builder object with all entities you need (search with on the docs).
I have 4 tables in my database which are: posts, categories, tags and relation_with_tag_category
In my Post model I have a 'belongsToMany' relationship:
public function categories(){
return $this->belongsToMany('App\Category', 'category_relation')->withTimestamps();
}
public function tags(){
return $this->belongsToMany('App\Tag', 'category_relation')->withTimestamps();
}
How can I do relationship with post and tag and category by the same table which I explain above and how can I display in my blade view?
It's just like wordpress term relationship
Assuming your relations works correctly (I cant tell if i only see one model relation) you can query your tables using with function.
$myPosts = Post::with(['categories','tags'])->get();
And use them like this
$myPosts->categories->all();
$myPosts->tags->all();
I want to find username from post_id using Post_Tag table using Eloquent model. Here are the tables.
User Table
user_id(pk)
username
Post Table
post_id(pk)
user_id(fk)
Post_Tag Table
post_id(fk)
Tag_id(fk)
How can I fetch username from User table using Post_Tag table. Here is what I have tried:
class Post extends Eloquent {
public function user() {
return $this->belongsTo('App\User');
}
}
class PostTag extends Eloquent {
public function post() {
return $this->hasMany('App\Post');
}
}
$posts = PostTag::with('post')->where('tag_id','=','20')->get();
One tag belongs to Multiple posts and each post will belong to an owner/User. Thank you in advance.
If your relations are working this would do it:
PostTag::find(20)->post()->first()
->user()->first()->username;
You say one Tag belongs to many posts, how do you choose which of the many posts you want to get the user's username?
Do you want to get all the users who have a post with some PostTag?
Edit: Try this:
PostTag::find(20)->with(['post', 'post.user'])->get();
Run this in artisan tinker or dd the result so you can see what is returned, I think this solves your problem. Just note that this may return a lot of data, you could use take instead of get to limit the results.
I'm working on a project that has a many to many relationship between User and Club. This relationship works and I can get the respective objects with: $user->clubs. The pivot table I've named memberships. I can get the pivot data with $club->pivot. Foreign keys are defined for the memberships table in migrations.
However, I'd like the pivot table to be represented by a model so that I can easily update attributes of Membership such as role (Or even add a Role model to Membership!) or status.
I've looked at "Defining A Custom Pivot Model" in the docs, but what it says doesn't work for me, I get:
ErrorException
Argument 1 passed to Illuminate\Database\Eloquent\Model::__construct() must be of the type array, object given
I've also looked at this description of how to do it, but it's more or less the same as above.
Membership model:
class Membership extends Eloquent {
protected $table = 'memberships';
public function user()
{
return $this->belongsTo('User');
}
public function club()
{
return $this->belongsTo('Club');
}
}
Has anyone done this before?
This has been solved by a suggestion by a reddit user to extend Pivot in my Membership model. I also had to add ->withPivot('status', 'role')->withTimestamps() to the relationship declarations in the User and Club models.
You can do this by adding some manual code.
Your Membership model looks ok. You can get all clubs of a $user easily if you define method $user->clubs() where you get all the clubs manually.
clubs() {
$memberships=$this->memberships;
$clubs=new \Illuminate\Database\Eloquent\Collection();
foreach($memberships as $m) {
$clubs=$clubs->merge($m->clubs);
}
return $clubs;
}