Laravel use link table on model - php

So I have the tables tags, posts and a link table for these
Now I want to get all the tags from the current post.
Now I want to get all the tags related to this post.
I made a model "Tag" (with no functions yet, just extending Eloquent)
How can I use this model to get all the tag names/titles based on the current post id, or do I need a seperate model for the Linking table(Which seems incorrect to me)?
I'm kinda lost in it right now, probably due to too much searching.
Anyone can help me out here?
SOLVED
$post = Post::where('id', $id)->first();
$tags= $post->tags;
Tags function in the Post model:
public function tags()
{
return $this->belongsToMany('Tag');
}

Add the following function to your Post model
public function tags()
{
return $this->belongsToMany('Tag');
}
Now you can call $post->tags()->getResults() to get all tags of a post.
Corresponding docs: http://laravel.com/docs/4.2/eloquent#many-to-many

Related

Laravel - Get belongsTo relationship without id using Eloquent

i'm using laravel 7.30, I have a post model linked to user model with belongsTo relationship, I want to retrieve all posts with user property that contains only the name of the user for api purposes.
what i've tried so far.
public function index()
{
return Post::with('user:id,name')->get();
}
but the result of this code is a nested object 'user' which has 2 fields id and name on each post, I only want a single field with posts fields called user which has the name only and not a nested object for api purposes.
I've made it using database query builder, but i'm looking for a way using Eloquent
Thanks in advance
You can add this to your Post Model:
protected $appends = [
"author_name"
];
public function getAuthorNameAttribute()
{
return $this->user->name;
}
This will make sure the user's name is appended to the Post object every time it is being called.
Then from your controller, you can easily do this:
public function index()
{
return Post::get();
}

Get name instead of ID one to one relationship

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.

Laravel Get data One to Many Relationship with conditions

how to display data one too many relationships with conditions into view.
I have a blog post that has a comment, but this comment has a condition that published or not.
here my Post Model
...
public function comments()
{
return $this->hasMany(Comment::class);
}
...
on my code above I can simply use $post->comments to show all the comments.
like I said before, I need only show comments with published is true
but how to add conditions?...
You can achieve this by getting the post with it's published comments;
$post = Post::where('id', $id)->with('comments', function ($q) {
$q->where('published', true);
})->first();
Then when in the view you call $post->comments, you will only get the published one.
Alternatively, if you really want to you can update your Model to have a published comments relationship, but this is less advised.
public function publishedComments()
{
return $this->hasMany(Comment::class)->where('published', true);
}
You can get only published comments by using
$this->post->comments()->where('published', true)->get()
Check the Documentation
Of course, since all relationships also serve as query builders, you can add further constraints to which comments are retrieved by calling the comments method and continuing to chain conditions onto the query: $comment = App\Post::find(1)->comments()->where('title', 'foo')->first();

Trying to get data via related table in Laravel

What I'm trying to do is to show the posts that have been saved by the user in the profile. I will try to explain it as good as possible refering to my code. So:
public function userProfil($id)
I have the profile function which get the data from userprofile table. and inside I have the following code for saved data:
$authed = User::find($id);
$savedarticles = $authed->mysaves;
$allsavings = DB::select("Select * from article where id=$savedarticles->id");
But this code does not work like this anyway. I can do this instead:
$authed = User::find($id);
$savedarticles = $authed->mysaves;
But when I try to get articles from article table with the article_id of mysaves, it does not work such as this:
$allsaved= DB::table('article')->where('id', $savedarticles->article_id);
the error it gives is like:
Property [article_id] does not exist on this collection instance.
although savearticle table has article_id I can output it without the line above and in view I get them as:
#foreach($savedarticles as $savedarticle)
<p>{{$savedarticle}}</p>
#endforeach
it gives me everything that is in the savearticle table and I can get do savedarticle->article_id and get article_id but can't get it in controller.
I am using Laravel 5.4.
The error message Property [article_id] does not exist on this collection instance. means you are trying to get an attribute of a single instance but from a collection.
For example the collection could be like
[$article1, $article2, $article3]
therefore what you tried to do is something similar to
[$article1, $article2, $article3]->article_id
You are trying to get an attribute from a collection instead of a single instance.
As for your query, you can use where in sql statement to search for rows that match any item in an array
$allsaved= DB::table('article')->whereIn('id', $savedarticles->pluck('article_id')->all());
What I have understood is that A USER has many POSTS and a POST belong to an article.
If this is true then you have to do following.
1: In USER model define a relation to get all posts. like below.
public function posts() {
// Foreign key will be a key that is stored in posts table and represent the user MAY BE: user_id
$this->hasMany(Posts::class, 'foreign_key', 'local_key')
}
This will allow you to get all posts belong to a user.
2: In posts, model defines a user relation like below.
public function user() {
$this->belongsTo(User::class, 'foreign_key', 'local_key');
}
This will allow you to get a post User;
3: Now in your controller you will have something like this.
public function show($user_id) {
// find a user with posts as eager loading(to avoid query again)
$user = User::with(['posts'])->where('id', $user_id)->first();
// get all posts that belong to this user
$posts = $user->posts;
}
In controller show($user_id) method you will have a user data as well as user posts data. Now if you want to get a post relations then simply define as below. let say a post belongs to an article as well.
4: In posts, model defines a relation to get an article.
public function article() {
// This will allow you to get a post artcle
$this->belongsTo(Article::class, 'foreign_key', 'local_key');
}
Now you can get the article as well while finding a user. please see below. I am rewriting controller show action to give you a better understanding.
5: Get a user with user_id
public function show($user_id) {
// find a user with posts as eager loading(to avoid query again)
// eager loading for posts & post child, this will give you NOSQL at runtime and all data will come from one query.
$user = User::with(['posts', 'posts.article'])->where('id', $user_id)->first();
// get all posts that belong to this user
$posts = $user->posts;
foreach($posts as $post) {
$article = $post->article; // Child relation of post.
}
}
Hope you will understand the flow, you have to make sure models relation to work it perfectly. If you need further help please let me know.

Add a calculated field to Laravel model query

I have a controller which has a query such as this one:
$post = Post::find($id);
$comments = $post->comments;
Where a post has many comments and a comment belongs to one post. The comments model has an id,comment,tag field.
What I want to do is that for any query such as this one, the model returns the fields id, comment, tag and tag_translated, where the latter is just a translation of the tag using the Lang facade.
I could solve this by using a for on the controller which iterates over the $comments and adds the field, however Ill have to do that for every controller that requires the tag_translared field. Is there a way to ask the model to include such a field?
Add this in your Comment Model:
protected $appends = ['tag_translated'];
public function getTagTranslatedAttribute()
{
return 'the translated tag';
}
Hope this helps.
Yes there is? just add this to your Comment model
public function getTagTranslatedAttribute()
{
return Lang::methodYouWish($this->tag);
}
then you can access this property from comment instance
$comment->tag_translated;
EDIT
You can modify your toArray method, just add it to Comment class
protected $appends = ['tag_translated'];
and then
$comment->toArray();
I was facing the same issue, and you just need to add two things:
The first one is the appends field:
protected $appends = ['field'];
The second one is the "getter":
public function getFieldAttribute()
At the end of the method name you need to add the "Attribute" suffix, and that's it.

Categories