I'm trying to create an Eloquent query that fetches all posts and checks if the user liked each of those posts.
I have the following models:
Post.php
class Post extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'posts';
public function user()
{
return $this->belongsTo('User');
}
public function likes()
{
return $this->hasMany('Like');
}
}
Like.php:
class Like extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'likes';
}
And your typical User model as well.
My DB structure is the following:
posts table:
+----+---------+---------+
| id | user_id | message |
+----+---------+---------+
users table:
+----+----------+
| id | username |
+----+----------+
likes table:
+----+---------+---------+
| id | post_id | user_id |
+----+---------+---------+
Right now, my query only returns all posts, but how can I modify it to return all posts and check if the user liked each post?
Route::get('/', array('as' => 'index', function()
{
$posts = Post::all();
return View::make('index')->with('posts', $posts);
}));
Thanks!
What about a left join between the posts table and the likes table, filtering by the actual user's id?
$post = DB::table('post')
->select(DB::raw('message, likes.user_id IS NOT NULL as liked'))
->leftJoin('likes', 'users_id', '=', 'likes.user_id')
->where('likes.user_id', '=', $curent_user_id)
->get();
I have no way to test it now, but I hope it might give you some inspiration :)
You can grab the likes with the post for that specific user. Try this..
Post::with(['likes' => function() use ($user_id) { $q->where('user_id','=', $user_id); }])->all();
It will return blank array if user haven't like the post.
Related
MY model works perfectly:
class Customer extends Model
{
/**
* #var string The database table used by the model.
*/
public $table = 'users';
/**
* #var array Validation rules
*/
public $rules = [
];
public $hasMany = [
'voucher' => ['ItScholarBd\Api\Models\Voucher']
];
}
This Customer model refers to users table. all users having role_id=5 is only customers. So this Model will always fetch users data where role_id = 5. I can achieve this as usual practice. But is there any smart way to set this where clause inside this Model so that Customer model always fetch user data having role_id = 5. i.e: Customer::get(); will return users where role_id = 5
Add following method in your customer model.
public function scopeCustomers($query)
{
return $query->where('role_id', 5);
}
and fetch records like this:-
$customers = Customer::customers();
Message Tables Column is
| messages_id(pk) | user_id | target_id | message | created_at
User_id has sender user's id. Target_id has receiver user's id
And simple user table has relation to MessageTable by HasMany.
public function message()
{
return $this->hasMany('App\Model\TableModel\Message', 'user_id', 'user_id');
}
I want to get Userdata and each last message from user_id=[1,2,3,4] to target_id = 5.
So I tried this
User::WhereIn(user_id, [1,2,3,4])
->with(['message' => function ($query) {
$query->Where('target_id', 5)->orderBy('messages_id', 'desc)->first();
}])->get();
But this query return User's data and one user last message.
How do I get users last message using hasMany ?
your hasMany relation is incorrect:
the third argument should be the primary key of the current model:
public function message()
{
return $this->hasMany('App\Model\TableModel\Message', 'user_id', 'id');
}
anyway, to get the last message, I recommend building a new relation using hasOne relation:
public function lastMessage()
{
return $this->hasOne('App\Model\TableModel\Message', 'user_id', 'id')->latest();
}
now, you can use this new relation like:
User::WhereIn(user_id, [1,2,3,4])
->with(['lastMessage' => function ($query) {
$query->Where('target_id', 5);
}])->get();
Here are my tables
Posts
id | name | created_At
Comments
id | comment | post_id | created_at
Post Model
function comments(){
return $this->hasMany('App\Models\Comment','id','post_id');
}
PostsController
function index()
{
Post::with('comments')::get();
}
Now how can i get list of all posts along with comments?
I am trying to match post_id in the child table.
In Your Post Model:
public function comments()
{
return $this->hasMany('App\Model\Comment');
}
In Your Post Controller :
use Illuminate\Http\Request;
function index(Request $request)
{
$posts=Post::with('comments')->get();
// in json
return response()->json($posts);
// in your view
//return view('viewname')->with('posts',$posts);
}
I'm having issues using the hasManythrough relationship in larval. Just following the documentation using the example there, which are:
countries
id - integer
name - string
users
id - integer
country_id - integer
name - string
posts
id - integer
user_id - integer
title - string
Here is how I set up the relationship in the models
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Country extends Model
{
public function posts() {
return $this->hasManyThrough('App\Post', 'App\User', 'user_id', 'country_id', 'id');
}
}
Here is the User model
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function posts() {
return $this->hasMany('App\Post');
}
public function country() {
return $this->hasOne('App\User');
}
}
Here is the Posts model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function user() {
return $this->belongsTo('App\User');
}
}
So, the website doesn't go through enough detail on how to extract the posts through the country model. Using the routes file, this is the query I used
Route::get('posts/countries/{id}', function($id) {
$countries = App\Country::where('id', $id)->get();
return $countries->posts;
});
It looks to me like I set up the relationship up correctly the way the docs say to. There is a country_id on the users table, so I'm not sure if the query is wrong or maybe I did set up the relationship incorrectly.
You aren't actually requesting the relationship, you are simply looking at the attribute on countries.
If you want to eagerload the posts in the query builder you will need to add with('posts') when you build the query. (Before you call ->get() which executes the query and turns it into a collection.)
Route::get('posts/countries/{id}', function($id) {
$country = App\Country::with('posts')->where('id', $id)->first();
return $country->posts;
});
Or if you want to lazyload you can ask for the relationship on the country model by doing ->posts() like this:
Route::get('posts/countries/{id}', function($id) {
$country = App\Country::with('posts')->where('id', $id)->first();
return $country->posts();
});
Notice: in both cases I changed the ->get() to ->first(). I assume you only want one country's posts returned.
->get() executes the query and returns the related models as a collection and ->first() takes the first model from the query.
#Nicklas Kevin Frank
Your solution didn't work for me. at least not completely, but you were right in some respects. I tinkered around, and discovered that the query worked like this better:
Route::get('posts/countries/{id}', function($id) {
$country = App\Country::where('id', $id)->first();
return view('country')->with('country', $country);
});
So, like you said, it diffidently needed the ->first() option, but it didn't need the with('posts') portion. But much thanks my friend. I couldn't have solved this without you.
it is possible to get all details (user, posts, postimages) within one collection / json?
user->hasmany(posts)
post->hasmany(postimage)
user:
id | name
post:
id | user_id | text
postimage:
id | post_id | imgpath
user model:
public function posts() {
return $this->hasMany('App\posts')->orderBy('id', 'ASC');
}
posts model:
public function images(){
return $this->hasMany('App\postsimages');
}
get all posts from user works fine:
$myposts = users::find(Auth::user()->id)->posts;
i'm able to get all images from a post within a loop
foreach($myposts as $mypost) {
$postimages = $mypost->images;
}
what i want is to get all posts, images without the loop e.g
$myposts = users::find(Auth::user()->id)->posts->images
thanks
Yes, use hasManyThrough relationship.
posts model:
public function images()
{
return $this->hasMany('App\postsimages');
}
user model
public function posts()
{
return $this->hasMany('App\posts')->orderBy('id', 'ASC');
}
public function images()
{
return $this->hasManyThrough('App\posts', 'App\postsimages');
}
then
$postimages = Auth::user()->images;